hiredis 0.5.2 → 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
  *
@@ -73,22 +75,23 @@ 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 */
79
84
  case REDIS_REPLY_ARRAY:
80
85
  if (r->element != NULL) {
81
86
  for (j = 0; j < r->elements; j++)
82
- if (r->element[j] != NULL)
83
- freeReplyObject(r->element[j]);
87
+ freeReplyObject(r->element[j]);
84
88
  free(r->element);
85
89
  }
86
90
  break;
87
91
  case REDIS_REPLY_ERROR:
88
92
  case REDIS_REPLY_STATUS:
89
93
  case REDIS_REPLY_STRING:
90
- if (r->str != NULL)
91
- free(r->str);
94
+ free(r->str);
92
95
  break;
93
96
  }
94
97
  free(r);
@@ -183,504 +186,23 @@ static void *createNilObject(const redisReadTask *task) {
183
186
  return r;
184
187
  }
185
188
 
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
- r->buf = 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;
189
+ /* Return the number of digits of 'v' when converted to string in radix 10.
190
+ * Implementation borrowed from link in redis/src/util.c:string2ll(). */
191
+ static uint32_t countDigits(uint64_t v) {
192
+ uint32_t result = 1;
193
+ for (;;) {
194
+ if (v < 10) return result;
195
+ if (v < 100) return result + 1;
196
+ if (v < 1000) return result + 2;
197
+ if (v < 10000) return result + 3;
198
+ v /= 10000U;
199
+ result += 4;
200
+ }
679
201
  }
680
202
 
681
203
  /* Helper that calculates the bulk length given a certain string length. */
682
204
  static size_t bulklen(size_t len) {
683
- return 1+intlen(len)+2+len+2;
205
+ return 1+countDigits(len)+2+len+2;
684
206
  }
685
207
 
686
208
  int redisvFormatCommand(char **target, const char *format, va_list ap) {
@@ -692,6 +214,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
692
214
  char **curargv = NULL, **newargv = NULL;
693
215
  int argc = 0;
694
216
  int totlen = 0;
217
+ int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */
695
218
  int j;
696
219
 
697
220
  /* Abort if there is not target to set */
@@ -708,19 +231,19 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
708
231
  if (*c == ' ') {
709
232
  if (touched) {
710
233
  newargv = realloc(curargv,sizeof(char*)*(argc+1));
711
- if (newargv == NULL) goto err;
234
+ if (newargv == NULL) goto memory_err;
712
235
  curargv = newargv;
713
236
  curargv[argc++] = curarg;
714
237
  totlen += bulklen(sdslen(curarg));
715
238
 
716
239
  /* curarg is put in argv so it can be overwritten. */
717
240
  curarg = sdsempty();
718
- if (curarg == NULL) goto err;
241
+ if (curarg == NULL) goto memory_err;
719
242
  touched = 0;
720
243
  }
721
244
  } else {
722
245
  newarg = sdscatlen(curarg,c,1);
723
- if (newarg == NULL) goto err;
246
+ if (newarg == NULL) goto memory_err;
724
247
  curarg = newarg;
725
248
  touched = 1;
726
249
  }
@@ -751,17 +274,14 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
751
274
  /* Try to detect printf format */
752
275
  {
753
276
  static const char intfmts[] = "diouxX";
277
+ static const char flags[] = "#0-+ ";
754
278
  char _format[16];
755
279
  const char *_p = c+1;
756
280
  size_t _l = 0;
757
281
  va_list _cpy;
758
282
 
759
283
  /* 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++;
284
+ while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++;
765
285
 
766
286
  /* Field width */
767
287
  while (*_p != '\0' && isdigit(*_p)) _p++;
@@ -829,7 +349,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
829
349
 
830
350
  fmt_invalid:
831
351
  va_end(_cpy);
832
- goto err;
352
+ goto format_err;
833
353
 
834
354
  fmt_valid:
835
355
  _l = (_p+1)-c;
@@ -848,7 +368,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
848
368
  }
849
369
  }
850
370
 
851
- if (newarg == NULL) goto err;
371
+ if (newarg == NULL) goto memory_err;
852
372
  curarg = newarg;
853
373
 
854
374
  touched = 1;
