2 * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
3 * Copyright (c) 2010, 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 typedef struct redisReader
{
45 struct redisReplyObjectFunctions
*fn
;
46 sds error
; /* holds optional error */
47 void *reply
; /* holds temporary reply */
49 sds buf
; /* read buffer */
50 size_t pos
; /* buffer cursor */
51 size_t len
; /* buffer length */
53 redisReadTask rstack
[9]; /* stack of read tasks */
54 int ridx
; /* index of stack */
55 void *privdata
; /* user-settable arbitrary field */
58 static redisReply
*createReplyObject(int type
);
59 static void *createStringObject(const redisReadTask
*task
, char *str
, size_t len
);
60 static void *createArrayObject(const redisReadTask
*task
, int elements
);
61 static void *createIntegerObject(const redisReadTask
*task
, long long value
);
62 static void *createNilObject(const redisReadTask
*task
);
63 static void redisSetReplyReaderError(redisReader
*r
, sds err
);
65 /* Default set of functions to build the reply. */
66 static redisReplyObjectFunctions defaultFunctions
= {
74 /* Create a reply object */
75 static redisReply
*createReplyObject(int type
) {
76 redisReply
*r
= malloc(sizeof(*r
));
83 /* Free a reply object */
84 void freeReplyObject(void *reply
) {
85 redisReply
*r
= reply
;
89 case REDIS_REPLY_INTEGER
:
90 break; /* Nothing to free */
91 case REDIS_REPLY_ARRAY
:
92 for (j
= 0; j
< r
->elements
; j
++)
93 if (r
->element
[j
]) freeReplyObject(r
->element
[j
]);
96 case REDIS_REPLY_ERROR
:
97 case REDIS_REPLY_STATUS
:
98 case REDIS_REPLY_STRING
:
105 static void *createStringObject(const redisReadTask
*task
, char *str
, size_t len
) {
106 redisReply
*r
= createReplyObject(task
->type
);
107 char *value
= malloc(len
+1);
108 if (!value
) redisOOM();
109 assert(task
->type
== REDIS_REPLY_ERROR
||
110 task
->type
== REDIS_REPLY_STATUS
||
111 task
->type
== REDIS_REPLY_STRING
);
113 /* Copy string value */
114 memcpy(value
,str
,len
);
120 redisReply
*parent
= task
->parent
->obj
;
121 assert(parent
->type
== REDIS_REPLY_ARRAY
);
122 parent
->element
[task
->idx
] = r
;
127 static void *createArrayObject(const redisReadTask
*task
, int elements
) {
128 redisReply
*r
= createReplyObject(REDIS_REPLY_ARRAY
);
129 r
->elements
= elements
;
130 if ((r
->element
= calloc(sizeof(redisReply
*),elements
)) == NULL
)
133 redisReply
*parent
= task
->parent
->obj
;
134 assert(parent
->type
== REDIS_REPLY_ARRAY
);
135 parent
->element
[task
->idx
] = r
;
140 static void *createIntegerObject(const redisReadTask
*task
, long long value
) {
141 redisReply
*r
= createReplyObject(REDIS_REPLY_INTEGER
);
144 redisReply
*parent
= task
->parent
->obj
;
145 assert(parent
->type
== REDIS_REPLY_ARRAY
);
146 parent
->element
[task
->idx
] = r
;
151 static void *createNilObject(const redisReadTask
*task
) {
152 redisReply
*r
= createReplyObject(REDIS_REPLY_NIL
);
154 redisReply
*parent
= task
->parent
->obj
;
155 assert(parent
->type
== REDIS_REPLY_ARRAY
);
156 parent
->element
[task
->idx
] = r
;
161 static char *readBytes(redisReader
*r
, unsigned int bytes
) {
163 if (r
->len
-r
->pos
>= bytes
) {
171 /* Find pointer to \r\n. */
172 static char *seekNewline(char *s
, size_t len
) {
176 /* Position should be < len-1 because the character at "pos" should be
177 * followed by a \n. Note that strchr cannot be used because it doesn't
178 * allow to search a limited length and the buffer that is being searched
179 * might not have a trailing NULL character. */
181 while(pos
< _len
&& s
[pos
] != '\r') pos
++;
182 if (s
[pos
] != '\r') {
186 if (s
[pos
+1] == '\n') {
190 /* Continue searching. */
198 /* Read a long long value starting at *s, under the assumption that it will be
199 * terminated by \r\n. Ambiguously returns -1 for unexpected input. */
200 static long long readLongLong(char *s
) {
208 } else if (*s
== '+') {
213 while ((c
= *(s
++)) != '\r') {
215 if (dec
>= 0 && dec
< 10) {
219 /* Should not happen... */
227 static char *readLine(redisReader
*r
, int *_len
) {
232 s
= seekNewline(p
,(r
->len
-r
->pos
));
234 len
= s
-(r
->buf
+r
->pos
);
235 r
->pos
+= len
+2; /* skip \r\n */
236 if (_len
) *_len
= len
;
242 static void moveToNextTask(redisReader
*r
) {
243 redisReadTask
*cur
, *prv
;
244 while (r
->ridx
>= 0) {
245 /* Return a.s.a.p. when the stack is now empty. */
251 cur
= &(r
->rstack
[r
->ridx
]);
252 prv
= &(r
->rstack
[r
->ridx
-1]);
253 assert(prv
->type
== REDIS_REPLY_ARRAY
);
254 if (cur
->idx
== prv
->elements
-1) {
257 /* Reset the type because the next item can be anything */
258 assert(cur
->idx
< prv
->elements
);
267 static int processLineItem(redisReader
*r
) {
268 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
273 if ((p
= readLine(r
,&len
)) != NULL
) {
274 if (cur
->type
== REDIS_REPLY_INTEGER
) {
275 if (r
->fn
&& r
->fn
->createInteger
)
276 obj
= r
->fn
->createInteger(cur
,readLongLong(p
));
278 obj
= (void*)REDIS_REPLY_INTEGER
;
280 /* Type will be error or status. */
281 if (r
->fn
&& r
->fn
->createString
)
282 obj
= r
->fn
->createString(cur
,p
,len
);
284 obj
= (void*)(size_t)(cur
->type
);
287 /* Set reply if this is the root object. */
288 if (r
->ridx
== 0) r
->reply
= obj
;
295 static int processBulkItem(redisReader
*r
) {
296 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
300 unsigned long bytelen
;
304 s
= seekNewline(p
,r
->len
-r
->pos
);
307 bytelen
= s
-(r
->buf
+r
->pos
)+2; /* include \r\n */
308 len
= readLongLong(p
);
311 /* The nil object can always be created. */
312 if (r
->fn
&& r
->fn
->createNil
)
313 obj
= r
->fn
->createNil(cur
);
315 obj
= (void*)REDIS_REPLY_NIL
;
318 /* Only continue when the buffer contains the entire bulk item. */
319 bytelen
+= len
+2; /* include \r\n */
320 if (r
->pos
+bytelen
<= r
->len
) {
321 if (r
->fn
&& r
->fn
->createString
)
322 obj
= r
->fn
->createString(cur
,s
+2,len
);
324 obj
= (void*)REDIS_REPLY_STRING
;
329 /* Proceed when obj was created. */
333 /* Set reply if this is the root object. */
334 if (r
->ridx
== 0) r
->reply
= obj
;
342 static int processMultiBulkItem(redisReader
*r
) {
343 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
349 /* Set error for nested multi bulks with depth > 1 */
351 redisSetReplyReaderError(r
,sdscatprintf(sdsempty(),
352 "No support for nested multi bulk replies with depth > 7"));
356 if ((p
= readLine(r
,NULL
)) != NULL
) {
357 elements
= readLongLong(p
);
358 root
= (r
->ridx
== 0);
360 if (elements
== -1) {
361 if (r
->fn
&& r
->fn
->createNil
)
362 obj
= r
->fn
->createNil(cur
);
364 obj
= (void*)REDIS_REPLY_NIL
;
367 if (r
->fn
&& r
->fn
->createArray
)
368 obj
= r
->fn
->createArray(cur
,elements
);
370 obj
= (void*)REDIS_REPLY_ARRAY
;
372 /* Modify task stack when there are more than 0 elements. */
374 cur
->elements
= elements
;
377 r
->rstack
[r
->ridx
].type
= -1;
378 r
->rstack
[r
->ridx
].elements
= -1;
379 r
->rstack
[r
->ridx
].idx
= 0;
380 r
->rstack
[r
->ridx
].obj
= NULL
;
381 r
->rstack
[r
->ridx
].parent
= cur
;
382 r
->rstack
[r
->ridx
].privdata
= r
->privdata
;
388 /* Set reply if this is the root object. */
389 if (root
) r
->reply
= obj
;
395 static int processItem(redisReader
*r
) {
396 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
400 /* check if we need to read type */
402 if ((p
= readBytes(r
,1)) != NULL
) {
405 cur
->type
= REDIS_REPLY_ERROR
;
408 cur
->type
= REDIS_REPLY_STATUS
;
411 cur
->type
= REDIS_REPLY_INTEGER
;
414 cur
->type
= REDIS_REPLY_STRING
;
417 cur
->type
= REDIS_REPLY_ARRAY
;
420 byte
= sdscatrepr(sdsempty(),p
,1);
421 redisSetReplyReaderError(r
,sdscatprintf(sdsempty(),
422 "Protocol error, got %s as reply type byte", byte
));
427 /* could not consume 1 byte */
432 /* process typed item */
434 case REDIS_REPLY_ERROR
:
435 case REDIS_REPLY_STATUS
:
436 case REDIS_REPLY_INTEGER
:
437 return processLineItem(r
);
438 case REDIS_REPLY_STRING
:
439 return processBulkItem(r
);
440 case REDIS_REPLY_ARRAY
:
441 return processMultiBulkItem(r
);
448 void *redisReplyReaderCreate(void) {
449 redisReader
*r
= calloc(sizeof(redisReader
),1);
451 r
->fn
= &defaultFunctions
;
457 /* Set the function set to build the reply. Returns REDIS_OK when there
458 * is no temporary object and it can be set, REDIS_ERR otherwise. */
459 int redisReplyReaderSetReplyObjectFunctions(void *reader
, redisReplyObjectFunctions
*fn
) {
460 redisReader
*r
= reader
;
461 if (r
->reply
== NULL
) {
468 /* Set the private data field that is used in the read tasks. This argument can
469 * be used to curry arbitrary data to the custom reply object functions. */
470 int redisReplyReaderSetPrivdata(void *reader
, void *privdata
) {
471 redisReader
*r
= reader
;
472 if (r
->reply
== NULL
) {
473 r
->privdata
= privdata
;
479 /* External libraries wrapping hiredis might need access to the temporary
480 * variable while the reply is built up. When the reader contains an
481 * object in between receiving some bytes to parse, this object might
482 * otherwise be free'd by garbage collection. */
483 void *redisReplyReaderGetObject(void *reader
) {
484 redisReader
*r
= reader
;
488 void redisReplyReaderFree(void *reader
) {
489 redisReader
*r
= reader
;
490 if (r
->error
!= NULL
)
492 if (r
->reply
!= NULL
&& r
->fn
)
493 r
->fn
->freeObject(r
->reply
);
499 static void redisSetReplyReaderError(redisReader
*r
, sds err
) {
500 if (r
->reply
!= NULL
)
501 r
->fn
->freeObject(r
->reply
);
503 /* Clear remaining buffer when we see a protocol error. */
504 if (r
->buf
!= NULL
) {
513 char *redisReplyReaderGetError(void *reader
) {
514 redisReader
*r
= reader
;
518 void redisReplyReaderFeed(void *reader
, const char *buf
, size_t len
) {
519 redisReader
*r
= reader
;
521 /* Copy the provided buffer. */
522 if (buf
!= NULL
&& len
>= 1) {
524 /* Destroy internal buffer when it is empty and is quite large. */
525 if (r
->len
== 0 && sdsavail(r
->buf
) > 16*1024) {
531 r
->buf
= sdscatlen(r
->buf
,buf
,len
);
532 r
->len
= sdslen(r
->buf
);
536 int redisReplyReaderGetReply(void *reader
, void **reply
) {
537 redisReader
*r
= reader
;
538 if (reply
!= NULL
) *reply
= NULL
;
540 /* When the buffer is empty, there will never be a reply. */
544 /* Set first item to process when the stack is empty. */
546 r
->rstack
[0].type
= -1;
547 r
->rstack
[0].elements
= -1;
548 r
->rstack
[0].idx
= -1;
549 r
->rstack
[0].obj
= NULL
;
550 r
->rstack
[0].parent
= NULL
;
551 r
->rstack
[0].privdata
= r
->privdata
;
555 /* Process items in reply. */
557 if (processItem(r
) < 0)
560 /* Discard part of the buffer when we've consumed at least 1k, to avoid
561 * doing unnecessary calls to memmove() in sds.c. */
562 if (r
->pos
>= 1024) {
563 r
->buf
= sdsrange(r
->buf
,r
->pos
,-1);
565 r
->len
= sdslen(r
->buf
);
568 /* Emit a reply when there is one. */
570 void *aux
= r
->reply
;
573 /* Check if there actually *is* a reply. */
574 if (r
->error
!= NULL
) {
577 if (reply
!= NULL
) *reply
= aux
;
583 /* Calculate the number of bytes needed to represent an integer as string. */
584 static int intlen(int i
) {
597 /* Helper function for redisvFormatCommand(). */
598 static void addArgument(sds a
, char ***argv
, int *argc
, int *totlen
) {
600 if ((*argv
= realloc(*argv
, sizeof(char*)*(*argc
))) == NULL
) redisOOM();
601 if (totlen
) *totlen
= *totlen
+1+intlen(sdslen(a
))+2+sdslen(a
)+2;
602 (*argv
)[(*argc
)-1] = a
;
605 int redisvFormatCommand(char **target
, const char *format
, va_list ap
) {
607 const char *arg
, *c
= format
;
608 char *cmd
= NULL
; /* final command */
609 int pos
; /* position in final command */
610 sds current
; /* current argument */
611 int touched
= 0; /* was the current argument touched? */
616 /* Abort if there is not target to set */
620 /* Build the command string accordingly to protocol */
621 current
= sdsempty();
623 if (*c
!= '%' || c
[1] == '\0') {
626 addArgument(current
, &argv
, &argc
, &totlen
);
627 current
= sdsempty();
631 current
= sdscatlen(current
,c
,1);
637 arg
= va_arg(ap
,char*);
640 current
= sdscatlen(current
,arg
,size
);
643 arg
= va_arg(ap
,char*);
644 size
= va_arg(ap
,size_t);
646 current
= sdscatlen(current
,arg
,size
);
649 current
= sdscat(current
,"%");
652 /* Try to detect printf format */
655 const char *_p
= c
+1;
660 if (*_p
!= '\0' && *_p
== '#') _p
++;
661 if (*_p
!= '\0' && *_p
== '0') _p
++;
662 if (*_p
!= '\0' && *_p
== '-') _p
++;
663 if (*_p
!= '\0' && *_p
== ' ') _p
++;
664 if (*_p
!= '\0' && *_p
== '+') _p
++;
667 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
672 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
677 if (*_p
== 'h' || *_p
== 'l') {
678 /* Allow a single repetition for these modifiers */
679 if (_p
[0] == _p
[1]) _p
++;
684 /* Conversion specifier */
685 if (*_p
!= '\0' && strchr("diouxXeEfFgGaA",*_p
) != NULL
) {
687 if (_l
< sizeof(_format
)-2) {
688 memcpy(_format
,c
,_l
);
691 current
= sdscatvprintf(current
,_format
,_cpy
);
694 /* Update current position (note: outer blocks
695 * increment c twice so compensate here) */
700 /* Consume and discard vararg */
710 /* Add the last argument if needed */
712 addArgument(current
, &argv
, &argc
, &totlen
);
717 /* Add bytes needed to hold multi bulk count */
718 totlen
+= 1+intlen(argc
)+2;
720 /* Build the command at protocol level */
721 cmd
= malloc(totlen
+1);
722 if (!cmd
) redisOOM();
723 pos
= sprintf(cmd
,"*%d\r\n",argc
);
724 for (j
= 0; j
< argc
; j
++) {
725 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",sdslen(argv
[j
]));
726 memcpy(cmd
+pos
,argv
[j
],sdslen(argv
[j
]));
727 pos
+= sdslen(argv
[j
]);
732 assert(pos
== totlen
);
739 /* Format a command according to the Redis protocol. This function
740 * takes a format similar to printf:
742 * %s represents a C null terminated string you want to interpolate
743 * %b represents a binary safe string
745 * When using %b you need to provide both the pointer to the string
746 * and the length in bytes. Examples:
748 * len = redisFormatCommand(target, "GET %s", mykey);
749 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
751 int redisFormatCommand(char **target
, const char *format
, ...) {
755 len
= redisvFormatCommand(target
,format
,ap
);
760 /* Format a command according to the Redis protocol. This function takes the
761 * number of arguments, an array with arguments and an array with their
762 * lengths. If the latter is set to NULL, strlen will be used to compute the
765 int redisFormatCommandArgv(char **target
, int argc
, const char **argv
, const size_t *argvlen
) {
766 char *cmd
= NULL
; /* final command */
767 int pos
; /* position in final command */
771 /* Calculate number of bytes needed for the command */
772 totlen
= 1+intlen(argc
)+2;
773 for (j
= 0; j
< argc
; j
++) {
774 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
775 totlen
+= 1+intlen(len
)+2+len
+2;
778 /* Build the command at protocol level */
779 cmd
= malloc(totlen
+1);
780 if (!cmd
) redisOOM();
781 pos
= sprintf(cmd
,"*%d\r\n",argc
);
782 for (j
= 0; j
< argc
; j
++) {
783 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
784 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",len
);
785 memcpy(cmd
+pos
,argv
[j
],len
);
790 assert(pos
== totlen
);
796 void __redisSetError(redisContext
*c
, int type
, const sds errstr
) {
798 if (errstr
!= NULL
) {
801 /* Only REDIS_ERR_IO may lack a description! */
802 assert(type
== REDIS_ERR_IO
);
803 c
->errstr
= sdsnew(strerror(errno
));
807 static redisContext
*redisContextInit(void) {
808 redisContext
*c
= calloc(sizeof(redisContext
),1);
811 c
->obuf
= sdsempty();
812 c
->fn
= &defaultFunctions
;
817 void redisFree(redisContext
*c
) {
820 if (c
->errstr
!= NULL
)
824 if (c
->reader
!= NULL
)
825 redisReplyReaderFree(c
->reader
);
829 /* Connect to a Redis instance. On error the field error in the returned
830 * context will be set to the return value of the error function.
831 * When no set of reply functions is given, the default set will be used. */
832 redisContext
*redisConnect(const char *ip
, int port
) {
833 redisContext
*c
= redisContextInit();
834 c
->flags
|= REDIS_BLOCK
;
835 redisContextConnectTcp(c
,ip
,port
,NULL
);
839 redisContext
*redisConnectWithTimeout(const char *ip
, int port
, struct timeval tv
) {
840 redisContext
*c
= redisContextInit();
841 c
->flags
|= REDIS_BLOCK
;
842 redisContextConnectTcp(c
,ip
,port
,&tv
);
846 redisContext
*redisConnectNonBlock(const char *ip
, int port
) {
847 redisContext
*c
= redisContextInit();
848 c
->flags
&= ~REDIS_BLOCK
;
849 redisContextConnectTcp(c
,ip
,port
,NULL
);
853 redisContext
*redisConnectUnix(const char *path
) {
854 redisContext
*c
= redisContextInit();
855 c
->flags
|= REDIS_BLOCK
;
856 redisContextConnectUnix(c
,path
,NULL
);
860 redisContext
*redisConnectUnixWithTimeout(const char *path
, struct timeval tv
) {
861 redisContext
*c
= redisContextInit();
862 c
->flags
|= REDIS_BLOCK
;
863 redisContextConnectUnix(c
,path
,&tv
);
867 redisContext
*redisConnectUnixNonBlock(const char *path
) {
868 redisContext
*c
= redisContextInit();
869 c
->flags
&= ~REDIS_BLOCK
;
870 redisContextConnectUnix(c
,path
,NULL
);
874 /* Set read/write timeout on a blocking socket. */
875 int redisSetTimeout(redisContext
*c
, struct timeval tv
) {
876 if (c
->flags
& REDIS_BLOCK
)
877 return redisContextSetTimeout(c
,tv
);
881 /* Set the replyObjectFunctions to use. Returns REDIS_ERR when the reader
882 * was already initialized and the function set could not be re-set.
883 * Return REDIS_OK when they could be set. */
884 int redisSetReplyObjectFunctions(redisContext
*c
, redisReplyObjectFunctions
*fn
) {
885 if (c
->reader
!= NULL
)
891 /* Helper function to lazily create a reply reader. */
892 static void __redisCreateReplyReader(redisContext
*c
) {
893 if (c
->reader
== NULL
) {
894 c
->reader
= redisReplyReaderCreate();
895 assert(redisReplyReaderSetReplyObjectFunctions(c
->reader
,c
->fn
) == REDIS_OK
);
899 /* Use this function to handle a read event on the descriptor. It will try
900 * and read some bytes from the socket and feed them to the reply parser.
902 * After this function is called, you may use redisContextReadReply to
903 * see if there is a reply available. */
904 int redisBufferRead(redisContext
*c
) {
906 int nread
= read(c
->fd
,buf
,sizeof(buf
));
908 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
909 /* Try again later */
911 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
914 } else if (nread
== 0) {
915 __redisSetError(c
,REDIS_ERR_EOF
,
916 sdsnew("Server closed the connection"));
919 __redisCreateReplyReader(c
);
920 redisReplyReaderFeed(c
->reader
,buf
,nread
);
925 /* Write the output buffer to the socket.
927 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
928 * succesfully written to the socket. When the buffer is empty after the
929 * write operation, "wdone" is set to 1 (if given).
931 * Returns REDIS_ERR if an error occured trying to write and sets
932 * c->error to hold the appropriate error string.
934 int redisBufferWrite(redisContext
*c
, int *done
) {
936 if (sdslen(c
->obuf
) > 0) {
937 nwritten
= write(c
->fd
,c
->obuf
,sdslen(c
->obuf
));
938 if (nwritten
== -1) {
939 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
940 /* Try again later */
942 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
945 } else if (nwritten
> 0) {
946 if (nwritten
== (signed)sdslen(c
->obuf
)) {
948 c
->obuf
= sdsempty();
950 c
->obuf
= sdsrange(c
->obuf
,nwritten
,-1);
954 if (done
!= NULL
) *done
= (sdslen(c
->obuf
) == 0);
958 /* Internal helper function to try and get a reply from the reader,
959 * or set an error in the context otherwise. */
960 int redisGetReplyFromReader(redisContext
*c
, void **reply
) {
961 __redisCreateReplyReader(c
);
962 if (redisReplyReaderGetReply(c
->reader
,reply
) == REDIS_ERR
) {
963 __redisSetError(c
,REDIS_ERR_PROTOCOL
,
964 sdsnew(((redisReader
*)c
->reader
)->error
));
970 int redisGetReply(redisContext
*c
, void **reply
) {
974 /* Try to read pending replies */
975 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
978 /* For the blocking context, flush output buffer and read reply */
979 if (aux
== NULL
&& c
->flags
& REDIS_BLOCK
) {
980 /* Write until done */
982 if (redisBufferWrite(c
,&wdone
) == REDIS_ERR
)
986 /* Read until there is a reply */
988 if (redisBufferRead(c
) == REDIS_ERR
)
990 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
992 } while (aux
== NULL
);
995 /* Set reply object */
996 if (reply
!= NULL
) *reply
= aux
;
1001 /* Helper function for the redisAppendCommand* family of functions.
1003 * Write a formatted command to the output buffer. When this family
1004 * is used, you need to call redisGetReply yourself to retrieve
1005 * the reply (or replies in pub/sub).
1007 void __redisAppendCommand(redisContext
*c
, char *cmd
, size_t len
) {
1008 c
->obuf
= sdscatlen(c
->obuf
,cmd
,len
);
1011 void redisvAppendCommand(redisContext
*c
, const char *format
, va_list ap
) {
1014 len
= redisvFormatCommand(&cmd
,format
,ap
);
1015 __redisAppendCommand(c
,cmd
,len
);
1019 void redisAppendCommand(redisContext
*c
, const char *format
, ...) {
1021 va_start(ap
,format
);
1022 redisvAppendCommand(c
,format
,ap
);
1026 void redisAppendCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1029 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1030 __redisAppendCommand(c
,cmd
,len
);
1034 /* Helper function for the redisCommand* family of functions.
1036 * Write a formatted command to the output buffer. If the given context is
1037 * blocking, immediately read the reply into the "reply" pointer. When the
1038 * context is non-blocking, the "reply" pointer will not be used and the
1039 * command is simply appended to the write buffer.
1041 * Returns the reply when a reply was succesfully retrieved. Returns NULL
1042 * otherwise. When NULL is returned in a blocking context, the error field
1043 * in the context will be set.
1045 static void *__redisCommand(redisContext
*c
, char *cmd
, size_t len
) {
1047 __redisAppendCommand(c
,cmd
,len
);
1049 if (c
->flags
& REDIS_BLOCK
) {
1050 if (redisGetReply(c
,&aux
) == REDIS_OK
)
1057 void *redisvCommand(redisContext
*c
, const char *format
, va_list ap
) {
1061 len
= redisvFormatCommand(&cmd
,format
,ap
);
1062 reply
= __redisCommand(c
,cmd
,len
);
1067 void *redisCommand(redisContext
*c
, const char *format
, ...) {
1070 va_start(ap
,format
);
1071 reply
= redisvCommand(c
,format
,ap
);
1076 void *redisCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1080 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1081 reply
= __redisCommand(c
,cmd
,len
);