xref: /redis-3.2.3/deps/hiredis/hiredis.c (revision 28f32c99)
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