hiredis 0.5.2 → 0.6.0

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.
@@ -73,6 +73,9 @@ void freeReplyObject(void *reply) {
73
73
  redisReply *r = reply;
74
74
  size_t j;
75
75
 
76
+ if (r == NULL)
77
+ return;
78
+
76
79
  switch(r->type) {
77
80
  case REDIS_REPLY_INTEGER:
78
81
  break; /* Nothing to free */
@@ -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,29 @@ 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;
424
+
425
+ cleanup:
426
+ if (curargv) {
427
+ while(argc--)
428
+ sdsfree(curargv[argc]);
429
+ free(curargv);
430
+ }
431
+
432
+ sdsfree(curarg);
904
433
 
905
434
  /* No need to check cmd since it is the last statement that can fail,
906
435
  * but do it anyway to be as defensive as possible. */
907
436
  if (cmd != NULL)
908
437
  free(cmd);
909
438
 
910
- return -1;
439
+ return error_type;
911
440
  }
912
441
 
913
442
  /* Format a command according to the Redis protocol. This function
@@ -917,7 +446,7 @@ err:
917
446
  * %b represents a binary safe string
918
447
  *
919
448
  * When using %b you need to provide both the pointer to the string
920
- * and the length in bytes. Examples:
449
+ * and the length in bytes as a size_t. Examples:
921
450
  *
922
451
  * len = redisFormatCommand(target, "GET %s", mykey);
923
452
  * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
@@ -928,9 +457,69 @@ int redisFormatCommand(char **target, const char *format, ...) {
928
457
  va_start(ap,format);
929
458
  len = redisvFormatCommand(target,format,ap);
930
459
  va_end(ap);
460
+
461
+ /* The API says "-1" means bad result, but we now also return "-2" in some
462
+ * cases. Force the return value to always be -1. */
463
+ if (len < 0)
464
+ len = -1;
465
+
931
466
  return len;
932
467
  }
933
468
 
469
+ /* Format a command according to the Redis protocol using an sds string and
470
+ * sdscatfmt for the processing of arguments. This function takes the
471
+ * number of arguments, an array with arguments and an array with their
472
+ * lengths. If the latter is set to NULL, strlen will be used to compute the
473
+ * argument lengths.
474
+ */
475
+ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
476
+ const size_t *argvlen)
477
+ {
478
+ sds cmd;
479
+ unsigned long long totlen;
480
+ int j;
481
+ size_t len;
482
+
483
+ /* Abort on a NULL target */
484
+ if (target == NULL)
485
+ return -1;
486
+
487
+ /* Calculate our total size */
488
+ totlen = 1+countDigits(argc)+2;
489
+ for (j = 0; j < argc; j++) {
490
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
491
+ totlen += bulklen(len);
492
+ }
493
+
494
+ /* Use an SDS string for command construction */
495
+ cmd = sdsempty();
496
+ if (cmd == NULL)
497
+ return -1;
498
+
499
+ /* We already know how much storage we need */
500
+ cmd = sdsMakeRoomFor(cmd, totlen);
501
+ if (cmd == NULL)
502
+ return -1;
503
+
504
+ /* Construct command */
505
+ cmd = sdscatfmt(cmd, "*%i\r\n", argc);
506
+ for (j=0; j < argc; j++) {
507
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
508
+ cmd = sdscatfmt(cmd, "$%T\r\n", len);
509
+ cmd = sdscatlen(cmd, argv[j], len);
510
+ cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
511
+ }
512
+
513
+ assert(sdslen(cmd)==totlen);
514
+
515
+ *target = cmd;
516
+ return totlen;
517
+ }
518
+
519
+ void redisFreeSdsCommand(sds cmd) {
520
+ sdsfree(cmd);
521
+ }
522
+
934
523
  /* Format a command according to the Redis protocol. This function takes the
935
524
  * number of arguments, an array with arguments and an array with their
936
525
  * lengths. If the latter is set to NULL, strlen will be used to compute the
@@ -942,8 +531,12 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
942
531
  size_t len;
943
532
  int totlen, j;
944
533
 
534
+ /* Abort on a NULL target */
535
+ if (target == NULL)
536
+ return -1;
537
+
945
538
  /* Calculate number of bytes needed for the command */
946
- totlen = 1+intlen(argc)+2;
539
+ totlen = 1+countDigits(argc)+2;
947
540
  for (j = 0; j < argc; j++) {
948
541
  len = argvlen ? argvlen[j] : strlen(argv[j]);
949
542
  totlen += bulklen(len);
@@ -970,6 +563,10 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
970
563
  return totlen;
971
564
  }
972
565
 
