1 /*
2 * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3 * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Redis nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "fmacros.h"
33 #include <string.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <assert.h>
37 #include <errno.h>
38 #include <ctype.h>
39
40 #include "hiredis.h"
41 #include "net.h"
42 #include "sds.h"
43
44 static redisReply *createReplyObject(int type);
45 static void *createStringObject(const redisReadTask *task, char *str, size_t len);
46 static void *createArrayObject(const redisReadTask *task, int elements);
47 static void *createIntegerObject(const redisReadTask *task, long long value);
48 static void *createNilObject(const redisReadTask *task);
49
50 /* Default set of functions to build the reply. Keep in mind that such a
51 * function returning NULL is interpreted as OOM. */
52 static redisReplyObjectFunctions defaultFunctions = {
53 createStringObject,
54 createArrayObject,
55 createIntegerObject,
56 createNilObject,
57 freeReplyObject
58 };
59
60 /* Create a reply object */
createReplyObject(int type)61 static redisReply *createReplyObject(int type) {
62 redisReply *r = calloc(1,sizeof(*r));
63
64 if (r == NULL)
65 return NULL;
66
67 r->type = type;
68 return r;
69 }
70
71 /* Free a reply object */
freeReplyObject(void * reply)72 void freeReplyObject(void *reply) {
73 redisReply *r = reply;
74 size_t j;
75
76 switch(r->type) {
77 case REDIS_REPLY_INTEGER:
78 break; /* Nothing to free */
79 case REDIS_REPLY_ARRAY:
80 if (r->element != NULL) {
81 for (j = 0; j < r->elements; j++)
82 if (r->element[j] != NULL)
83 freeReplyObject(r->element[j]);
84 free(r->element);
85 }
86 break;
87 case REDIS_REPLY_ERROR:
88 case REDIS_REPLY_STATUS:
89 case REDIS_REPLY_STRING:
90 if (r->str != NULL)
91 free(r->str);
92 break;
93 }
94 free(r);
95 }
96
createStringObject(const redisReadTask * task,char * str,size_t len)97 static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
98 redisReply *r, *parent;
99 char *buf;
100
101 r = createReplyObject(task->type);
102 if (r == NULL)
103 return NULL;
104
105 buf = malloc(len+1);
106 if (buf == NULL) {
107 freeReplyObject(r);
108 return NULL;
109 }
110
111 assert(task->type == REDIS_REPLY_ERROR ||
112 task->type == REDIS_REPLY_STATUS ||
113 task->type == REDIS_REPLY_STRING);
114
115 /* Copy string value */
116 memcpy(buf,str,len);
117 buf[len] = '\0';
118 r->str = buf;
119 r->len = len;
120
121 if (task->parent) {
122 parent = task->parent->obj;
123 assert(parent->type == REDIS_REPLY_ARRAY);
124 parent->element[task->idx] = r;
125 }
126 return r;
127 }
128
createArrayObject(const redisReadTask * task,int elements)129 static void *createArrayObject(const redisReadTask *task, int elements) {
130 redisReply *r, *parent;
131
132 r = createReplyObject(REDIS_REPLY_ARRAY);
133 if (r == NULL)
134 return NULL;
135
136 if (elements > 0) {
137 r->element = calloc(elements,sizeof(redisReply*));
138 if (r->element == NULL) {
139 freeReplyObject(r);
140 return NULL;
141 }
142 }
143
144 r->elements = elements;
145
146 if (task->parent) {
147 parent = task->parent->obj;
148 assert(parent->type == REDIS_REPLY_ARRAY);
149 parent->element[task->idx] = r;
150 }
151 return r;
152 }
153
createIntegerObject(const redisReadTask * task,long long value)154 static void *createIntegerObject(const redisReadTask *task, long long value) {
155 redisReply *r, *parent;
156
157 r = createReplyObject(REDIS_REPLY_INTEGER);
158 if (r == NULL)
159 return NULL;
160
161 r->integer = value;
162
163 if (task->parent) {
164 parent = task->parent->obj;
165 assert(parent->type == REDIS_REPLY_ARRAY);
166 parent->element[task->idx] = r;
167 }
168 return r;
169 }
170
createNilObject(const redisReadTask * task)171 static void *createNilObject(const redisReadTask *task) {
172 redisReply *r, *parent;
173
174 r = createReplyObject(REDIS_REPLY_NIL);
175 if (r == NULL)
176 return NULL;
177
178 if (task->parent) {
179 parent = task->parent->obj;
180 assert(parent->type == REDIS_REPLY_ARRAY);
181 parent->element[task->idx] = r;
182 }
183 return r;
184 }
185
__redisReaderSetError(redisReader * r,int type,const char * str)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
chrtos(char * buf,size_t size,char byte)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
__redisReaderSetErrorProtocolByte(redisReader * r,char byte)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
__redisReaderSetErrorOOM(redisReader * r)245 static void __redisReaderSetErrorOOM(redisReader *r) {
246 __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
247 }
248
readBytes(redisReader * r,unsigned int bytes)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. */
seekNewline(char * s,size_t len)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. */
readLongLong(char * s)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
readLine(redisReader * r,int * _len)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
moveToNextTask(redisReader * r)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
processLineItem(redisReader * r)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
processBulkItem(redisReader * r)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
processMultiBulkItem(redisReader * r)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
processItem(redisReader * r)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
redisReaderCreate(void)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
redisReaderFree(redisReader * r)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
redisReaderFeed(redisReader * r,const char * buf,size_t len)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
redisReaderGetReply(redisReader * r,void ** reply)617 int redisReaderGetReply(redisReader *r, void **reply) {
618 /* Default target pointer to NULL. */
619 if (reply != NULL)
620 *reply = NULL;
621
622 /* Return early when this reader is in an erroneous state. */
623 if (r->err)
624 return REDIS_ERR;
625
626 /* When the buffer is empty, there will never be a reply. */
627 if (r->len == 0)
628 return REDIS_OK;
629
630 /* Set first item to process when the stack is empty. */
631 if (r->ridx == -1) {
632 r->rstack[0].type = -1;
633 r->rstack[0].elements = -1;
634 r->rstack[0].idx = -1;
635 r->rstack[0].obj = NULL;
636 r->rstack[0].parent = NULL;
637 r->rstack[0].privdata = r->privdata;
638 r->ridx = 0;
639 }
640
641 /* Process items in reply. */
642 while (r->ridx >= 0)
643 if (processItem(r) != REDIS_OK)
644 break;
645
646 /* Return ASAP when an error occurred. */
647 if (r->err)
648 return REDIS_ERR;
649
650 /* Discard part of the buffer when we've consumed at least 1k, to avoid
651 * doing unnecessary calls to memmove() in sds.c. */
652 if (r->pos >= 1024) {
653 sdsrange(r->buf,r->pos,-1);
654 r->pos = 0;
655 r->len = sdslen(r->buf);
656 }
657
658 /* Emit a reply when there is one. */
659 if (r->ridx == -1) {
660 if (reply != NULL)
661 *reply = r->reply;
662 r->reply = NULL;
663 }
664 return REDIS_OK;
665 }
666
667 /* Calculate the number of bytes needed to represent an integer as string. */
intlen(int i)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;
679 }
680
681 /* Helper that calculates the bulk length given a certain string length. */
bulklen(size_t len)682 static size_t bulklen(size_t len) {
683 return 1+intlen(len)+2+len+2;
684 }
685
redisvFormatCommand(char ** target,const char * format,va_list ap)686 int redisvFormatCommand(char **target, const char *format, va_list ap) {
687 const char *c = format;
688 char *cmd = NULL; /* final command */
689 int pos; /* position in final command */
690 sds curarg, newarg; /* current argument */
691 int touched = 0; /* was the current argument touched? */
692 char **curargv = NULL, **newargv = NULL;
693 int argc = 0;
694 int totlen = 0;
695 int j;
696
697 /* Abort if there is not target to set */
698 if (target == NULL)
699 return -1;
700
701 /* Build the command string accordingly to protocol */
702 curarg = sdsempty();
703 if (curarg == NULL)
704 return -1;
705
706 while(*c != '\0') {
707 if (*c != '%' || c[1] == '\0') {
708 if (*c == ' ') {
709 if (touched) {
710 newargv = realloc(curargv,sizeof(char*)*(argc+1));
711 if (newargv == NULL) goto err;
712 curargv = newargv;
713 curargv[argc++] = curarg;
714 totlen += bulklen(sdslen(curarg));
715
716 /* curarg is put in argv so it can be overwritten. */
717 curarg = sdsempty();
718 if (curarg == NULL) goto err;
719 touched = 0;
720 }
721 } else {
722 newarg = sdscatlen(curarg,c,1);
723 if (newarg == NULL) goto err;
724 curarg = newarg;
725 touched = 1;
726 }
727 } else {
728 char *arg;
729 size_t size;
730
731 /* Set newarg so it can be checked even if it is not touched. */
732 newarg = curarg;
733
734 switch(c[1]) {
735 case 's':
736 arg = va_arg(ap,char*);
737 size = strlen(arg);
738 if (size > 0)
739 newarg = sdscatlen(curarg,arg,size);
740 break;
741 case 'b':
742 arg = va_arg(ap,char*);
743 size = va_arg(ap,size_t);
744 if (size > 0)
745 newarg = sdscatlen(curarg,arg,size);
746 break;
747 case '%':
748 newarg = sdscat(curarg,"%");
749 break;
750 default:
751 /* Try to detect printf format */
752 {
753 static const char intfmts[] = "diouxX";
754 char _format[16];
755 const char *_p = c+1;
756 size_t _l = 0;
757 va_list _cpy;
758
759 /* 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++;
765
766 /* Field width */
767 while (*_p != '\0' && isdigit(*_p)) _p++;
768
769 /* Precision */
770 if (*_p == '.') {
771 _p++;
772 while (*_p != '\0' && isdigit(*_p)) _p++;
773 }
774
775 /* Copy va_list before consuming with va_arg */
776 va_copy(_cpy,ap);
777
778 /* Integer conversion (without modifiers) */
779 if (strchr(intfmts,*_p) != NULL) {
780 va_arg(ap,int);
781 goto fmt_valid;
782 }
783
784 /* Double conversion (without modifiers) */
785 if (strchr("eEfFgGaA",*_p) != NULL) {
786 va_arg(ap,double);
787 goto fmt_valid;
788 }
789
790 /* Size: char */
791 if (_p[0] == 'h' && _p[1] == 'h') {
792 _p += 2;
793 if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
794 va_arg(ap,int); /* char gets promoted to int */
795 goto fmt_valid;
796 }
797 goto fmt_invalid;
798 }
799
800 /* Size: short */
801 if (_p[0] == 'h') {
802 _p += 1;
803 if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
804 va_arg(ap,int); /* short gets promoted to int */
805 goto fmt_valid;
806 }
807 goto fmt_invalid;
808 }
809
810 /* Size: long long */
811 if (_p[0] == 'l' && _p[1] == 'l') {
812 _p += 2;
813 if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
814 va_arg(ap,long long);
815 goto fmt_valid;
816 }
817 goto fmt_invalid;
818 }
819
820 /* Size: long */
821 if (_p[0] == 'l') {
822 _p += 1;
823 if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
824 va_arg(ap,long);
825 goto fmt_valid;
826 }
827 goto fmt_invalid;
828 }
829
830 fmt_invalid:
831 va_end(_cpy);
832 goto err;
833
834 fmt_valid:
835 _l = (_p+1)-c;
836 if (_l < sizeof(_format)-2) {
837 memcpy(_format,c,_l);
838 _format[_l] = '\0';
839 newarg = sdscatvprintf(curarg,_format,_cpy);
840
841 /* Update current position (note: outer blocks
842 * increment c twice so compensate here) */
843 c = _p-1;
844 }
845
846 va_end(_cpy);
847 break;
848 }
849 }
850
851 if (newarg == NULL) goto err;
852 curarg = newarg;
853
854 touched = 1;
855 c++;
856 }
857 c++;
858 }
859
860 /* Add the last argument if needed */
861 if (touched) {
862 newargv = realloc(curargv,sizeof(char*)*(argc+1));
863 if (newargv == NULL) goto err;
864 curargv = newargv;
865 curargv[argc++] = curarg;
866 totlen += bulklen(sdslen(curarg));
867 } else {
868 sdsfree(curarg);
869 }
870
871 /* Clear curarg because it was put in curargv or was free'd. */
872 curarg = NULL;
873
874 /* Add bytes needed to hold multi bulk count */
875 totlen += 1+intlen(argc)+2;
876
877 /* Build the command at protocol level */
878 cmd = malloc(totlen+1);
879 if (cmd == NULL) goto err;
880
881 pos = sprintf(cmd,"*%d\r\n",argc);
882 for (j = 0; j < argc; j++) {
883 pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
884 memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
885 pos += sdslen(curargv[j]);
886 sdsfree(curargv[j]);
887 cmd[pos++] = '\r';
888 cmd[pos++] = '\n';
889 }
890 assert(pos == totlen);
891 cmd[pos] = '\0';
892
893 free(curargv);
894 *target = cmd;
895 return totlen;
896
897 err:
898 while(argc--)
899 sdsfree(curargv[argc]);
900 free(curargv);
901
902 if (curarg != NULL)
903 sdsfree(curarg);
904
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);
909
910 return -1;
911 }
912
913 /* Format a command according to the Redis protocol. This function
914 * takes a format similar to printf:
915 *
916 * %s represents a C null terminated string you want to interpolate
917 * %b represents a binary safe string
918 *
919 * When using %b you need to provide both the pointer to the string
920 * and the length in bytes as a size_t. Examples:
921 *
922 * len = redisFormatCommand(target, "GET %s", mykey);
923 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
924 */
redisFormatCommand(char ** target,const char * format,...)925 int redisFormatCommand(char **target, const char *format, ...) {
926 va_list ap;
927 int len;
928 va_start(ap,format);
929 len = redisvFormatCommand(target,format,ap);
930 va_end(ap);
931 return len;
932 }
933
934 /* Format a command according to the Redis protocol. This function takes the
935 * number of arguments, an array with arguments and an array with their
936 * lengths. If the latter is set to NULL, strlen will be used to compute the
937 * argument lengths.
938 */
redisFormatCommandArgv(char ** target,int argc,const char ** argv,const size_t * argvlen)939 int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
940 char *cmd = NULL; /* final command */
941 int pos; /* position in final command */
942 size_t len;
943 int totlen, j;
944
945 /* Calculate number of bytes needed for the command */
946 totlen = 1+intlen(argc)+2;
947 for (j = 0; j < argc; j++) {
948 len = argvlen ? argvlen[j] : strlen(argv[j]);
949 totlen += bulklen(len);
950 }
951
952 /* Build the command at protocol level */
953 cmd = malloc(totlen+1);
954 if (cmd == NULL)
955 return -1;
956
957 pos = sprintf(cmd,"*%d\r\n",argc);
958 for (j = 0; j < argc; j++) {
959 len = argvlen ? argvlen[j] : strlen(argv[j]);
960 pos += sprintf(cmd+pos,"$%zu\r\n",len);
961 memcpy(cmd+pos,argv[j],len);
962 pos += len;
963 cmd[pos++] = '\r';
964 cmd[pos++] = '\n';
965 }
966 assert(pos == totlen);
967 cmd[pos] = '\0';
968
969 *target = cmd;
970 return totlen;
971 }
972
__redisSetError(redisContext * c,int type,const char * str)973 void __redisSetError(redisContext *c, int type, const char *str) {
974 size_t len;
975
976 c->err = type;
977 if (str != NULL) {
978 len = strlen(str);
979 len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
980 memcpy(c->errstr,str,len);
981 c->errstr[len] = '\0';
982 } else {
983 /* Only REDIS_ERR_IO may lack a description! */
984 assert(type == REDIS_ERR_IO);
985 strerror_r(errno,c->errstr,sizeof(c->errstr));
986 }
987 }
988
redisContextInit(void)989 static redisContext *redisContextInit(void) {
990 redisContext *c;
991
992 c = calloc(1,sizeof(redisContext));
993 if (c == NULL)
994 return NULL;
995
996 c->err = 0;
997 c->errstr[0] = '\0';
998 c->obuf = sdsempty();
999 c->reader = redisReaderCreate();
1000 return c;
1001 }
1002
redisFree(redisContext * c)1003 void redisFree(redisContext *c) {
1004 if (c->fd > 0)
1005 close(c->fd);
1006 if (c->obuf != NULL)
1007 sdsfree(c->obuf);
1008 if (c->reader != NULL)
1009 redisReaderFree(c->reader);
1010 free(c);
1011 }
1012
redisFreeKeepFd(redisContext * c)1013 int redisFreeKeepFd(redisContext *c) {
1014 int fd = c->fd;
1015 c->fd = -1;
1016 redisFree(c);
1017 return fd;
1018 }
1019
1020 /* Connect to a Redis instance. On error the field error in the returned
1021 * context will be set to the return value of the error function.
1022 * When no set of reply functions is given, the default set will be used. */
redisConnect(const char * ip,int port)1023 redisContext *redisConnect(const char *ip, int port) {
1024 redisContext *c;
1025
1026 c = redisContextInit();
1027 if (c == NULL)
1028 return NULL;
1029
1030 c->flags |= REDIS_BLOCK;
1031 redisContextConnectTcp(c,ip,port,NULL);
1032 return c;
1033 }
1034
redisConnectWithTimeout(const char * ip,int port,const struct timeval tv)1035 redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
1036 redisContext *c;
1037
1038 c = redisContextInit();
1039 if (c == NULL)
1040 return NULL;
1041
1042 c->flags |= REDIS_BLOCK;
1043 redisContextConnectTcp(c,ip,port,&tv);
1044 return c;
1045 }
1046
redisConnectNonBlock(const char * ip,int port)1047 redisContext *redisConnectNonBlock(const char *ip, int port) {
1048 redisContext *c;
1049
1050 c = redisContextInit();
1051 if (c == NULL)
1052 return NULL;
1053
1054 c->flags &= ~REDIS_BLOCK;
1055 redisContextConnectTcp(c,ip,port,NULL);
1056 return c;
1057 }
1058
redisConnectBindNonBlock(const char * ip,int port,const char * source_addr)1059 redisContext *redisConnectBindNonBlock(const char *ip, int port,
1060 const char *source_addr) {
1061 redisContext *c = redisContextInit();
1062 c->flags &= ~REDIS_BLOCK;
1063 redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
1064 return c;
1065 }
1066
redisConnectUnix(const char * path)1067 redisContext *redisConnectUnix(const char *path) {
1068 redisContext *c;
1069
1070 c = redisContextInit();
1071 if (c == NULL)
1072 return NULL;
1073
1074 c->flags |= REDIS_BLOCK;
1075 redisContextConnectUnix(c,path,NULL);
1076 return c;
1077 }
1078
redisConnectUnixWithTimeout(const char * path,const struct timeval tv)1079 redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
1080 redisContext *c;
1081
1082 c = redisContextInit();
1083 if (c == NULL)
1084 return NULL;
1085
1086 c->flags |= REDIS_BLOCK;
1087 redisContextConnectUnix(c,path,&tv);
1088 return c;
1089 }
1090
redisConnectUnixNonBlock(const char * path)1091 redisContext *redisConnectUnixNonBlock(const char *path) {
1092 redisContext *c;
1093
1094 c = redisContextInit();
1095 if (c == NULL)
1096 return NULL;
1097
1098 c->flags &= ~REDIS_BLOCK;
1099 redisContextConnectUnix(c,path,NULL);
1100 return c;
1101 }
1102
redisConnectFd(int fd)1103 redisContext *redisConnectFd(int fd) {
1104 redisContext *c;
1105
1106 c = redisContextInit();
1107 if (c == NULL)
1108 return NULL;
1109
1110 c->fd = fd;
1111 c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
1112 return c;
1113 }
1114
1115 /* Set read/write timeout on a blocking socket. */
redisSetTimeout(redisContext * c,const struct timeval tv)1116 int redisSetTimeout(redisContext *c, const struct timeval tv) {
1117 if (c->flags & REDIS_BLOCK)
1118 return redisContextSetTimeout(c,tv);
1119 return REDIS_ERR;
1120 }
1121
1122 /* Enable connection KeepAlive. */
redisEnableKeepAlive(redisContext * c)1123 int redisEnableKeepAlive(redisContext *c) {
1124 if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
1125 return REDIS_ERR;
1126 return REDIS_OK;
1127 }
1128
1129 /* Use this function to handle a read event on the descriptor. It will try
1130 * and read some bytes from the socket and feed them to the reply parser.
1131 *
1132 * After this function is called, you may use redisContextReadReply to
1133 * see if there is a reply available. */
redisBufferRead(redisContext * c)1134 int redisBufferRead(redisContext *c) {
1135 char buf[1024*16];
1136 int nread;
1137
1138 /* Return early when the context has seen an error. */
1139 if (c->err)
1140 return REDIS_ERR;
1141
1142 nread = read(c->fd,buf,sizeof(buf));
1143 if (nread == -1) {
1144 if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1145 /* Try again later */
1146 } else {
1147 __redisSetError(c,REDIS_ERR_IO,NULL);
1148 return REDIS_ERR;
1149 }
1150 } else if (nread == 0) {
1151 __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
1152 return REDIS_ERR;
1153 } else {
1154 if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
1155 __redisSetError(c,c->reader->err,c->reader->errstr);
1156 return REDIS_ERR;
1157 }
1158 }
1159 return REDIS_OK;
1160 }
1161
1162 /* Write the output buffer to the socket.
1163 *
1164 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
1165 * succesfully written to the socket. When the buffer is empty after the
1166 * write operation, "done" is set to 1 (if given).
1167 *
1168 * Returns REDIS_ERR if an error occured trying to write and sets
1169 * c->errstr to hold the appropriate error string.
1170 */
redisBufferWrite(redisContext * c,int * done)1171 int redisBufferWrite(redisContext *c, int *done) {
1172 int nwritten;
1173
1174 /* Return early when the context has seen an error. */
1175 if (c->err)
1176 return REDIS_ERR;
1177
1178 if (sdslen(c->obuf) > 0) {
1179 nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
1180 if (nwritten == -1) {
1181 if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1182 /* Try again later */
1183 } else {
1184 __redisSetError(c,REDIS_ERR_IO,NULL);
1185 return REDIS_ERR;
1186 }
1187 } else if (nwritten > 0) {
1188 if (nwritten == (signed)sdslen(c->obuf)) {
1189 sdsfree(c->obuf);
1190 c->obuf = sdsempty();
1191 } else {
1192 sdsrange(c->obuf,nwritten,-1);
1193 }
1194 }
1195 }
1196 if (done != NULL) *done = (sdslen(c->obuf) == 0);
1197 return REDIS_OK;
1198 }
1199
1200 /* Internal helper function to try and get a reply from the reader,
1201 * or set an error in the context otherwise. */
redisGetReplyFromReader(redisContext * c,void ** reply)1202 int redisGetReplyFromReader(redisContext *c, void **reply) {
1203 if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
1204 __redisSetError(c,c->reader->err,c->reader->errstr);
1205 return REDIS_ERR;
1206 }
1207 return REDIS_OK;
1208 }
1209
redisGetReply(redisContext * c,void ** reply)1210 int redisGetReply(redisContext *c, void **reply) {
1211 int wdone = 0;
1212 void *aux = NULL;
1213
1214 /* Try to read pending replies */
1215 if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
1216 return REDIS_ERR;
1217
1218 /* For the blocking context, flush output buffer and read reply */
1219 if (aux == NULL && c->flags & REDIS_BLOCK) {
1220 /* Write until done */
1221 do {
1222 if (redisBufferWrite(c,&wdone) == REDIS_ERR)
1223 return REDIS_ERR;
1224 } while (!wdone);
1225
1226 /* Read until there is a reply */
1227 do {
1228 if (redisBufferRead(c) == REDIS_ERR)
1229 return REDIS_ERR;
1230 if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
1231 return REDIS_ERR;
1232 } while (aux == NULL);
1233 }
1234
1235 /* Set reply object */
1236 if (reply != NULL) *reply = aux;
1237 return REDIS_OK;
1238 }
1239
1240
1241 /* Helper function for the redisAppendCommand* family of functions.
1242 *
1243 * Write a formatted command to the output buffer. When this family
1244 * is used, you need to call redisGetReply yourself to retrieve
1245 * the reply (or replies in pub/sub).
1246 */
__redisAppendCommand(redisContext * c,const char * cmd,size_t len)1247 int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
1248 sds newbuf;
1249
1250 newbuf = sdscatlen(c->obuf,cmd,len);
1251 if (newbuf == NULL) {
1252 __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1253 return REDIS_ERR;
1254 }
1255
1256 c->obuf = newbuf;
1257 return REDIS_OK;
1258 }
1259
redisAppendFormattedCommand(redisContext * c,const char * cmd,size_t len)1260 int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
1261
1262 if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
1263 return REDIS_ERR;
1264 }
1265
1266 return REDIS_OK;
1267 }
1268
redisvAppendCommand(redisContext * c,const char * format,va_list ap)1269 int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1270 char *cmd;
1271 int len;
1272
1273 len = redisvFormatCommand(&cmd,format,ap);
1274 if (len == -1) {
1275 __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1276 return REDIS_ERR;
1277 }
1278
1279 if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1280 free(cmd);
1281 return REDIS_ERR;
1282 }
1283
1284 free(cmd);
1285 return REDIS_OK;
1286 }
1287
redisAppendCommand(redisContext * c,const char * format,...)1288 int redisAppendCommand(redisContext *c, const char *format, ...) {
1289 va_list ap;
1290 int ret;
1291
1292 va_start(ap,format);
1293 ret = redisvAppendCommand(c,format,ap);
1294 va_end(ap);
1295 return ret;
1296 }
1297
redisAppendCommandArgv(redisContext * c,int argc,const char ** argv,const size_t * argvlen)1298 int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
1299 char *cmd;
1300 int len;
1301
1302 len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
1303 if (len == -1) {
1304 __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1305 return REDIS_ERR;
1306 }
1307
1308 if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1309 free(cmd);
1310 return REDIS_ERR;
1311 }
1312
1313 free(cmd);
1314 return REDIS_OK;
1315 }
1316
1317 /* Helper function for the redisCommand* family of functions.
1318 *
1319 * Write a formatted command to the output buffer. If the given context is
1320 * blocking, immediately read the reply into the "reply" pointer. When the
1321 * context is non-blocking, the "reply" pointer will not be used and the
1322 * command is simply appended to the write buffer.
1323 *
1324 * Returns the reply when a reply was succesfully retrieved. Returns NULL
1325 * otherwise. When NULL is returned in a blocking context, the error field
1326 * in the context will be set.
1327 */
__redisBlockForReply(redisContext * c)1328 static void *__redisBlockForReply(redisContext *c) {
1329 void *reply;
1330
1331 if (c->flags & REDIS_BLOCK) {
1332 if (redisGetReply(c,&reply) != REDIS_OK)
1333 return NULL;
1334 return reply;
1335 }
1336 return NULL;
1337 }
1338
redisvCommand(redisContext * c,const char * format,va_list ap)1339 void *redisvCommand(redisContext *c, const char *format, va_list ap) {
1340 if (redisvAppendCommand(c,format,ap) != REDIS_OK)
1341 return NULL;
1342 return __redisBlockForReply(c);
1343 }
1344
redisCommand(redisContext * c,const char * format,...)1345 void *redisCommand(redisContext *c, const char *format, ...) {
1346 va_list ap;
1347 void *reply = NULL;
1348 va_start(ap,format);
1349 reply = redisvCommand(c,format,ap);
1350 va_end(ap);
1351 return reply;
1352 }
1353
redisCommandArgv(redisContext * c,int argc,const char ** argv,const size_t * argvlen)1354 void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
1355 if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
1356 return NULL;
1357 return __redisBlockForReply(c);
1358 }
1359