@@ -860,7 +380,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
860
380
  /* Add the last argument if needed */
861
381
  if (touched) {
862
382
  newargv = realloc(curargv,sizeof(char*)*(argc+1));
863
- if (newargv == NULL) goto err;
383
+ if (newargv == NULL) goto memory_err;
864
384
  curargv = newargv;
865
385
  curargv[argc++] = curarg;
866
386
  totlen += bulklen(sdslen(curarg));
@@ -872,11 +392,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
872
392
  curarg = NULL;
873
393
 
874
394
  /* Add bytes needed to hold multi bulk count */
875
- totlen += 1+intlen(argc)+2;
395
+ totlen += 1+countDigits(argc)+2;
876
396
 
877
397
  /* Build the command at protocol level */
878
398
  cmd = malloc(totlen+1);
879
- if (cmd == NULL) goto err;
399
+ if (cmd == NULL) goto memory_err;
880
400
 
881
401
  pos = sprintf(cmd,"*%d\r\n",argc);
882
402
  for (j = 0; j < argc; j++) {
@@ -894,20 +414,25 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
894
414
  *target = cmd;
895
415
  return totlen;
896
416
 
897
- err:
898
- while(argc--)
899
- sdsfree(curargv[argc]);
900
- free(curargv);
417
+ format_err:
418
+ error_type = -2;
419
+ goto cleanup;
901
420
 
902
- if (curarg != NULL)
903
- sdsfree(curarg);
421
+ memory_err:
422
+ error_type = -1;
423
+ goto cleanup;
904
424
 
905
- /* No need to check cmd since it is the last statement that can fail,
906
- * but do it anyway to be as defensive as possible. */
907
- if (cmd != NULL)
908
- free(cmd);
425
+ cleanup:
426
+ if (curargv) {
427
+ while(argc--)
428
+ sdsfree(curargv[argc]);
429
+ free(curargv);
430
+ }
431
+
432
+ sdsfree(curarg);
433
+ free(cmd);
909
434
 
910
- return -1;
435
+ return error_type;
911
436
  }
912
437
 
913
438
  /* Format a command according to the Redis protocol. This function
@@ -917,7 +442,7 @@ err:
917
442
  * %b represents a binary safe string
918
443
  *
919
444
  * When using %b you need to provide both the pointer to the string
920
- * and the length in bytes. Examples:
445
+ * and the length in bytes as a size_t. Examples:
921
446
  *
922
447
  * len = redisFormatCommand(target, "GET %s", mykey);
923
448
  * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
@@ -928,9 +453,69 @@ int redisFormatCommand(char **target, const char *format, ...) {
928
453
  va_start(ap,format);
929
454
  len = redisvFormatCommand(target,format,ap);
930
455
  va_end(ap);
456
+
457
+ /* The API says "-1" means bad result, but we now also return "-2" in some
458
+ * cases. Force the return value to always be -1. */
459
+ if (len < 0)
460
+ len = -1;
461
+
931
462
  return len;
932
463
  }
933
464
 
465
+ /* Format a command according to the Redis protocol using an sds string and
466
+ * sdscatfmt for the processing of arguments. This function takes the
467
+ * number of arguments, an array with arguments and an array with their
468
+ * lengths. If the latter is set to NULL, strlen will be used to compute the
469
+ * argument lengths.
470
+ */
471
+ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
472
+ const size_t *argvlen)
473
+ {
474
+ sds cmd;
475
+ unsigned long long totlen;
476
+ int j;
477
+ size_t len;
478
+
479
+ /* Abort on a NULL target */
480
+ if (target == NULL)
481
+ return -1;
482
+
483
+ /* Calculate our total size */
484
+ totlen = 1+countDigits(argc)+2;
485
+ for (j = 0; j < argc; j++) {
486
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
487
+ totlen += bulklen(len);
488
+ }
489
+
490
+ /* Use an SDS string for command construction */
491
+ cmd = sdsempty();
492
+ if (cmd == NULL)
493
+ return -1;
494
+
495
+ /* We already know how much storage we need */
496
+ cmd = sdsMakeRoomFor(cmd, totlen);
497
+ if (cmd == NULL)
498
+ return -1;
499
+
500
+ /* Construct command */
501
+ cmd = sdscatfmt(cmd, "*%i\r\n", argc);
502
+ for (j=0; j < argc; j++) {
503
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
504
+ cmd = sdscatfmt(cmd, "$%u\r\n", len);
505
+ cmd = sdscatlen(cmd, argv[j], len);
506
+ cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
507
+ }
508
+
509
+ assert(sdslen(cmd)==totlen);
510
+
511
+ *target = cmd;
512
+ return totlen;
513
+ }
514
+
515
+ void redisFreeSdsCommand(sds cmd) {
516
+ sdsfree(cmd);
517
+ }
518
+
934
519
  /* Format a command according to the Redis protocol. This function takes the
935
520
  * number of arguments, an array with arguments and an array with their
936
521
  * lengths. If the latter is set to NULL, strlen will be used to compute the
@@ -942,8 +527,12 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
942
527
  size_t len;
943
528
  int totlen, j;
944
529
 
530
+ /* Abort on a NULL target */
531
+ if (target == NULL)
532
+ return -1;
533
+
945
534
  /* Calculate number of bytes needed for the command */
