hiredis 0.5.2 → 0.6.0

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