566
+ void redisFreeCommand(char *cmd) {
567
+ free(cmd);
568
+ }
569
+
973
570
  void __redisSetError(redisContext *c, int type, const char *str) {
974
571
  size_t len;
975
572
 
@@ -982,10 +579,14 @@ void __redisSetError(redisContext *c, int type, const char *str) {
982
579
  } else {
983
580
  /* Only REDIS_ERR_IO may lack a description! */
984
581
  assert(type == REDIS_ERR_IO);
985
- strerror_r(errno,c->errstr,sizeof(c->errstr));
582
+ __redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
986
583
  }
987
584
  }
988
585
 
586
+ redisReader *redisReaderCreate(void) {
587
+ return redisReaderCreateWithFunctions(&defaultFunctions);
588
+ }
589
+
989
590
  static redisContext *redisContextInit(void) {
990
591
  redisContext *c;
991
592
 
@@ -997,10 +598,18 @@ static redisContext *redisContextInit(void) {
997
598
  c->errstr[0] = '\0';
998
599
  c->obuf = sdsempty();
999
600
  c->reader = redisReaderCreate();
601
+
602
+ if (c->obuf == NULL || c->reader == NULL) {
603
+ redisFree(c);
604
+ return NULL;
605
+ }
606
+
1000
607
  return c;
1001
608
  }
1002
609
 
1003
610
  void redisFree(redisContext *c) {
611
+ if (c == NULL)
612
+ return;
1004
613
  if (c->fd > 0)
1005
614
  close(c->fd);
1006
615
  if (c->obuf != NULL)
@@ -1010,58 +619,131 @@ void redisFree(redisContext *c) {
1010
619
  free(c);
1011
620
  }
1012
621
 
622
+ int redisFreeKeepFd(redisContext *c) {
623
+ int fd = c->fd;
624
+ c->fd = -1;
625
+ redisFree(c);
626
+ return fd;
627
+ }
628
+
1013
629
  /* Connect to a Redis instance. On error the field error in the returned
1014
630
  * context will be set to the return value of the error function.
1015
631
  * When no set of reply functions is given, the default set will be used. */
1016
632
  redisContext *redisConnect(const char *ip, int port) {
1017
- redisContext *c = redisContextInit();
633
+ redisContext *c;
634
+
635
+ c = redisContextInit();
636
+ if (c == NULL)
637
+ return NULL;
638
+
1018
639
  c->flags |= REDIS_BLOCK;
1019
640
  redisContextConnectTcp(c,ip,port,NULL);
1020
641
  return c;
1021
642
  }
1022
643
 
1023
- redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv) {
1024
- redisContext *c = redisContextInit();
644
+ redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
645
+ redisContext *c;
646
+
647
+ c = redisContextInit();
648
+ if (c == NULL)
649
+ return NULL;
650
+
1025
651
  c->flags |= REDIS_BLOCK;
1026
652
  redisContextConnectTcp(c,ip,port,&tv);
1027
653
  return c;
1028
654
  }
1029
655
 
1030
656
  redisContext *redisConnectNonBlock(const char *ip, int port) {
1031
- redisContext *c = redisContextInit();
657
+ redisContext *c;
658
+
659
+ c = redisContextInit();
660
+ if (c == NULL)
661
+ return NULL;
662
+
1032
663
  c->flags &= ~REDIS_BLOCK;
1033
664
  redisContextConnectTcp(c,ip,port,NULL);
1034
665
  return c;
1035
666
  }
1036
667
 
1037
- redisContext *redisConnectUnix(const char *path) {
668
+ redisContext *redisConnectBindNonBlock(const char *ip, int port,
669
+ const char *source_addr) {
670
+ redisContext *c = redisContextInit();
671
+ c->flags &= ~REDIS_BLOCK;
672
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
673
+ return c;
674
+ }
675
+
676
+ redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
677
+ const char *source_addr) {
1038
678
  redisContext *c = redisContextInit();
679
+ c->flags &= ~REDIS_BLOCK;
680
+ c->flags |= REDIS_REUSEADDR;
681
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
682
+ return c;
683
+ }
684
+
685
+ redisContext *redisConnectUnix(const char *path) {
686
+ redisContext *c;
687
+
688
+ c = redisContextInit();
689
+ if (c == NULL)
690
+ return NULL;
691
+
1039
692
  c->flags |= REDIS_BLOCK;
1040
693
  redisContextConnectUnix(c,path,NULL);
1041
694
  return c;
1042
695
  }
1043
696
 
1044
- redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv) {
1045
- redisContext *c = redisContextInit();
697
+ redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
698
+ redisContext *c;
699
+
700
+ c = redisContextInit();
701
+ if (c == NULL)
702
+ return NULL;
703
+
1046
704
  c->flags |= REDIS_BLOCK;
1047
705
  redisContextConnectUnix(c,path,&tv);
1048
706
  return c;
1049
707
  }