946
- totlen = 1+intlen(argc)+2;
535
+ totlen = 1+countDigits(argc)+2;
947
536
  for (j = 0; j < argc; j++) {
948
537
  len = argvlen ? argvlen[j] : strlen(argv[j]);
949
538
  totlen += bulklen(len);
@@ -970,6 +559,10 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
970
559
  return totlen;
971
560
  }
972
561
 
562
+ void redisFreeCommand(char *cmd) {
563
+ free(cmd);
564
+ }
565
+
973
566
  void __redisSetError(redisContext *c, int type, const char *str) {
974
567
  size_t len;
975
568
 
@@ -982,10 +575,14 @@ void __redisSetError(redisContext *c, int type, const char *str) {
982
575
  } else {
983
576
  /* Only REDIS_ERR_IO may lack a description! */
984
577
  assert(type == REDIS_ERR_IO);
985
- strerror_r(errno,c->errstr,sizeof(c->errstr));
578
+ strerror_r(errno, c->errstr, sizeof(c->errstr));
986
579
  }
987
580
  }
988
581
 
582
+ redisReader *redisReaderCreate(void) {
583
+ return redisReaderCreateWithFunctions(&defaultFunctions);
584
+ }
585
+
989
586
  static redisContext *redisContextInit(void) {
990
587
  redisContext *c;
991
588
 
@@ -993,75 +590,188 @@ static redisContext *redisContextInit(void) {
993
590
  if (c == NULL)
994
591
  return NULL;
995
592
 
996
- c->err = 0;
997
- c->errstr[0] = '\0';
998
593
  c->obuf = sdsempty();
999
594
  c->reader = redisReaderCreate();
595
+
596
+ if (c->obuf == NULL || c->reader == NULL) {
597
+ redisFree(c);
598
+ return NULL;
599
+ }
600
+
1000
601
  return c;
1001
602
  }
1002
603
 
1003
604
  void redisFree(redisContext *c) {
605
+ if (c == NULL)
606
+ return;
1004
607
  if (c->fd > 0)
1005
608
  close(c->fd);
1006
- if (c->obuf != NULL)
1007
- sdsfree(c->obuf);
1008
- if (c->reader != NULL)
1009
- 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);
1010
615
  free(c);
1011
616
  }
1012
617
 
618
+ int redisFreeKeepFd(redisContext *c) {
619
+ int fd = c->fd;
620
+ c->fd = -1;
621
+ redisFree(c);
622
+ return fd;
623
+ }
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
+
1013
653
  /* Connect to a Redis instance. On error the field error in the returned
1014
654
  * context will be set to the return value of the error function.
1015
655
  * When no set of reply functions is given, the default set will be used. */
1016
656
  redisContext *redisConnect(const char *ip, int port) {
1017
- redisContext *c = redisContextInit();
657
+ redisContext *c;
658
+
659
+ c = redisContextInit();
660
+ if (c == NULL)
661
+ return NULL;
662
+
1018
663
  c->flags |= REDIS_BLOCK;
1019
664
  redisContextConnectTcp(c,ip,port,NULL);
1020
665
  return c;
1021
666
  }
