hiredis 0.5.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
1
  /*
2
2
  * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
3
+ * Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
+ * Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
5
+ * Jan-Erik Rediger <janerik at fnordig dot com>
4
6
  *
5
7
  * All rights reserved.
6
8
  *
@@ -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
  }