1050
708
 
1051
709
  redisContext *redisConnectUnixNonBlock(const char *path) {
1052
- redisContext *c = redisContextInit();
710
+ redisContext *c;
711
+
712
+ c = redisContextInit();
713
+ if (c == NULL)
714
+ return NULL;
715
+
1053
716
  c->flags &= ~REDIS_BLOCK;
1054
717
  redisContextConnectUnix(c,path,NULL);
1055
718
  return c;
1056
719
  }
1057
720
 
721
+ redisContext *redisConnectFd(int fd) {
722
+ redisContext *c;
723
+
724
+ c = redisContextInit();
725
+ if (c == NULL)
726
+ return NULL;
727
+
728
+ c->fd = fd;
729
+ c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
730
+ return c;
731
+ }
732
+
1058
733
  /* Set read/write timeout on a blocking socket. */
1059
- int redisSetTimeout(redisContext *c, struct timeval tv) {
734
+ int redisSetTimeout(redisContext *c, const struct timeval tv) {
1060
735
  if (c->flags & REDIS_BLOCK)
1061
736
  return redisContextSetTimeout(c,tv);
1062
737
  return REDIS_ERR;
1063
738
  }
1064
739
 
740
+ /* Enable connection KeepAlive. */
741
+ int redisEnableKeepAlive(redisContext *c) {
742
+ if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
743
+ return REDIS_ERR;
744
+ return REDIS_OK;
745
+ }
746
+
1065
747
  /* Use this function to handle a read event on the descriptor. It will try
1066
748
  * and read some bytes from the socket and feed them to the reply parser.
1067
749
  *
@@ -1077,7 +759,7 @@ int redisBufferRead(redisContext *c) {
1077
759
 
1078
760
  nread = read(c->fd,buf,sizeof(buf));
1079
761
  if (nread == -1) {
1080
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
762
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1081
763
  /* Try again later */
1082
764
  } else {
1083
765
  __redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1114,7 +796,7 @@ int redisBufferWrite(redisContext *c, int *done) {
1114
796
  if (sdslen(c->obuf) > 0) {
1115
797
  nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
1116
798
  if (nwritten == -1) {
1117
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
799
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1118
800
  /* Try again later */
1119
801
  } else {
1120
802
  __redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1125,7 +807,7 @@ int redisBufferWrite(redisContext *c, int *done) {
1125
807
  sdsfree(c->obuf);
1126
808
  c->obuf = sdsempty();
1127
809
  } else {
1128
- c->obuf = sdsrange(c->obuf,nwritten,-1);
810
+ sdsrange(c->obuf,nwritten,-1);
1129
811
  }
1130
812
  }
1131
813
  }
@@ -1180,7 +862,7 @@ int redisGetReply(redisContext *c, void **reply) {
1180
862
  * is used, you need to call redisGetReply yourself to retrieve
1181
863
  * the reply (or replies in pub/sub).
1182
864
  */
1183
- int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
865
+ int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
1184
866
  sds newbuf;
1185
867
 
1186
868
  newbuf = sdscatlen(c->obuf,cmd,len);
@@ -1193,6 +875,15 @@ int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
1193
875
  return REDIS_OK;
1194
876
  }
1195
877
 
878
+ int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
879
+
880
+ if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
881
+ return REDIS_ERR;
882
+ }
883
+
884
+ return REDIS_OK;
885
+ }
886
+
1196
887
  int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1197
888
  char *cmd;
1198
889
  int len;
@@ -1201,6 +892,9 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1201
892
  if (len == -1) {
1202
893
  __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1203
894
  return REDIS_ERR;
895
+ } else if (len == -2) {
896
+ __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
897
+ return REDIS_ERR;
1204
898
  }
1205
899
 
1206
900
  if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
@@ -1223,21 +917,21 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
1223
917
  }
1224
918
 
1225
919
  int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
1226
- char *cmd;
920
+ sds cmd;
1227
921
  int len;
1228
922
 
1229
- len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
923
+ len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
1230
924
  if (len == -1) {
1231
925
  __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1232
926
  return REDIS_ERR;
1233
927
  }
1234
928
 
1235
929
  if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1236
- free(cmd);
930
+ sdsfree(cmd);
1237
931
  return REDIS_ERR;
1238
932
  }
1239
933
 
1240
- free(cmd);
934
+ sdsfree(cmd);
1241
935
  return REDIS_OK;
1242
936
  }
1243
937