1022
667
 
1023
- redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv) {
1024
- redisContext *c = redisContextInit();
668
+ redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
669
+ redisContext *c;
670
+
671
+ c = redisContextInit();
672
+ if (c == NULL)
673
+ return NULL;
674
+
1025
675
  c->flags |= REDIS_BLOCK;
1026
676
  redisContextConnectTcp(c,ip,port,&tv);
1027
677
  return c;
1028
678
  }
1029
679
 
1030
680
  redisContext *redisConnectNonBlock(const char *ip, int port) {
1031
- redisContext *c = redisContextInit();
681
+ redisContext *c;
682
+
683
+ c = redisContextInit();
684
+ if (c == NULL)
685
+ return NULL;
686
+
1032
687
  c->flags &= ~REDIS_BLOCK;
1033
688
  redisContextConnectTcp(c,ip,port,NULL);
1034
689
  return c;
1035
690
  }
1036
691
 
1037
- redisContext *redisConnectUnix(const char *path) {
692
+ redisContext *redisConnectBindNonBlock(const char *ip, int port,
693
+ const char *source_addr) {
694
+ redisContext *c = redisContextInit();
695
+ if (c == NULL)
696
+ return NULL;
697
+ c->flags &= ~REDIS_BLOCK;
698
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
699
+ return c;
700
+ }
701
+
702
+ redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
703
+ const char *source_addr) {
1038
704
  redisContext *c = redisContextInit();
705
+ if (c == NULL)
706
+ return NULL;
707
+ c->flags &= ~REDIS_BLOCK;
708
+ c->flags |= REDIS_REUSEADDR;
709
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
710
+ return c;
711
+ }
712
+
713
+ redisContext *redisConnectUnix(const char *path) {
714
+ redisContext *c;
715
+
716
+ c = redisContextInit();
717
+ if (c == NULL)
718
+ return NULL;
719
+
1039
720
  c->flags |= REDIS_BLOCK;
1040
721
  redisContextConnectUnix(c,path,NULL);
1041
722
  return c;
1042
723
  }
1043
724
 
1044
- redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv) {
1045
- redisContext *c = redisContextInit();
725
+ redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
726
+ redisContext *c;
727
+
728
+ c = redisContextInit();
729
+ if (c == NULL)
730
+ return NULL;
731
+
1046
732
  c->flags |= REDIS_BLOCK;
1047
733
  redisContextConnectUnix(c,path,&tv);
1048
734
  return c;
1049
735
  }
1050
736
 
1051
737
  redisContext *redisConnectUnixNonBlock(const char *path) {
1052
- redisContext *c = redisContextInit();
738
+ redisContext *c;
739
+
740
+ c = redisContextInit();
741
+ if (c == NULL)
742
+ return NULL;
743
+
1053
744
  c->flags &= ~REDIS_BLOCK;
1054
745
  redisContextConnectUnix(c,path,NULL);
1055
746
  return c;
1056
747
  }
1057
748
 
749
+ redisContext *redisConnectFd(int fd) {
750
+ redisContext *c;
751
+
752
+ c = redisContextInit();
753
+ if (c == NULL)
754
+ return NULL;
755
+
756
+ c->fd = fd;
757
+ c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
758
+ return c;
759
+ }
760
+
1058
761
  /* Set read/write timeout on a blocking socket. */
