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 > 2 */
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 if (r
->buf
== NULL
) {
576 void redisReaderFree(redisReader
*r
) {
577 if (r
->reply
!= NULL
&& r
->fn
&& r
->fn
->freeObject
)
578 r
->fn
->freeObject(r
->reply
);
584 int redisReaderFeed(redisReader
*r
, const char *buf
, size_t len
) {
587 /* Return early when this reader is in an erroneous state. */
591 /* Copy the provided buffer. */
592 if (buf
!= NULL
&& len
>= 1) {
594 /* Destroy internal buffer when it is empty and is quite large. */
595 if (r
->len
== 0 && sdsavail(r
->buf
) > 16*1024) {
600 /* r->buf should not be NULL since we just free'd a larger one. */
601 assert(r
->buf
!= NULL
);
605 newbuf
= sdscatlen(r
->buf
,buf
,len
);
606 if (newbuf
== NULL
) {
607 __redisReaderSetErrorOOM(r
);
612 r
->len
= sdslen(r
->buf
);
618 int redisReaderGetReply(redisReader
*r
, void **reply
) {
619 /* Default target pointer to NULL. */
623 /* Return early when this reader is in an erroneous state. */
627 /* When the buffer is empty, there will never be a reply. */
631 /* Set first item to process when the stack is empty. */
633 r
->rstack
[0].type
= -1;
634 r
->rstack
[0].elements
= -1;
635 r
->rstack
[0].idx
= -1;
636 r
->rstack
[0].obj
= NULL
;
637 r
->rstack
[0].parent
= NULL
;
638 r
->rstack
[0].privdata
= r
->privdata
;
642 /* Process items in reply. */
644 if (processItem(r
) != REDIS_OK
)
647 /* Return ASAP when an error occurred. */
651 /* Discard part of the buffer when we've consumed at least 1k, to avoid
652 * doing unnecessary calls to memmove() in sds.c. */
653 if (r
->pos
>= 1024) {
654 r
->buf
= sdsrange(r
->buf
,r
->pos
,-1);
656 r
->len
= sdslen(r
->buf
);
659 /* Emit a reply when there is one. */
668 /* Calculate the number of bytes needed to represent an integer as string. */
669 static int intlen(int i
) {
682 /* Helper that calculates the bulk length given a certain string length. */
683 static size_t bulklen(size_t len
) {
684 return 1+intlen(len
)+2+len
+2;
687 int redisvFormatCommand(char **target
, const char *format
, va_list ap
) {
688 const char *c
= format
;
689 char *cmd
= NULL
; /* final command */
690 int pos
; /* position in final command */
691 sds curarg
, newarg
; /* current argument */
692 int touched
= 0; /* was the current argument touched? */
693 char **curargv
= NULL
, **newargv
= NULL
;
698 /* Abort if there is not target to set */
702 /* Build the command string accordingly to protocol */
708 if (*c
!= '%' || c
[1] == '\0') {
711 newargv
= realloc(curargv
,sizeof(char*)*(argc
+1));
712 if (newargv
== NULL
) goto err
;
714 curargv
[argc
++] = curarg
;
715 totlen
+= bulklen(sdslen(curarg
));
717 /* curarg is put in argv so it can be overwritten. */
719 if (curarg
== NULL
) goto err
;
723 newarg
= sdscatlen(curarg
,c
,1);
724 if (newarg
== NULL
) goto err
;
732 /* Set newarg so it can be checked even if it is not touched. */
737 arg
= va_arg(ap
,char*);
740 newarg
= sdscatlen(curarg
,arg
,size
);
743 arg
= va_arg(ap
,char*);
744 size
= va_arg(ap
,size_t);
746 newarg
= sdscatlen(curarg
,arg
,size
);
749 newarg
= sdscat(curarg
,"%");
752 /* Try to detect printf format */
754 static const char intfmts
[] = "diouxX";
756 const char *_p
= c
+1;
761 if (*_p
!= '\0' && *_p
== '#') _p
++;
762 if (*_p
!= '\0' && *_p
== '0') _p
++;
763 if (*_p
!= '\0' && *_p
== '-') _p
++;
764 if (*_p
!= '\0' && *_p
== ' ') _p
++;
765 if (*_p
!= '\0' && *_p
== '+') _p
++;
768 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
773 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
776 /* Copy va_list before consuming with va_arg */
779 /* Integer conversion (without modifiers) */
780 if (strchr(intfmts
,*_p
) != NULL
) {
785 /* Double conversion (without modifiers) */
786 if (strchr("eEfFgGaA",*_p
) != NULL
) {
792 if (_p
[0] == 'h' && _p
[1] == 'h') {
794 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
795 va_arg(ap
,int); /* char gets promoted to int */
804 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
805 va_arg(ap
,int); /* short gets promoted to int */
811 /* Size: long long */
812 if (_p
[0] == 'l' && _p
[1] == 'l') {
814 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
815 va_arg(ap
,long long);
824 if (*_p
!= '\0' && strchr(intfmts
,*_p
) != NULL
) {
837 if (_l
< sizeof(_format
)-2) {
838 memcpy(_format
,c
,_l
);
840 newarg
= sdscatvprintf(curarg
,_format
,_cpy
);
842 /* Update current position (note: outer blocks
843 * increment c twice so compensate here) */
852 if (newarg
== NULL
) goto err
;
861 /* Add the last argument if needed */
863 newargv
= realloc(curargv
,sizeof(char*)*(argc
+1));
864 if (newargv
== NULL
) goto err
;
866 curargv
[argc
++] = curarg
;
867 totlen
+= bulklen(sdslen(curarg
));
872 /* Clear curarg because it was put in curargv or was free'd. */
875 /* Add bytes needed to hold multi bulk count */
876 totlen
+= 1+intlen(argc
)+2;
878 /* Build the command at protocol level */
879 cmd
= malloc(totlen
+1);
880 if (cmd
== NULL
) goto err
;
882 pos
= sprintf(cmd
,"*%d\r\n",argc
);
883 for (j
= 0; j
< argc
; j
++) {
884 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",sdslen(curargv
[j
]));
885 memcpy(cmd
+pos
,curargv
[j
],sdslen(curargv
[j
]));
886 pos
+= sdslen(curargv
[j
]);
891 assert(pos
== totlen
);
900 sdsfree(curargv
[argc
]);
906 /* No need to check cmd since it is the last statement that can fail,
907 * but do it anyway to be as defensive as possible. */
914 /* Format a command according to the Redis protocol. This function
915 * takes a format similar to printf:
917 * %s represents a C null terminated string you want to interpolate
918 * %b represents a binary safe string
920 * When using %b you need to provide both the pointer to the string
921 * and the length in bytes. Examples:
923 * len = redisFormatCommand(target, "GET %s", mykey);
924 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
926 int redisFormatCommand(char **target
, const char *format
, ...) {
930 len
= redisvFormatCommand(target
,format
,ap
);
935 /* Format a command according to the Redis protocol. This function takes the
936 * number of arguments, an array with arguments and an array with their
937 * lengths. If the latter is set to NULL, strlen will be used to compute the
940 int redisFormatCommandArgv(char **target
, int argc
, const char **argv
, const size_t *argvlen
) {
941 char *cmd
= NULL
; /* final command */
942 int pos
; /* position in final command */
946 /* Calculate number of bytes needed for the command */
947 totlen
= 1+intlen(argc
)+2;
948 for (j
= 0; j
< argc
; j
++) {
949 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
950 totlen
+= bulklen(len
);
953 /* Build the command at protocol level */
954 cmd
= malloc(totlen
+1);
958 pos
= sprintf(cmd
,"*%d\r\n",argc
);
959 for (j
= 0; j
< argc
; j
++) {
960 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
961 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",len
);
962 memcpy(cmd
+pos
,argv
[j
],len
);
967 assert(pos
== totlen
);
974 void __redisSetError(redisContext
*c
, int type
, const char *str
) {
980 len
= len
< (sizeof(c
->errstr
)-1) ? len
: (sizeof(c
->errstr
)-1);
981 memcpy(c
->errstr
,str
,len
);
982 c
->errstr
[len
] = '\0';
984 /* Only REDIS_ERR_IO may lack a description! */
985 assert(type
== REDIS_ERR_IO
);
986 strerror_r(errno
,c
->errstr
,sizeof(c
->errstr
));
990 static redisContext
*redisContextInit(void) {
993 c
= calloc(1,sizeof(redisContext
));
999 c
->obuf
= sdsempty();
1000 c
->reader
= redisReaderCreate();
1004 void redisFree(redisContext
*c
) {
1007 if (c
->obuf
!= NULL
)
1009 if (c
->reader
!= NULL
)
1010 redisReaderFree(c
->reader
);
1014 /* Connect to a Redis instance. On error the field error in the returned
1015 * context will be set to the return value of the error function.
1016 * When no set of reply functions is given, the default set will be used. */
1017 redisContext
*redisConnect(const char *ip
, int port
) {
1018 redisContext
*c
= redisContextInit();
1019 c
->flags
|= REDIS_BLOCK
;
1020 redisContextConnectTcp(c
,ip
,port
,NULL
);
1024 redisContext
*redisConnectWithTimeout(const char *ip
, int port
, struct timeval tv
) {
1025 redisContext
*c
= redisContextInit();
1026 c
->flags
|= REDIS_BLOCK
;
1027 redisContextConnectTcp(c
,ip
,port
,&tv
);
1031 redisContext
*redisConnectNonBlock(const char *ip
, int port
) {
1032 redisContext
*c
= redisContextInit();
1033 c
->flags
&= ~REDIS_BLOCK
;
1034 redisContextConnectTcp(c
,ip
,port
,NULL
);
1038 redisContext
*redisConnectUnix(const char *path
) {
1039 redisContext
*c
= redisContextInit();
1040 c
->flags
|= REDIS_BLOCK
;
1041 redisContextConnectUnix(c
,path
,NULL
);
1045 redisContext
*redisConnectUnixWithTimeout(const char *path
, struct timeval tv
) {
1046 redisContext
*c
= redisContextInit();
1047 c
->flags
|= REDIS_BLOCK
;
1048 redisContextConnectUnix(c
,path
,&tv
);
1052 redisContext
*redisConnectUnixNonBlock(const char *path
) {
1053 redisContext
*c
= redisContextInit();
1054 c
->flags
&= ~REDIS_BLOCK
;
1055 redisContextConnectUnix(c
,path
,NULL
);
1059 /* Set read/write timeout on a blocking socket. */
1060 int redisSetTimeout(redisContext
*c
, struct timeval tv
) {
1061 if (c
->flags
& REDIS_BLOCK
)
1062 return redisContextSetTimeout(c
,tv
);
1066 /* Use this function to handle a read event on the descriptor. It will try
1067 * and read some bytes from the socket and feed them to the reply parser.
1069 * After this function is called, you may use redisContextReadReply to
1070 * see if there is a reply available. */
1071 int redisBufferRead(redisContext
*c
) {
1075 /* Return early when the context has seen an error. */
1079 nread
= read(c
->fd
,buf
,sizeof(buf
));
1081 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
1082 /* Try again later */
1084 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
1087 } else if (nread
== 0) {
1088 __redisSetError(c
,REDIS_ERR_EOF
,"Server closed the connection");
1091 if (redisReaderFeed(c
->reader
,buf
,nread
) != REDIS_OK
) {
1092 __redisSetError(c
,c
->reader
->err
,c
->reader
->errstr
);
1099 /* Write the output buffer to the socket.
1101 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
1102 * succesfully written to the socket. When the buffer is empty after the
1103 * write operation, "done" is set to 1 (if given).
1105 * Returns REDIS_ERR if an error occured trying to write and sets
1106 * c->errstr to hold the appropriate error string.
1108 int redisBufferWrite(redisContext
*c
, int *done
) {
1111 /* Return early when the context has seen an error. */
1115 if (sdslen(c
->obuf
) > 0) {
1116 nwritten
= write(c
->fd
,c
->obuf
,sdslen(c
->obuf
));
1117 if (nwritten
== -1) {
1118 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
1119 /* Try again later */
1121 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
1124 } else if (nwritten
> 0) {
1125 if (nwritten
== (signed)sdslen(c
->obuf
)) {
1127 c
->obuf
= sdsempty();
1129 c
->obuf
= sdsrange(c
->obuf
,nwritten
,-1);
1133 if (done
!= NULL
) *done
= (sdslen(c
->obuf
) == 0);
1137 /* Internal helper function to try and get a reply from the reader,
1138 * or set an error in the context otherwise. */
1139 int redisGetReplyFromReader(redisContext
*c
, void **reply
) {
1140 if (redisReaderGetReply(c
->reader
,reply
) == REDIS_ERR
) {
1141 __redisSetError(c
,c
->reader
->err
,c
->reader
->errstr
);
1147 int redisGetReply(redisContext
*c
, void **reply
) {
1151 /* Try to read pending replies */
1152 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
1155 /* For the blocking context, flush output buffer and read reply */
1156 if (aux
== NULL
&& c
->flags
& REDIS_BLOCK
) {
1157 /* Write until done */
1159 if (redisBufferWrite(c
,&wdone
) == REDIS_ERR
)
1163 /* Read until there is a reply */
1165 if (redisBufferRead(c
) == REDIS_ERR
)
1167 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
1169 } while (aux
== NULL
);
1172 /* Set reply object */
1173 if (reply
!= NULL
) *reply
= aux
;
1178 /* Helper function for the redisAppendCommand* family of functions.
1180 * Write a formatted command to the output buffer. When this family
1181 * is used, you need to call redisGetReply yourself to retrieve
1182 * the reply (or replies in pub/sub).
1184 int __redisAppendCommand(redisContext
*c
, char *cmd
, size_t len
) {
1187 newbuf
= sdscatlen(c
->obuf
,cmd
,len
);
1188 if (newbuf
== NULL
) {
1189 __redisSetError(c
,REDIS_ERR_OOM
,"Out of memory");
1197 int redisvAppendCommand(redisContext
*c
, const char *format
, va_list ap
) {
1201 len
= redisvFormatCommand(&cmd
,format
,ap
);
1203 __redisSetError(c
,REDIS_ERR_OOM
,"Out of memory");
1207 if (__redisAppendCommand(c
,cmd
,len
) != REDIS_OK
) {
1216 int redisAppendCommand(redisContext
*c
, const char *format
, ...) {
1220 va_start(ap
,format
);
1221 ret
= redisvAppendCommand(c
,format
,ap
);
1226 int redisAppendCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1230 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1232 __redisSetError(c
,REDIS_ERR_OOM
,"Out of memory");
1236 if (__redisAppendCommand(c
,cmd
,len
) != REDIS_OK
) {
1245 /* Helper function for the redisCommand* family of functions.
1247 * Write a formatted command to the output buffer. If the given context is
1248 * blocking, immediately read the reply into the "reply" pointer. When the
1249 * context is non-blocking, the "reply" pointer will not be used and the
1250 * command is simply appended to the write buffer.
1252 * Returns the reply when a reply was succesfully retrieved. Returns NULL
1253 * otherwise. When NULL is returned in a blocking context, the error field
1254 * in the context will be set.
1256 static void *__redisBlockForReply(redisContext
*c
) {
1259 if (c
->flags
& REDIS_BLOCK
) {
1260 if (redisGetReply(c
,&reply
) != REDIS_OK
)
1267 void *redisvCommand(redisContext
*c
, const char *format
, va_list ap
) {
1268 if (redisvAppendCommand(c
,format
,ap
) != REDIS_OK
)
1270 return __redisBlockForReply(c
);
1273 void *redisCommand(redisContext
*c
, const char *format
, ...) {
1276 va_start(ap
,format
);
1277 reply
= redisvCommand(c
,format
,ap
);
1282 void *redisCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1283 if (redisAppendCommandArgv(c
,argc
,argv
,argvlen
) != REDIS_OK
)
1285 return __redisBlockForReply(c
);