]> git.saurik.com Git - redis.git/blame - deps/hiredis/hiredis.c
Query the archive to provide a complete KEYS list.
[redis.git] / deps / hiredis / hiredis.c
CommitLineData
24f753a8 1/*
b66e5add 2 * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3 * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
a1e97d69 4 *
24f753a8
PN
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
b66e5add 32#include "fmacros.h"
24f753a8
PN
33#include <string.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <assert.h>
37#include <errno.h>
a1e97d69 38#include <ctype.h>
24f753a8
PN
39
40#include "hiredis.h"
41#include "net.h"
42#include "sds.h"
24f753a8
PN
43
44static redisReply *createReplyObject(int type);
45static void *createStringObject(const redisReadTask *task, char *str, size_t len);
46static void *createArrayObject(const redisReadTask *task, int elements);
47static void *createIntegerObject(const redisReadTask *task, long long value);
48static void *createNilObject(const redisReadTask *task);
24f753a8 49
b66e5add 50/* Default set of functions to build the reply. Keep in mind that such a
51 * function returning NULL is interpreted as OOM. */
24f753a8
PN
52static redisReplyObjectFunctions defaultFunctions = {
53 createStringObject,
54 createArrayObject,
55 createIntegerObject,
56 createNilObject,
57 freeReplyObject
58};
59
60/* Create a reply object */
61static redisReply *createReplyObject(int type) {
b66e5add 62 redisReply *r = calloc(1,sizeof(*r));
63
64 if (r == NULL)
65 return NULL;
24f753a8 66
24f753a8
PN
67 r->type = type;
68 return r;
69}
70
71/* Free a reply object */
72void 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:
b66e5add 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 }
24f753a8 86 break;
a1e97d69
PN
87 case REDIS_REPLY_ERROR:
88 case REDIS_REPLY_STATUS:
89 case REDIS_REPLY_STRING:
b66e5add 90 if (r->str != NULL)
91 free(r->str);
24f753a8
PN
92 break;
93 }
94 free(r);
95}
96
97static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
b66e5add 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 ||
24f753a8
PN
112 task->type == REDIS_REPLY_STATUS ||
113 task->type == REDIS_REPLY_STRING);
114
115 /* Copy string value */
b66e5add 116 memcpy(buf,str,len);
117 buf[len] = '\0';
118 r->str = buf;
24f753a8
PN
119 r->len = len;
120
121 if (task->parent) {
b66e5add 122 parent = task->parent->obj;
24f753a8
PN
123 assert(parent->type == REDIS_REPLY_ARRAY);
124 parent->element[task->idx] = r;
125 }
126 return r;
127}
128
129static void *createArrayObject(const redisReadTask *task, int elements) {
b66e5add 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
24f753a8 144 r->elements = elements;
b66e5add 145
24f753a8 146 if (task->parent) {
b66e5add 147 parent = task->parent->obj;
24f753a8
PN
148 assert(parent->type == REDIS_REPLY_ARRAY);
149 parent->element[task->idx] = r;
150 }
151 return r;
152}
153
154static void *createIntegerObject(const redisReadTask *task, long long value) {
b66e5add 155 redisReply *r, *parent;
156
157 r = createReplyObject(REDIS_REPLY_INTEGER);
158 if (r == NULL)
159 return NULL;
160
24f753a8 161 r->integer = value;
b66e5add 162
24f753a8 163 if (task->parent) {
b66e5add 164 parent = task->parent->obj;
24f753a8
PN
165 assert(parent->type == REDIS_REPLY_ARRAY);
166 parent->element[task->idx] = r;
167 }
168 return r;
169}
170
171static void *createNilObject(const redisReadTask *task) {
b66e5add 172 redisReply *r, *parent;
173
174 r = createReplyObject(REDIS_REPLY_NIL);
175 if (r == NULL)
176 return NULL;
177
24f753a8 178 if (task->parent) {
b66e5add 179 parent = task->parent->obj;
24f753a8
PN
180 assert(parent->type == REDIS_REPLY_ARRAY);
181 parent->element[task->idx] = r;
182 }
183 return r;
184}
185
b66e5add 186static 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
212static 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
236static 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
245static void __redisReaderSetErrorOOM(redisReader *r) {
246 __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
247}
248
24f753a8
PN
249static char *readBytes(redisReader *r, unsigned int bytes) {
250 char *p;
a1e97d69 251 if (r->len-r->pos >= bytes) {
24f753a8
PN
252 p = r->buf+r->pos;
253 r->pos += bytes;
254 return p;
255 }
256 return NULL;
257}
258
a1e97d69
PN
259/* Find pointer to \r\n. */
260static 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;
57c9babd 273 } else {
a1e97d69
PN
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. */
288static 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;
57c9babd
PN
309 }
310 }
a1e97d69
PN
311
312 return mult*v;
afc156c2
PN
313}
314
24f753a8 315static char *readLine(redisReader *r, int *_len) {
afc156c2 316 char *p, *s;
24f753a8 317 int len;
afc156c2
PN
318
319 p = r->buf+r->pos;
a1e97d69 320 s = seekNewline(p,(r->len-r->pos));
24f753a8 321 if (s != NULL) {
24f753a8
PN
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
330static void moveToNextTask(redisReader *r) {
331 redisReadTask *cur, *prv;
afc156c2
PN
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 }
24f753a8 338
afc156c2
PN
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 }
24f753a8
PN
352 }
353}
354
355static 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) {
9703b1b3
PN
362 if (cur->type == REDIS_REPLY_INTEGER) {
363 if (r->fn && r->fn->createInteger)
a1e97d69 364 obj = r->fn->createInteger(cur,readLongLong(p));
9703b1b3
PN
365 else
366 obj = (void*)REDIS_REPLY_INTEGER;
24f753a8 367 } else {
9703b1b3
PN
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);
24f753a8
PN
373 }
374
b66e5add 375 if (obj == NULL) {
376 __redisReaderSetErrorOOM(r);
377 return REDIS_ERR;
378 }
379
a1e97d69
PN
380 /* Set reply if this is the root object. */
381 if (r->ridx == 0) r->reply = obj;
24f753a8 382 moveToNextTask(r);
b66e5add 383 return REDIS_OK;
24f753a8 384 }
b66e5add 385
386 return REDIS_ERR;
24f753a8
PN
387}
388
389static 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;
a1e97d69 395 int success = 0;
24f753a8
PN
396
397 p = r->buf+r->pos;
a1e97d69 398 s = seekNewline(p,r->len-r->pos);
24f753a8
PN
399 if (s != NULL) {
400 p = r->buf+r->pos;
401 bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
a1e97d69 402 len = readLongLong(p);
24f753a8
PN
403
404 if (len < 0) {
405 /* The nil object can always be created. */
9703b1b3
PN
406 if (r->fn && r->fn->createNil)
407 obj = r->fn->createNil(cur);
408 else
409 obj = (void*)REDIS_REPLY_NIL;
a1e97d69 410 success = 1;
24f753a8
PN
411 } else {
412 /* Only continue when the buffer contains the entire bulk item. */
413 bytelen += len+2; /* include \r\n */
a1e97d69 414 if (r->pos+bytelen <= r->len) {
9703b1b3
PN
415 if (r->fn && r->fn->createString)
416 obj = r->fn->createString(cur,s+2,len);
417 else
418 obj = (void*)REDIS_REPLY_STRING;
a1e97d69 419 success = 1;
24f753a8
PN
420 }
421 }
422
423 /* Proceed when obj was created. */
a1e97d69 424 if (success) {
b66e5add 425 if (obj == NULL) {
426 __redisReaderSetErrorOOM(r);
427 return REDIS_ERR;
428 }
429
24f753a8 430 r->pos += bytelen;
a1e97d69
PN
431
432 /* Set reply if this is the root object. */
433 if (r->ridx == 0) r->reply = obj;
24f753a8 434 moveToNextTask(r);
b66e5add 435 return REDIS_OK;
24f753a8
PN
436 }
437 }
b66e5add 438
439 return REDIS_ERR;
24f753a8
PN
440}
441
442static int processMultiBulkItem(redisReader *r) {
443 redisReadTask *cur = &(r->rstack[r->ridx]);
444 void *obj;
445 char *p;
446 long elements;
a1e97d69
PN
447 int root = 0;
448
7fcba9fd 449 /* Set error for nested multi bulks with depth > 7 */
8e65b6a3 450 if (r->ridx == 8) {
b66e5add 451 __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
8e65b6a3 452 "No support for nested multi bulk replies with depth > 7");
b66e5add 453 return REDIS_ERR;
a1e97d69 454 }
24f753a8
PN
455
456 if ((p = readLine(r,NULL)) != NULL) {
a1e97d69
PN
457 elements = readLongLong(p);
458 root = (r->ridx == 0);
459
24f753a8 460 if (elements == -1) {
9703b1b3
PN
461 if (r->fn && r->fn->createNil)
462 obj = r->fn->createNil(cur);
463 else
464 obj = (void*)REDIS_REPLY_NIL;
b66e5add 465
466 if (obj == NULL) {
467 __redisReaderSetErrorOOM(r);
468 return REDIS_ERR;
469 }
470
24f753a8
PN
471 moveToNextTask(r);
472 } else {
9703b1b3
PN
473 if (r->fn && r->fn->createArray)
474 obj = r->fn->createArray(cur,elements);
475 else
476 obj = (void*)REDIS_REPLY_ARRAY;
24f753a8 477
b66e5add 478 if (obj == NULL) {
479 __redisReaderSetErrorOOM(r);
480 return REDIS_ERR;
481 }
482
24f753a8
PN
483 /* Modify task stack when there are more than 0 elements. */
484 if (elements > 0) {
485 cur->elements = elements;
a1e97d69 486 cur->obj = obj;
24f753a8
PN
487 r->ridx++;
488 r->rstack[r->ridx].type = -1;
489 r->rstack[r->ridx].elements = -1;
24f753a8 490 r->rstack[r->ridx].idx = 0;
a1e97d69
PN
491 r->rstack[r->ridx].obj = NULL;
492 r->rstack[r->ridx].parent = cur;
493 r->rstack[r->ridx].privdata = r->privdata;
24f753a8
PN
494 } else {
495 moveToNextTask(r);
496 }
497 }
498
a1e97d69
PN
499 /* Set reply if this is the root object. */
500 if (root) r->reply = obj;
b66e5add 501 return REDIS_OK;
24f753a8 502 }
b66e5add 503
504 return REDIS_ERR;
24f753a8
PN
505}
506
507static int processItem(redisReader *r) {
508 redisReadTask *cur = &(r->rstack[r->ridx]);
509 char *p;
24f753a8
PN
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:
b66e5add 531 __redisReaderSetErrorProtocolByte(r,*p);
532 return REDIS_ERR;
24f753a8
PN
533 }
534 } else {
535 /* could not consume 1 byte */
b66e5add 536 return REDIS_ERR;
24f753a8
PN
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:
a1e97d69 551 assert(NULL);
b66e5add 552 return REDIS_ERR; /* Avoid warning. */
24f753a8
PN
553 }
554}
555
b66e5add 556redisReader *redisReaderCreate(void) {
557 redisReader *r;
24f753a8 558
b66e5add 559 r = calloc(sizeof(redisReader),1);
560 if (r == NULL)
561 return NULL;
afc156c2 562
b66e5add 563 r->err = 0;
564 r->errstr[0] = '\0';
565 r->fn = &defaultFunctions;
566 r->buf = sdsempty();
7fcba9fd 567 r->maxbuf = REDIS_READER_MAX_BUF;
b66e5add 568 if (r->buf == NULL) {
569 free(r);
570 return NULL;
a1e97d69 571 }
a1e97d69 572
b66e5add 573 r->ridx = -1;
574 return r;
24f753a8
PN
575}
576
b66e5add 577void redisReaderFree(redisReader *r) {
578 if (r->reply != NULL && r->fn && r->fn->freeObject)
24f753a8
PN
579 r->fn->freeObject(r->reply);
580 if (r->buf != NULL)
581 sdsfree(r->buf);
582 free(r);
583}
584
b66e5add 585int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
586 sds newbuf;
24f753a8 587
b66e5add 588 /* Return early when this reader is in an erroneous state. */
589 if (r->err)
590 return REDIS_ERR;
24f753a8
PN
591
592 /* Copy the provided buffer. */
a1e97d69 593 if (buf != NULL && len >= 1) {
9703b1b3 594 /* Destroy internal buffer when it is empty and is quite large. */
7fcba9fd 595 if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
9703b1b3
PN
596 sdsfree(r->buf);
597 r->buf = sdsempty();
598 r->pos = 0;
b66e5add 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;
9703b1b3 608 }
b66e5add 609
610 r->buf = newbuf;
a1e97d69
PN
611 r->len = sdslen(r->buf);
612 }
b66e5add 613
614 return REDIS_OK;
24f753a8
PN
615}
616
b66e5add 617int 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;
24f753a8
PN
625
626 /* When the buffer is empty, there will never be a reply. */
a1e97d69 627 if (r->len == 0)
24f753a8
PN
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;
24f753a8 634 r->rstack[0].idx = -1;
a1e97d69
PN
635 r->rstack[0].obj = NULL;
636 r->rstack[0].parent = NULL;
637 r->rstack[0].privdata = r->privdata;
24f753a8
PN
638 r->ridx = 0;
639 }
640
641 /* Process items in reply. */
642 while (r->ridx >= 0)
b66e5add 643 if (processItem(r) != REDIS_OK)
24f753a8
PN
644 break;
645
b66e5add 646 /* Return ASAP when an error occurred. */
647 if (r->err)
648 return REDIS_ERR;
649
9703b1b3
PN
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);
24f753a8 654 r->pos = 0;
a1e97d69 655 r->len = sdslen(r->buf);
24f753a8
PN
656 }
657
658 /* Emit a reply when there is one. */
659 if (r->ridx == -1) {
b66e5add 660 if (reply != NULL)
661 *reply = r->reply;
24f753a8 662 r->reply = NULL;
24f753a8
PN
663 }
664 return REDIS_OK;
665}
666
667/* Calculate the number of bytes needed to represent an integer as string. */
668static 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
b66e5add 681/* Helper that calculates the bulk length given a certain string length. */
682static size_t bulklen(size_t len) {
683 return 1+intlen(len)+2+len+2;
24f753a8
PN
684}
685
686int redisvFormatCommand(char **target, const char *format, va_list ap) {
b66e5add 687 const char *c = format;
24f753a8
PN
688 char *cmd = NULL; /* final command */
689 int pos; /* position in final command */
b66e5add 690 sds curarg, newarg; /* current argument */
9703b1b3 691 int touched = 0; /* was the current argument touched? */
b66e5add 692 char **curargv = NULL, **newargv = NULL;
693 int argc = 0;
24f753a8 694 int totlen = 0;
b66e5add 695 int j;
24f753a8
PN
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 */
b66e5add 702 curarg = sdsempty();
703 if (curarg == NULL)
704 return -1;
705
24f753a8
PN
706 while(*c != '\0') {
707 if (*c != '%' || c[1] == '\0') {
708 if (*c == ' ') {
9703b1b3 709 if (touched) {
b66e5add 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;
9703b1b3 719 touched = 0;
24f753a8
PN
720 }
721 } else {
b66e5add 722 newarg = sdscatlen(curarg,c,1);
723 if (newarg == NULL) goto err;
724 curarg = newarg;
9703b1b3 725 touched = 1;
24f753a8
PN
726 }
727 } else {
b66e5add 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
24f753a8
PN
734 switch(c[1]) {
735 case 's':
736 arg = va_arg(ap,char*);
a1e97d69
PN
737 size = strlen(arg);
738 if (size > 0)
b66e5add 739 newarg = sdscatlen(curarg,arg,size);
24f753a8
PN
740 break;
741 case 'b':
742 arg = va_arg(ap,char*);
743 size = va_arg(ap,size_t);
a1e97d69 744 if (size > 0)
b66e5add 745 newarg = sdscatlen(curarg,arg,size);
24f753a8
PN
746 break;
747 case '%':
b66e5add 748 newarg = sdscat(curarg,"%");
24f753a8 749 break;
a1e97d69
PN
750 default:
751 /* Try to detect printf format */
752 {
b66e5add 753 static const char intfmts[] = "diouxX";
a1e97d69
PN
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
b66e5add 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;
a1e97d69 796 }
b66e5add 797 goto fmt_invalid;
a1e97d69
PN
798 }
799
b66e5add 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;
a1e97d69 806 }
b66e5add 807 goto fmt_invalid;
a1e97d69
PN
808 }
809
b66e5add 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;
a1e97d69 848 }
24f753a8 849 }
b66e5add 850
851 if (newarg == NULL) goto err;
852 curarg = newarg;
853
9703b1b3 854 touched = 1;
24f753a8
PN
855 c++;
856 }
857 c++;
858 }
859
860 /* Add the last argument if needed */
9703b1b3 861 if (touched) {
b66e5add 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));
24f753a8 867 } else {
b66e5add 868 sdsfree(curarg);
24f753a8
PN
869 }
870
b66e5add 871 /* Clear curarg because it was put in curargv or was free'd. */
872 curarg = NULL;
873
24f753a8
PN
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);
b66e5add 879 if (cmd == NULL) goto err;
880
24f753a8
PN
881 pos = sprintf(cmd,"*%d\r\n",argc);
882 for (j = 0; j < argc; j++) {
b66e5add 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]);
24f753a8
PN
887 cmd[pos++] = '\r';
888 cmd[pos++] = '\n';
889 }
890 assert(pos == totlen);
b66e5add 891 cmd[pos] = '\0';
892
893 free(curargv);
24f753a8
PN
894 *target = cmd;
895 return totlen;
b66e5add 896
897err:
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;
24f753a8
PN
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. Examples:
921 *
922 * len = redisFormatCommand(target, "GET %s", mykey);
923 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
924 */
925int 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 */
939int 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]);
b66e5add 949 totlen += bulklen(len);
24f753a8
PN
950 }
951
952 /* Build the command at protocol level */
953 cmd = malloc(totlen+1);
b66e5add 954 if (cmd == NULL)
955 return -1;
956
24f753a8
PN
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);
b66e5add 967 cmd[pos] = '\0';
968
24f753a8
PN
969 *target = cmd;
970 return totlen;
971}
972
b66e5add 973void __redisSetError(redisContext *c, int type, const char *str) {
974 size_t len;
975
24f753a8 976 c->err = type;
b66e5add 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';
24f753a8
PN
982 } else {
983 /* Only REDIS_ERR_IO may lack a description! */
984 assert(type == REDIS_ERR_IO);
b66e5add 985 strerror_r(errno,c->errstr,sizeof(c->errstr));
24f753a8
PN
986 }
987}
988
9703b1b3 989static redisContext *redisContextInit(void) {
b66e5add 990 redisContext *c;
991
992 c = calloc(1,sizeof(redisContext));
993 if (c == NULL)
994 return NULL;
995
24f753a8 996 c->err = 0;
b66e5add 997 c->errstr[0] = '\0';
24f753a8 998 c->obuf = sdsempty();
b66e5add 999 c->reader = redisReaderCreate();
24f753a8
PN
1000 return c;
1001}
1002
1003void redisFree(redisContext *c) {
9703b1b3 1004 if (c->fd > 0)
24f753a8 1005 close(c->fd);
24f753a8
PN
1006 if (c->obuf != NULL)
1007 sdsfree(c->obuf);
1008 if (c->reader != NULL)
b66e5add 1009 redisReaderFree(c->reader);
24f753a8
PN
1010 free(c);
1011}
1012
1013/* Connect to a Redis instance. On error the field error in the returned
1014 * context will be set to the return value of the error function.
1015 * When no set of reply functions is given, the default set will be used. */
1016redisContext *redisConnect(const char *ip, int port) {
1017 redisContext *c = redisContextInit();
1018 c->flags |= REDIS_BLOCK;
9703b1b3
PN
1019 redisContextConnectTcp(c,ip,port,NULL);
1020 return c;
1021}
1022
1023redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv) {
1024 redisContext *c = redisContextInit();
1025 c->flags |= REDIS_BLOCK;
1026 redisContextConnectTcp(c,ip,port,&tv);
24f753a8
PN
1027 return c;
1028}
1029
1030redisContext *redisConnectNonBlock(const char *ip, int port) {
1031 redisContext *c = redisContextInit();
1032 c->flags &= ~REDIS_BLOCK;
9703b1b3 1033 redisContextConnectTcp(c,ip,port,NULL);
24f753a8
PN
1034 return c;
1035}
1036
1037redisContext *redisConnectUnix(const char *path) {
1038 redisContext *c = redisContextInit();
1039 c->flags |= REDIS_BLOCK;
9703b1b3
PN
1040 redisContextConnectUnix(c,path,NULL);
1041 return c;
1042}
1043
1044redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv) {
1045 redisContext *c = redisContextInit();
1046 c->flags |= REDIS_BLOCK;
1047 redisContextConnectUnix(c,path,&tv);
24f753a8
PN
1048 return c;
1049}
1050
1051redisContext *redisConnectUnixNonBlock(const char *path) {
1052 redisContext *c = redisContextInit();
1053 c->flags &= ~REDIS_BLOCK;
9703b1b3 1054 redisContextConnectUnix(c,path,NULL);
24f753a8
PN
1055 return c;
1056}
1057
9703b1b3
PN
1058/* Set read/write timeout on a blocking socket. */
1059int redisSetTimeout(redisContext *c, struct timeval tv) {
1060 if (c->flags & REDIS_BLOCK)
1061 return redisContextSetTimeout(c,tv);
1062 return REDIS_ERR;
1063}
1064
24f753a8
PN
1065/* Use this function to handle a read event on the descriptor. It will try
1066 * and read some bytes from the socket and feed them to the reply parser.
1067 *
1068 * After this function is called, you may use redisContextReadReply to
1069 * see if there is a reply available. */
1070int redisBufferRead(redisContext *c) {
8e65b6a3 1071 char buf[1024*16];
b66e5add 1072 int nread;
1073
1074 /* Return early when the context has seen an error. */
1075 if (c->err)
1076 return REDIS_ERR;
1077
1078 nread = read(c->fd,buf,sizeof(buf));
24f753a8 1079 if (nread == -1) {
9703b1b3 1080 if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
24f753a8
PN
1081 /* Try again later */
1082 } else {
1083 __redisSetError(c,REDIS_ERR_IO,NULL);
1084 return REDIS_ERR;
1085 }
1086 } else if (nread == 0) {
b66e5add 1087 __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
24f753a8
PN
1088 return REDIS_ERR;
1089 } else {
b66e5add 1090 if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
1091 __redisSetError(c,c->reader->err,c->reader->errstr);
1092 return REDIS_ERR;
1093 }
24f753a8
PN
1094 }
1095 return REDIS_OK;
1096}
1097
1098/* Write the output buffer to the socket.
1099 *
1100 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
1101 * succesfully written to the socket. When the buffer is empty after the
b66e5add 1102 * write operation, "done" is set to 1 (if given).
24f753a8
PN
1103 *
1104 * Returns REDIS_ERR if an error occured trying to write and sets
b66e5add 1105 * c->errstr to hold the appropriate error string.
24f753a8
PN
1106 */
1107int redisBufferWrite(redisContext *c, int *done) {
1108 int nwritten;
b66e5add 1109
1110 /* Return early when the context has seen an error. */
1111 if (c->err)
1112 return REDIS_ERR;
1113
24f753a8
PN
1114 if (sdslen(c->obuf) > 0) {
1115 nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
1116 if (nwritten == -1) {
9703b1b3 1117 if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
24f753a8
PN
1118 /* Try again later */
1119 } else {
1120 __redisSetError(c,REDIS_ERR_IO,NULL);
1121 return REDIS_ERR;
1122 }
1123 } else if (nwritten > 0) {
1124 if (nwritten == (signed)sdslen(c->obuf)) {
1125 sdsfree(c->obuf);
1126 c->obuf = sdsempty();
1127 } else {
1128 c->obuf = sdsrange(c->obuf,nwritten,-1);
1129 }
1130 }
1131 }
1132 if (done != NULL) *done = (sdslen(c->obuf) == 0);
1133 return REDIS_OK;
1134}
1135
1136/* Internal helper function to try and get a reply from the reader,
1137 * or set an error in the context otherwise. */
1138int redisGetReplyFromReader(redisContext *c, void **reply) {
b66e5add 1139 if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
1140 __redisSetError(c,c->reader->err,c->reader->errstr);
24f753a8
PN
1141 return REDIS_ERR;
1142 }
1143 return REDIS_OK;
1144}
1145
1146int redisGetReply(redisContext *c, void **reply) {
1147 int wdone = 0;
1148 void *aux = NULL;
1149
1150 /* Try to read pending replies */
1151 if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
1152 return REDIS_ERR;
1153
1154 /* For the blocking context, flush output buffer and read reply */
1155 if (aux == NULL && c->flags & REDIS_BLOCK) {
1156 /* Write until done */
1157 do {
1158 if (redisBufferWrite(c,&wdone) == REDIS_ERR)
1159 return REDIS_ERR;
1160 } while (!wdone);
1161
1162 /* Read until there is a reply */
1163 do {
1164 if (redisBufferRead(c) == REDIS_ERR)
1165 return REDIS_ERR;
1166 if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
1167 return REDIS_ERR;
1168 } while (aux == NULL);
1169 }
1170
1171 /* Set reply object */
1172 if (reply != NULL) *reply = aux;
1173 return REDIS_OK;
1174}
1175
1176
1177/* Helper function for the redisAppendCommand* family of functions.
1178 *
1179 * Write a formatted command to the output buffer. When this family
1180 * is used, you need to call redisGetReply yourself to retrieve
1181 * the reply (or replies in pub/sub).
1182 */
b66e5add 1183int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
1184 sds newbuf;
1185
1186 newbuf = sdscatlen(c->obuf,cmd,len);
1187 if (newbuf == NULL) {
1188 __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1189 return REDIS_ERR;
1190 }
1191
1192 c->obuf = newbuf;
1193 return REDIS_OK;
24f753a8
PN
1194}
1195
b66e5add 1196int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
24f753a8
PN
1197 char *cmd;
1198 int len;
b66e5add 1199
24f753a8 1200 len = redisvFormatCommand(&cmd,format,ap);
b66e5add 1201 if (len == -1) {
1202 __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1203 return REDIS_ERR;
1204 }
1205
1206 if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1207 free(cmd);
1208 return REDIS_ERR;
1209 }
1210
24f753a8 1211 free(cmd);
b66e5add 1212 return REDIS_OK;
24f753a8
PN
1213}
1214
b66e5add 1215int redisAppendCommand(redisContext *c, const char *format, ...) {
24f753a8 1216 va_list ap;
b66e5add 1217 int ret;
1218
24f753a8 1219 va_start(ap,format);
b66e5add 1220 ret = redisvAppendCommand(c,format,ap);
24f753a8 1221 va_end(ap);
b66e5add 1222 return ret;
24f753a8
PN
1223}
1224
b66e5add 1225int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
24f753a8
PN
1226 char *cmd;
1227 int len;
b66e5add 1228
24f753a8 1229 len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
b66e5add 1230 if (len == -1) {
1231 __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1232 return REDIS_ERR;
1233 }
1234
1235 if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1236 free(cmd);
1237 return REDIS_ERR;
1238 }
1239
24f753a8 1240 free(cmd);
b66e5add 1241 return REDIS_OK;
24f753a8
PN
1242}
1243
1244/* Helper function for the redisCommand* family of functions.
1245 *
1246 * Write a formatted command to the output buffer. If the given context is
1247 * blocking, immediately read the reply into the "reply" pointer. When the
1248 * context is non-blocking, the "reply" pointer will not be used and the
1249 * command is simply appended to the write buffer.
1250 *
1251 * Returns the reply when a reply was succesfully retrieved. Returns NULL
1252 * otherwise. When NULL is returned in a blocking context, the error field
1253 * in the context will be set.
1254 */
b66e5add 1255static void *__redisBlockForReply(redisContext *c) {
1256 void *reply;
24f753a8
PN
1257
1258 if (c->flags & REDIS_BLOCK) {
b66e5add 1259 if (redisGetReply(c,&reply) != REDIS_OK)
1260 return NULL;
1261 return reply;
24f753a8
PN
1262 }
1263 return NULL;
1264}
1265
1266void *redisvCommand(redisContext *c, const char *format, va_list ap) {
b66e5add 1267 if (redisvAppendCommand(c,format,ap) != REDIS_OK)
1268 return NULL;
1269 return __redisBlockForReply(c);
24f753a8
PN
1270}
1271
1272void *redisCommand(redisContext *c, const char *format, ...) {
1273 va_list ap;
1274 void *reply = NULL;
1275 va_start(ap,format);
1276 reply = redisvCommand(c,format,ap);
1277 va_end(ap);
1278 return reply;
1279}
1280
1281void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
b66e5add 1282 if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
1283 return NULL;
1284 return __redisBlockForReply(c);
24f753a8 1285}