1059
- int redisSetTimeout(redisContext *c, struct timeval tv) {
762
+ int redisSetTimeout(redisContext *c, const struct timeval tv) {
1060
763
  if (c->flags & REDIS_BLOCK)
1061
764
  return redisContextSetTimeout(c,tv);
1062
765
  return REDIS_ERR;
1063
766
  }
1064
767
 
768
+ /* Enable connection KeepAlive. */
769
+ int redisEnableKeepAlive(redisContext *c) {
770
+ if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
771
+ return REDIS_ERR;
772
+ return REDIS_OK;
773
+ }
774
+
1065
775
  /* Use this function to handle a read event on the descriptor. It will try
1066
776
  * and read some bytes from the socket and feed them to the reply parser.
1067
777
  *
@@ -1077,7 +787,7 @@ int redisBufferRead(redisContext *c) {
1077
787
 
1078
788
  nread = read(c->fd,buf,sizeof(buf));
1079
789
  if (nread == -1) {
1080
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
790
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1081
791
  /* Try again later */
1082
792
  } else {
1083
793
  __redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1098,10 +808,10 @@ int redisBufferRead(redisContext *c) {
1098
808
  /* Write the output buffer to the socket.
1099
809
  *
1100
810
  * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
1101
- * 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
1102
812
  * write operation, "done" is set to 1 (if given).
1103
813
  *
1104
- * 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
1105
815
  * c->errstr to hold the appropriate error string.
1106
816
  */
1107
817
  int redisBufferWrite(redisContext *c, int *done) {
@@ -1114,7 +824,7 @@ int redisBufferWrite(redisContext *c, int *done) {
1114
824
  if (sdslen(c->obuf) > 0) {
1115
825
  nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
1116
826
  if (nwritten == -1) {
1117
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
827
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1118
828
  /* Try again later */
1119
829
  } else {
1120
830
  __redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1125,7 +835,7 @@ int redisBufferWrite(redisContext *c, int *done) {
1125
835
  sdsfree(c->obuf);
1126
836
  c->obuf = sdsempty();
1127
837
  } else {
1128
- c->obuf = sdsrange(c->obuf,nwritten,-1);
838
+ sdsrange(c->obuf,nwritten,-1);
1129
839
  }
1130
840
  }
1131
841
  }
@@ -1180,7 +890,7 @@ int redisGetReply(redisContext *c, void **reply) {
1180
890
  * is used, you need to call redisGetReply yourself to retrieve
1181
891
  * the reply (or replies in pub/sub).
1182
892
  */
1183
- int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
893
+ int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
1184
894
  sds newbuf;
1185
895
 
1186
896
  newbuf = sdscatlen(c->obuf,cmd,len);
@@ -1193,6 +903,15 @@ int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
1193
903
  return REDIS_OK;
1194
904
  }
1195
905
 
906
+ int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
907
+
908
+ if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
909
+ return REDIS_ERR;
910
+ }
911
+
912
+ return REDIS_OK;
913
+ }
914
+
1196
915
  int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1197
916
  char *cmd;
1198
917
  int len;
@@ -1201,6 +920,9 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1201
920
  if (len == -1) {
1202
921
  __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1203
922
  return REDIS_ERR;
923
+ } else if (len == -2) {
924
+ __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
925
+ return REDIS_ERR;
1204
926
  }
1205
927
 
1206
928
  if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
@@ -1223,21 +945,21 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
1223
945
  }
1224
946
 
1225
947
  int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
1226
- char *cmd;
948
+ sds cmd;
1227
949
  int len;
1228
950
 
1229
- len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
951
+ len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
1230
952
  if (len == -1) {
1231
953
  __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1232
954
  return REDIS_ERR;
1233
955
  }
1234
956
 
1235
957
  if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1236
- free(cmd);
958
+ sdsfree(cmd);
1237
959
  return REDIS_ERR;
1238
960
  }
1239
961
 
1240
- free(cmd);
962
+ sdsfree(cmd);
1241
963
  return REDIS_OK;
1242
964
  }
1243
965
 
@@ -1248,7 +970,7 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
1248
970
  * context is non-blocking, the "reply" pointer will not be used and the
1249
971
  * command is simply appended to the write buffer.
1250
972
  *
1251
- * Returns the reply when a reply was succesfully retrieved. Returns NULL
973
+ * Returns the reply when a reply was successfully retrieved. Returns NULL
1252
974
  * otherwise. When NULL is returned in a blocking context, the error field
1253
975
  * in the context will be set.
1254
976
  */
@@ -1271,9 +993,8 @@ void *redisvCommand(redisContext *c, const char *format, va_list ap) {
1271
993
 
1272
994
  void *redisCommand(redisContext *c, const char *format, ...) {
1273
995
  va_list ap;
1274
- void *reply = NULL;
1275
996
  va_start(ap,format);
1276
- reply = redisvCommand(c,format,ap);
997
+ void *reply = redisvCommand(c,format,ap);
1277
998
  va_end(ap);
1278
999
  return reply;
1279
1000
  }