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) {
523 /* Destroy internal buffer when it is empty and is quite large. */
524 if (r
->len
== 0 && sdsavail(r
->buf
) > 16*1024) {
530 r
->buf
= sdscatlen(r
->buf
,buf
,len
);
531 r
->len
= sdslen(r
->buf
);
535 int redisReplyReaderGetReply(void *reader
, void **reply
) {
536 redisReader
*r
= reader
;
537 if (reply
!= NULL
) *reply
= NULL
;
539 /* When the buffer is empty, there will never be a reply. */
543 /* Set first item to process when the stack is empty. */
545 r
->rstack
[0].type
= -1;
546 r
->rstack
[0].elements
= -1;
547 r
->rstack
[0].idx
= -1;
548 r
->rstack
[0].obj
= NULL
;
549 r
->rstack
[0].parent
= NULL
;
550 r
->rstack
[0].privdata
= r
->privdata
;
554 /* Process items in reply. */
556 if (processItem(r
) < 0)
559 /* Discard part of the buffer when we've consumed at least 1k, to avoid
560 * doing unnecessary calls to memmove() in sds.c. */
561 if (r
->pos
>= 1024) {
562 r
->buf
= sdsrange(r
->buf
,r
->pos
,-1);
564 r
->len
= sdslen(r
->buf
);
567 /* Emit a reply when there is one. */
569 void *aux
= r
->reply
;
572 /* Check if there actually *is* a reply. */
573 if (r
->error
!= NULL
) {
576 if (reply
!= NULL
) *reply
= aux
;
582 /* Calculate the number of bytes needed to represent an integer as string. */
583 static int intlen(int i
) {
596 /* Helper function for redisvFormatCommand(). */
597 static void addArgument(sds a
, char ***argv
, int *argc
, int *totlen
) {
599 if ((*argv
= realloc(*argv
, sizeof(char*)*(*argc
))) == NULL
) redisOOM();
600 if (totlen
) *totlen
= *totlen
+1+intlen(sdslen(a
))+2+sdslen(a
)+2;
601 (*argv
)[(*argc
)-1] = a
;
604 int redisvFormatCommand(char **target
, const char *format
, va_list ap
) {
606 const char *arg
, *c
= format
;
607 char *cmd
= NULL
; /* final command */
608 int pos
; /* position in final command */
609 sds current
; /* current argument */
610 int touched
= 0; /* was the current argument touched? */
615 /* Abort if there is not target to set */
619 /* Build the command string accordingly to protocol */
620 current
= sdsempty();
622 if (*c
!= '%' || c
[1] == '\0') {
625 addArgument(current
, &argv
, &argc
, &totlen
);
626 current
= sdsempty();
630 current
= sdscatlen(current
,c
,1);
636 arg
= va_arg(ap
,char*);
639 current
= sdscatlen(current
,arg
,size
);
642 arg
= va_arg(ap
,char*);
643 size
= va_arg(ap
,size_t);
645 current
= sdscatlen(current
,arg
,size
);
648 current
= sdscat(current
,"%");
651 /* Try to detect printf format */
654 const char *_p
= c
+1;
659 if (*_p
!= '\0' && *_p
== '#') _p
++;
660 if (*_p
!= '\0' && *_p
== '0') _p
++;
661 if (*_p
!= '\0' && *_p
== '-') _p
++;
662 if (*_p
!= '\0' && *_p
== ' ') _p
++;
663 if (*_p
!= '\0' && *_p
== '+') _p
++;
666 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
671 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
676 if (*_p
== 'h' || *_p
== 'l') {
677 /* Allow a single repetition for these modifiers */
678 if (_p
[0] == _p
[1]) _p
++;
683 /* Conversion specifier */
684 if (*_p
!= '\0' && strchr("diouxXeEfFgGaA",*_p
) != NULL
) {
686 if (_l
< sizeof(_format
)-2) {
687 memcpy(_format
,c
,_l
);
690 current
= sdscatvprintf(current
,_format
,_cpy
);
693 /* Update current position (note: outer blocks
694 * increment c twice so compensate here) */
699 /* Consume and discard vararg */
709 /* Add the last argument if needed */
711 addArgument(current
, &argv
, &argc
, &totlen
);
716 /* Add bytes needed to hold multi bulk count */
717 totlen
+= 1+intlen(argc
)+2;
719 /* Build the command at protocol level */
720 cmd
= malloc(totlen
+1);
721 if (!cmd
) redisOOM();
722 pos
= sprintf(cmd
,"*%d\r\n",argc
);
723 for (j
= 0; j
< argc
; j
++) {
724 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",sdslen(argv
[j
]));
725 memcpy(cmd
+pos
,argv
[j
],sdslen(argv
[j
]));
726 pos
+= sdslen(argv
[j
]);
731 assert(pos
== totlen
);
738 /* Format a command according to the Redis protocol. This function
739 * takes a format similar to printf:
741 * %s represents a C null terminated string you want to interpolate
742 * %b represents a binary safe string
744 * When using %b you need to provide both the pointer to the string
745 * and the length in bytes. Examples:
747 * len = redisFormatCommand(target, "GET %s", mykey);
748 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
750 int redisFormatCommand(char **target
, const char *format
, ...) {
754 len
= redisvFormatCommand(target
,format
,ap
);
759 /* Format a command according to the Redis protocol. This function takes the
760 * number of arguments, an array with arguments and an array with their
761 * lengths. If the latter is set to NULL, strlen will be used to compute the
764 int redisFormatCommandArgv(char **target
, int argc
, const char **argv
, const size_t *argvlen
) {
765 char *cmd
= NULL
; /* final command */
766 int pos
; /* position in final command */
770 /* Calculate number of bytes needed for the command */
771 totlen
= 1+intlen(argc
)+2;
772 for (j
= 0; j
< argc
; j
++) {
773 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
774 totlen
+= 1+intlen(len
)+2+len
+2;
777 /* Build the command at protocol level */
778 cmd
= malloc(totlen
+1);
779 if (!cmd
) redisOOM();
780 pos
= sprintf(cmd
,"*%d\r\n",argc
);
781 for (j
= 0; j
< argc
; j
++) {
782 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
783 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",len
);
784 memcpy(cmd
+pos
,argv
[j
],len
);
789 assert(pos
== totlen
);
795 void __redisSetError(redisContext
*c
, int type
, const sds errstr
) {
797 if (errstr
!= NULL
) {
800 /* Only REDIS_ERR_IO may lack a description! */
801 assert(type
== REDIS_ERR_IO
);
802 c
->errstr
= sdsnew(strerror(errno
));
806 static redisContext
*redisContextInit(void) {
807 redisContext
*c
= calloc(sizeof(redisContext
),1);
810 c
->obuf
= sdsempty();
811 c
->fn
= &defaultFunctions
;
816 void redisFree(redisContext
*c
) {
819 if (c
->errstr
!= NULL
)
823 if (c
->reader
!= NULL
)
824 redisReplyReaderFree(c
->reader
);
828 /* Connect to a Redis instance. On error the field error in the returned
829 * context will be set to the return value of the error function.
830 * When no set of reply functions is given, the default set will be used. */
831 redisContext
*redisConnect(const char *ip
, int port
) {
832 redisContext
*c
= redisContextInit();
833 c
->flags
|= REDIS_BLOCK
;
834 redisContextConnectTcp(c
,ip
,port
,NULL
);
838 redisContext
*redisConnectWithTimeout(const char *ip
, int port
, struct timeval tv
) {
839 redisContext
*c
= redisContextInit();
840 c
->flags
|= REDIS_BLOCK
;
841 redisContextConnectTcp(c
,ip
,port
,&tv
);
845 redisContext
*redisConnectNonBlock(const char *ip
, int port
) {
846 redisContext
*c
= redisContextInit();
847 c
->flags
&= ~REDIS_BLOCK
;
848 redisContextConnectTcp(c
,ip
,port
,NULL
);
852 redisContext
*redisConnectUnix(const char *path
) {
853 redisContext
*c
= redisContextInit();
854 c
->flags
|= REDIS_BLOCK
;
855 redisContextConnectUnix(c
,path
,NULL
);
859 redisContext
*redisConnectUnixWithTimeout(const char *path
, struct timeval tv
) {
860 redisContext
*c
= redisContextInit();
861 c
->flags
|= REDIS_BLOCK
;
862 redisContextConnectUnix(c
,path
,&tv
);
866 redisContext
*redisConnectUnixNonBlock(const char *path
) {
867 redisContext
*c
= redisContextInit();
868 c
->flags
&= ~REDIS_BLOCK
;
869 redisContextConnectUnix(c
,path
,NULL
);
873 /* Set read/write timeout on a blocking socket. */
874 int redisSetTimeout(redisContext
*c
, struct timeval tv
) {
875 if (c
->flags
& REDIS_BLOCK
)
876 return redisContextSetTimeout(c
,tv
);
880 /* Set the replyObjectFunctions to use. Returns REDIS_ERR when the reader
881 * was already initialized and the function set could not be re-set.
882 * Return REDIS_OK when they could be set. */
883 int redisSetReplyObjectFunctions(redisContext
*c
, redisReplyObjectFunctions
*fn
) {
884 if (c
->reader
!= NULL
)
890 /* Helper function to lazily create a reply reader. */
891 static void __redisCreateReplyReader(redisContext
*c
) {
892 if (c
->reader
== NULL
) {
893 c
->reader
= redisReplyReaderCreate();
894 assert(redisReplyReaderSetReplyObjectFunctions(c
->reader
,c
->fn
) == REDIS_OK
);
898 /* Use this function to handle a read event on the descriptor. It will try
899 * and read some bytes from the socket and feed them to the reply parser.
901 * After this function is called, you may use redisContextReadReply to
902 * see if there is a reply available. */
903 int redisBufferRead(redisContext
*c
) {
905 int nread
= read(c
->fd
,buf
,sizeof(buf
));
907 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
908 /* Try again later */
910 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
913 } else if (nread
== 0) {
914 __redisSetError(c
,REDIS_ERR_EOF
,
915 sdsnew("Server closed the connection"));
918 __redisCreateReplyReader(c
);
919 redisReplyReaderFeed(c
->reader
,buf
,nread
);
924 /* Write the output buffer to the socket.
926 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
927 * succesfully written to the socket. When the buffer is empty after the
928 * write operation, "wdone" is set to 1 (if given).
930 * Returns REDIS_ERR if an error occured trying to write and sets
931 * c->error to hold the appropriate error string.
933 int redisBufferWrite(redisContext
*c
, int *done
) {
935 if (sdslen(c
->obuf
) > 0) {
936 nwritten
= write(c
->fd
,c
->obuf
,sdslen(c
->obuf
));
937 if (nwritten
== -1) {
938 if (errno
== EAGAIN
&& !(c
->flags
& REDIS_BLOCK
)) {
939 /* Try again later */
941 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
944 } else if (nwritten
> 0) {
945 if (nwritten
== (signed)sdslen(c
->obuf
)) {
947 c
->obuf
= sdsempty();
949 c
->obuf
= sdsrange(c
->obuf
,nwritten
,-1);
953 if (done
!= NULL
) *done
= (sdslen(c
->obuf
) == 0);
957 /* Internal helper function to try and get a reply from the reader,
958 * or set an error in the context otherwise. */
959 int redisGetReplyFromReader(redisContext
*c
, void **reply
) {
960 __redisCreateReplyReader(c
);
961 if (redisReplyReaderGetReply(c
->reader
,reply
) == REDIS_ERR
) {
962 __redisSetError(c
,REDIS_ERR_PROTOCOL
,
963 sdsnew(((redisReader
*)c
->reader
)->error
));
969 int redisGetReply(redisContext
*c
, void **reply
) {
973 /* Try to read pending replies */
974 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
977 /* For the blocking context, flush output buffer and read reply */
978 if (aux
== NULL
&& c
->flags
& REDIS_BLOCK
) {
979 /* Write until done */
981 if (redisBufferWrite(c
,&wdone
) == REDIS_ERR
)
985 /* Read until there is a reply */
987 if (redisBufferRead(c
) == REDIS_ERR
)
989 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
991 } while (aux
== NULL
);
994 /* Set reply object */
995 if (reply
!= NULL
) *reply
= aux
;
1000 /* Helper function for the redisAppendCommand* family of functions.
1002 * Write a formatted command to the output buffer. When this family
1003 * is used, you need to call redisGetReply yourself to retrieve
1004 * the reply (or replies in pub/sub).
1006 void __redisAppendCommand(redisContext
*c
, char *cmd
, size_t len
) {
1007 c
->obuf
= sdscatlen(c
->obuf
,cmd
,len
);
1010 void redisvAppendCommand(redisContext
*c
, const char *format
, va_list ap
) {
1013 len
= redisvFormatCommand(&cmd
,format
,ap
);
1014 __redisAppendCommand(c
,cmd
,len
);
1018 void redisAppendCommand(redisContext
*c
, const char *format
, ...) {
1020 va_start(ap
,format
);
1021 redisvAppendCommand(c
,format
,ap
);
1025 void redisAppendCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1028 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1029 __redisAppendCommand(c
,cmd
,len
);
1033 /* Helper function for the redisCommand* family of functions.
1035 * Write a formatted command to the output buffer. If the given context is
1036 * blocking, immediately read the reply into the "reply" pointer. When the
1037 * context is non-blocking, the "reply" pointer will not be used and the
1038 * command is simply appended to the write buffer.
1040 * Returns the reply when a reply was succesfully retrieved. Returns NULL
1041 * otherwise. When NULL is returned in a blocking context, the error field
1042 * in the context will be set.
1044 static void *__redisCommand(redisContext
*c
, char *cmd
, size_t len
) {
1046 __redisAppendCommand(c
,cmd
,len
);
1048 if (c
->flags
& REDIS_BLOCK
) {
1049 if (redisGetReply(c
,&aux
) == REDIS_OK
)
1056 void *redisvCommand(redisContext
*c
, const char *format
, va_list ap
) {
1060 len
= redisvFormatCommand(&cmd
,format
,ap
);
1061 reply
= __redisCommand(c
,cmd
,len
);
1066 void *redisCommand(redisContext
*c
, const char *format
, ...) {
1069 va_start(ap
,format
);
1070 reply
= redisvCommand(c
,format
,ap
);
1075 void *redisCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1079 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1080 reply
= __redisCommand(c
,cmd
,len
);