2 * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3 * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
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.
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.
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
);
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
= {
60 /* Create a reply object */
61 static redisReply
*createReplyObject(int type
) {
62 redisReply
*r
= calloc(1,sizeof(*r
));
71 /* Free a reply object */
72 void freeReplyObject(void *reply
) {
73 redisReply
*r
= reply
;
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
]);
87 case REDIS_REPLY_ERROR
:
88 case REDIS_REPLY_STATUS
:
89 case REDIS_REPLY_STRING
:
97 static void *createStringObject(const redisReadTask
*task
, char *str
, size_t len
) {
98 redisReply
*r
, *parent
;
101 r
= createReplyObject(task
->type
);
111 assert(task
->type
== REDIS_REPLY_ERROR
||
112 task
->type
== REDIS_REPLY_STATUS
||
113 task
->type
== REDIS_REPLY_STRING
);
115 /* Copy string value */
122 parent
= task
->parent
->obj
;
123 assert(parent
->type
== REDIS_REPLY_ARRAY
);
124 parent
->element
[task
->idx
] = r
;
129 static void *createArrayObject(const redisReadTask
*task
, int elements
) {
130 redisReply
*r
, *parent
;
132 r
= createReplyObject(REDIS_REPLY_ARRAY
);
137 r
->element
= calloc(elements
,sizeof(redisReply
*));
138 if (r
->element
== NULL
) {
144 r
->elements
= elements
;
147 parent
= task
->parent
->obj
;
148 assert(parent
->type
== REDIS_REPLY_ARRAY
);
149 parent
->element
[task
->idx
] = r
;
154 static void *createIntegerObject(const redisReadTask
*task
, long long value
) {
155 redisReply
*r
, *parent
;
157 r
= createReplyObject(REDIS_REPLY_INTEGER
);
164 parent
= task
->parent
->obj
;
165 assert(parent
->type
== REDIS_REPLY_ARRAY
);
166 parent
->element
[task
->idx
] = r
;
171 static void *createNilObject(const redisReadTask
*task
) {
172 redisReply
*r
, *parent
;
174 r
= createReplyObject(REDIS_REPLY_NIL
);
179 parent
= task
->parent
->obj
;
180 assert(parent
->type
== REDIS_REPLY_ARRAY
);
181 parent
->element
[task
->idx
] = r
;
186 static void __redisReaderSetError(redisReader
*r
, int type
, const char *str
) {
189 if (r
->reply
!= NULL
&& r
->fn
&& r
->fn
->freeObject
) {
190 r
->fn
->freeObject(r
->reply
);
194 /* Clear input buffer on errors. */
195 if (r
->buf
!= NULL
) {
201 /* Reset task stack. */
207 len
= len
< (sizeof(r
->errstr
)-1) ? len
: (sizeof(r
->errstr
)-1);
208 memcpy(r
->errstr
,str
,len
);
209 r
->errstr
[len
] = '\0';
212 static size_t chrtos(char *buf
, size_t size
, char byte
) {
218 len
= snprintf(buf
,size
,"\"\\%c\"",byte
);
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;
227 len
= snprintf(buf
,size
,"\"%c\"",byte
);
229 len
= snprintf(buf
,size
,"\"\\x%02x\"",(unsigned char)byte
);
236 static void __redisReaderSetErrorProtocolByte(redisReader
*r
, char byte
) {
237 char cbuf
[8], sbuf
[128];
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
);
245 static void __redisReaderSetErrorOOM(redisReader
*r
) {
246 __redisReaderSetError(r
,REDIS_ERR_OOM
,"Out of memory");
249 static char *readBytes(redisReader
*r
, unsigned int bytes
) {
251 if (r
->len
-r
->pos
>= bytes
) {
259 /* Find pointer to \r\n. */
260 static char *seekNewline(char *s
, size_t len
) {
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. */
269 while(pos
< _len
&& s
[pos
] != '\r') pos
++;
270 if (s
[pos
] != '\r') {
274 if (s
[pos
+1] == '\n') {
278 /* Continue searching. */
286 /* Read a long long value starting at *s, under the assumption that it will be
287 * terminated by \r\n. Ambiguously returns -1 for unexpected input. */
288 static long long readLongLong(char *s
) {
296 } else if (*s
== '+') {
301 while ((c
= *(s
++)) != '\r') {
303 if (dec
>= 0 && dec
< 10) {
307 /* Should not happen... */
315 static char *readLine(redisReader
*r
, int *_len
) {
320 s
= seekNewline(p
,(r
->len
-r
->pos
));
322 len
= s
-(r
->buf
+r
->pos
);
323 r
->pos
+= len
+2; /* skip \r\n */
324 if (_len
) *_len
= len
;
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. */
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) {
345 /* Reset the type because the next item can be anything */
346 assert(cur
->idx
< prv
->elements
);
355 static int processLineItem(redisReader
*r
) {
356 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
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
));
366 obj
= (void*)REDIS_REPLY_INTEGER
;
368 /* Type will be error or status. */
369 if (r
->fn
&& r
->fn
->createString
)
370 obj
= r
->fn
->createString(cur
,p
,len
);
372 obj
= (void*)(size_t)(cur
->type
);
376 __redisReaderSetErrorOOM(r
);
380 /* Set reply if this is the root object. */
381 if (r
->ridx
== 0) r
->reply
= obj
;
389 static int processBulkItem(redisReader
*r
) {
390 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
394 unsigned long bytelen
;
398 s
= seekNewline(p
,r
->len
-r
->pos
);
401 bytelen
= s
-(r
->buf
+r
->pos
)+2; /* include \r\n */
402 len
= readLongLong(p
);
405 /* The nil object can always be created. */
406 if (r
->fn
&& r
->fn
->createNil
)
407 obj
= r
->fn
->createNil(cur
);
409 obj
= (void*)REDIS_REPLY_NIL
;
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
);
418 obj
= (void*)REDIS_REPLY_STRING
;
423 /* Proceed when obj was created. */
426 __redisReaderSetErrorOOM(r
);
432 /* Set reply if this is the root object. */
433 if (r
->ridx
== 0) r
->reply
= obj
;
442 static int processMultiBulkItem(redisReader
*r
) {
443 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
449 /* Set error for nested multi bulks with depth > 7 */
451 __redisReaderSetError(r
,REDIS_ERR_PROTOCOL
,
452 "No support for nested multi bulk replies with depth > 7");
456 if ((p
= readLine(r
,NULL
)) != NULL
) {
457 elements
= readLongLong(p
);
458 root
= (r
->ridx
== 0);
460 if (elements
== -1) {
461 if (r
->fn
&& r
->fn
->createNil
)
462 obj
= r
->fn
->createNil(cur
);
464 obj
= (void*)REDIS_REPLY_NIL
;
467 __redisReaderSetErrorOOM(r
);
473 if (r
->fn
&& r
->fn
->createArray
)
474 obj
= r
->fn
->createArray(cur
,elements
);
476 obj
= (void*)REDIS_REPLY_ARRAY
;
479 __redisReaderSetErrorOOM(r
);
483 /* Modify task stack when there are more than 0 elements. */
485 cur
->elements
= elements
;
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
;
499 /* Set reply if this is the root object. */
500 if (root
) r
->reply
= obj
;
507 static int processItem(redisReader
*r
) {
508 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
511 /* check if we need to read type */
513 if ((p
= readBytes(r
,1)) != NULL
) {
516 cur
->type
= REDIS_REPLY_ERROR
;
519 cur
->type
= REDIS_REPLY_STATUS
;
522 cur
->type
= REDIS_REPLY_INTEGER
;
525 cur
->type
= REDIS_REPLY_STRING
;
528 cur
->type
= REDIS_REPLY_ARRAY
;
531 __redisReaderSetErrorProtocolByte(r
,*p
);
535 /* could not consume 1 byte */
540 /* process typed item */
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
);
552 return REDIS_ERR
; /* Avoid warning. */
556 redisReader
*redisReaderCreate(void) {
559 r
= calloc(sizeof(redisReader
),1);
565 r
->fn
= &defaultFunctions
;
567 r
->maxbuf
= REDIS_READER_MAX_BUF
;
568 if (r
->buf
== NULL
) {
577 void redisReaderFree(redisReader
*r
) {
578 if (r
->reply
!= NULL
&& r
->fn
&& r
->fn
->freeObject
)
579 r
->fn
->freeObject(r
->reply
);
585 int redisReaderFeed(redisReader
*r
, const char *buf
, size_t len
) {
588 /* Return early when this reader is in an erroneous state. */
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
) {
600 /* r->buf should not be NULL since we just free'd a larger one. */
601 assert(r
->buf
!= NULL
);
604 newbuf
= sdscatlen(r
->buf
,buf
,len
);
605 if (newbuf
== NULL
) {
606 __redisReaderSetErrorOOM(r
);
611 r
->len
= sdslen(r
->buf
);
617 int redisReaderGetReply(redisReader
*r
, void **reply
) {
618 /* Default target pointer to NULL. */
622 /* Return early when this reader is in an erroneous state. */
626 /* When the buffer is empty, there will never be a reply. */
630 /* Set first item to process when the stack is empty. */
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
;
641 /* Process items in reply. */
643 if (processItem(r
) != REDIS_OK
)
646 /* Return ASAP when an error occurred. */
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);
655 r
->len
= sdslen(r
->buf
);
658 /* Emit a reply when there is one. */
667 /* Calculate the number of bytes needed to represent an integer as string. */
668 static int intlen(int i
) {
681 /* Helper that calculates the bulk length given a certain string length. */
682 static size_t bulklen(size_t len
) {
683 return 1+intlen(len
)+2+len
+2;
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
;
697 /* Abort if there is not target to set */
701 /* Build the command string accordingly to protocol */
707 if (*c
!= '%' || c
[1] == '\0') {
710 newargv
= realloc(curargv
,sizeof(char*)*(argc
+1));
711 if (newargv
== NULL
) goto err
;
713 curargv
[argc
++] = curarg
;
714 totlen
+= bulklen(sdslen(curarg
));
716 /* curarg is put in argv so it can be overwritten. */
718 if (curarg
== NULL
) goto err
;
722 newarg
= sdscatlen(curarg
,c
,1);
723 if (newarg
== NULL
) goto err
;
731 /* Set newarg so it can be checked even if it is not touched. */
736 arg
= va_arg(ap
,char*);
739 newarg
= sdscatlen(curarg
,arg
,size
);
742 arg
= va_arg(ap
,char*);
743 size
= va_arg(ap
,size_t);
745 newarg
= sdscatlen(curarg
,arg
,size
);
748 newarg
= sdscat(curarg
,"%");
751 /* Try to detect printf format */
753 static const char intfmts
[] = "diouxX";
755 const char *_p
= c
+1;
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
++;
767 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
772 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
775 /* Copy va_list before consuming with va_arg */
778 /* Integer conversion (without modifiers) */
779 if (strchr(intfmts
,*_p
) != NULL
) {
784 /* Double conversion (without modifiers) */
785 if (strchr("eEfFgGaA",*_p
) != NULL
) {
791 if (_p
[0] == 'h' && _p
[1] == 'h') {
793 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
794 va_arg(ap
,int); /* char gets promoted to int */
803 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
804 va_arg(ap
,int); /* short gets promoted to int */
810 /* Size: long long */
811 if (_p
[0] == 'l' && _p
[1] == 'l') {
813 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
814 va_arg(ap
,long long);
823 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
836 if (_l
< sizeof(_format
)-2) {
837 memcpy(_format
,c
,_l
);
839 newarg
= sdscatvprintf(curarg
,_format
,_cpy
);
841 /* Update current position (note: outer blocks
842 * increment c twice so compensate here) */
851 if (newarg
== NULL
) goto err
;
860 /* Add the last argument if needed */
862 newargv
= realloc(curargv
,sizeof(char*)*(argc
+1));
863 if (newargv
== NULL
) goto err
;
865 curargv
[argc
++] = curarg
;
866 totlen
+= bulklen(sdslen(curarg
));
871 /* Clear curarg because it was put in curargv or was free'd. */
874 /* Add bytes needed to hold multi bulk count */
875 totlen
+= 1+intlen(argc
)+2;
877 /* Build the command at protocol level */
878 cmd
= malloc(totlen
+1);
879 if (cmd
== NULL
) goto err
;
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
]);
890 assert(pos
== totlen
);
899 sdsfree(curargv
[argc
]);
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. */
913 /* Format a command according to the Redis protocol. This function
914 * takes a format similar to printf:
916 * %s represents a C null terminated string you want to interpolate
917 * %b represents a binary safe string
919 * When using %b you need to provide both the pointer to the string
920 * and the length in bytes. Examples:
922 * len = redisFormatCommand(target, "GET %s", mykey);
923 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
925 int redisFormatCommand(char **target
, const char *format
, ...) {
929 len
= redisvFormatCommand(target
,format
,ap
);
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
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 */
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
);
952 /* Build the command at protocol level */
953 cmd
= malloc(totlen
+1);
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
);
966 assert(pos
== totlen
);
973 void __redisSetError(redisContext
*c
, int type
, const char *str
) {
979 len
= len
< (sizeof(c
->errstr
)-1) ? len
: (sizeof(c
->errstr
)-1);
980 memcpy(c
->errstr
,str
,len
);
981 c
->errstr
[len
] = '\0';
983 /* Only REDIS_ERR_IO may lack a description! */
984 assert(type
== REDIS_ERR_IO
);
985 strerror_r(errno
,c
->errstr
,sizeof(c
->errstr
));
989 static redisContext
*redisContextInit(void) {
992 c
= calloc(1,sizeof(redisContext
));
998 c
->obuf
= sdsempty();
999 c
->reader
= redisReaderCreate();
1003 void redisFree(redisContext
*c
) {
1006 if (c
->obuf
!= NULL
)
1008 if (c
->reader
!= NULL
)
1009 redisReaderFree(c
->reader
);
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. */
1016 redisContext
*redisConnect(const char *ip
, int port
) {
1017 redisContext
*c
= redisContextInit();
1018 c
->flags
|= REDIS_BLOCK
;
1019 redisContextConnectTcp(c
,ip
,port
,NULL
);
1023 redisContext
*redisConnectWithTimeout(const char *ip
, int port
, struct timeval tv
) {
1024 redisContext
*c
= redisContextInit();
1025 c
->flags
|= REDIS_BLOCK
;
1026 redisContextConnectTcp(c
,ip
,port
,&tv
);
1030 redisContext
*redisConnectNonBlock(const char *ip
, int port
) {
1031 redisContext
*c
= redisContextInit();
1032 c
->flags
&= ~REDIS_BLOCK
;
1033 redisContextConnectTcp(c
,ip
,port
,NULL
);
1037 redisContext
*redisConnectUnix(const char *path
) {
1038 redisContext
*c
= redisContextInit();
1039 c
->flags
|= REDIS_BLOCK
;
1040 redisContextConnectUnix(c
,path
,NULL
);
1044 redisContext
*redisConnectUnixWithTimeout(const char *path
, struct timeval tv
) {
1045 redisContext
*c
= redisContextInit();
1046 c
->flags
|= REDIS_BLOCK
;
1047 redisContextConnectUnix(c
,path
,&tv
);
1051 redisContext
*redisConnectUnixNonBlock(const char *path
) {
1052 redisContext
*c
= redisContextInit();
1053 c
->flags
&= ~REDIS_BLOCK
;
1054 redisContextConnectUnix(c
,path
,NULL
);
1058 /* Set read/write timeout on a blocking socket. */
1059 int redisSetTimeout(redisContext
*c
, struct timeval tv
) {
1060 if (c
->flags
& REDIS_BLOCK
)
1061 return redisContextSetTimeout(c
,tv
);
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.
1068 * After this function is called, you may use redisContextReadReply to
1069 * see if there is a reply available. */
1070 int redisBufferRead(redisContext
*c
) {
1074 /* Return early when the context has seen an error. */
1078 nread
= read(c
->fd
,buf
,sizeof(buf
));
1080 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
1081 /* Try again later */
1083 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
1086 } else if (nread
== 0) {
1087 __redisSetError(c
,REDIS_ERR_EOF
,"Server closed the connection");
1090 if (redisReaderFeed(c
->reader
,buf
,nread
) != REDIS_OK
) {
1091 __redisSetError(c
,c
->reader
->err
,c
->reader
->errstr
);
1098 /* Write the output buffer to the socket.
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
1102 * write operation, "done" is set to 1 (if given).
1104 * Returns REDIS_ERR if an error occured trying to write and sets
1105 * c->errstr to hold the appropriate error string.
1107 int redisBufferWrite(redisContext
*c
, int *done
) {
1110 /* Return early when the context has seen an error. */
1114 if (sdslen(c
->obuf
) > 0) {
1115 nwritten
= write(c
->fd
,c
->obuf
,sdslen(c
->obuf
));
1116 if (nwritten
== -1) {
1117 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
1118 /* Try again later */
1120 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
1123 } else if (nwritten
> 0) {
1124 if (nwritten
== (signed)sdslen(c
->obuf
)) {
1126 c
->obuf
= sdsempty();
1128 c
->obuf
= sdsrange(c
->obuf
,nwritten
,-1);
1132 if (done
!= NULL
) *done
= (sdslen(c
->obuf
) == 0);
1136 /* Internal helper function to try and get a reply from the reader,
1137 * or set an error in the context otherwise. */
1138 int redisGetReplyFromReader(redisContext
*c
, void **reply
) {
1139 if (redisReaderGetReply(c
->reader
,reply
) == REDIS_ERR
) {
1140 __redisSetError(c
,c
->reader
->err
,c
->reader
->errstr
);
1146 int redisGetReply(redisContext
*c
, void **reply
) {
1150 /* Try to read pending replies */
1151 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
1154 /* For the blocking context, flush output buffer and read reply */
1155 if (aux
== NULL
&& c
->flags
& REDIS_BLOCK
) {
1156 /* Write until done */
1158 if (redisBufferWrite(c
,&wdone
) == REDIS_ERR
)
1162 /* Read until there is a reply */
1164 if (redisBufferRead(c
) == REDIS_ERR
)
1166 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
1168 } while (aux
== NULL
);
1171 /* Set reply object */
1172 if (reply
!= NULL
) *reply
= aux
;
1177 /* Helper function for the redisAppendCommand* family of functions.
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).
1183 int __redisAppendCommand(redisContext
*c
, char *cmd
, size_t len
) {
1186 newbuf
= sdscatlen(c
->obuf
,cmd
,len
);
1187 if (newbuf
== NULL
) {
1188 __redisSetError(c
,REDIS_ERR_OOM
,"Out of memory");
1196 int redisvAppendCommand(redisContext
*c
, const char *format
, va_list ap
) {
1200 len
= redisvFormatCommand(&cmd
,format
,ap
);
1202 __redisSetError(c
,REDIS_ERR_OOM
,"Out of memory");
1206 if (__redisAppendCommand(c
,cmd
,len
) != REDIS_OK
) {
1215 int redisAppendCommand(redisContext
*c
, const char *format
, ...) {
1219 va_start(ap
,format
);
1220 ret
= redisvAppendCommand(c
,format
,ap
);
1225 int redisAppendCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1229 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1231 __redisSetError(c
,REDIS_ERR_OOM
,"Out of memory");
1235 if (__redisAppendCommand(c
,cmd
,len
) != REDIS_OK
) {
1244 /* Helper function for the redisCommand* family of functions.
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.
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.
1255 static void *__redisBlockForReply(redisContext
*c
) {
1258 if (c
->flags
& REDIS_BLOCK
) {
1259 if (redisGetReply(c
,&reply
) != REDIS_OK
)
1266 void *redisvCommand(redisContext
*c
, const char *format
, va_list ap
) {
1267 if (redisvAppendCommand(c
,format
,ap
) != REDIS_OK
)
1269 return __redisBlockForReply(c
);
1272 void *redisCommand(redisContext
*c
, const char *format
, ...) {
1275 va_start(ap
,format
);
1276 reply
= redisvCommand(c
,format
,ap
);
1281 void *redisCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1282 if (redisAppendCommandArgv(c
,argc
,argv
,argvlen
) != REDIS_OK
)
1284 return __redisBlockForReply(c
);