diff --git a/hiredis.c b/hiredis.c index 45a932a..585dfe8 100644 --- a/hiredis.c +++ b/hiredis.c @@ -714,25 +714,35 @@ int redisProcessCallbacks(redisContext *c) { return REDIS_OK; } -/* Use this function to try and write the entire output buffer to the - * descriptor. Returns 1 when the entire buffer was written, 0 otherwise. */ +/* Write the output buffer to the socket. + * + * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was + * succesfully written to the socket. When the buffer is empty after the + * write operation, "wdone" is set to 1 (if given). + * + * Returns REDIS_ERR if an error occured trying to write and sets + * c->error to hold the appropriate error string. + */ int redisBufferWrite(redisContext *c, int *done) { - int nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); - if (nwritten == -1) { - if (errno == EAGAIN) { - /* Try again later */ - } else { - /* Set error in context */ - c->error = sdscatprintf(sdsempty(), - "write: %s", strerror(errno)); - return REDIS_ERR; - } - } else if (nwritten > 0) { - if (nwritten == (signed)sdslen(c->obuf)) { - sdsfree(c->obuf); - c->obuf = sdsempty(); - } else { - c->obuf = sdsrange(c->obuf,nwritten,-1); + int nwritten; + if (sdslen(c->obuf) > 0) { + nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); + if (nwritten == -1) { + if (errno == EAGAIN) { + /* Try again later */ + } else { + /* Set error in context */ + c->error = sdscatprintf(sdsempty(), + "write: %s", strerror(errno)); + return REDIS_ERR; + } + } else if (nwritten > 0) { + if (nwritten == (signed)sdslen(c->obuf)) { + sdsfree(c->obuf); + c->obuf = sdsempty(); + } else { + c->obuf = sdsrange(c->obuf,nwritten,-1); + } } } if (done != NULL) *done = (sdslen(c->obuf) == 0); diff --git a/test.c b/test.c index 09bc32d..2800616 100644 --- a/test.c +++ b/test.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "hiredis.h" @@ -203,6 +204,7 @@ static void __test_callback(redisContext *c, const void *privdata) { static void test_nonblocking_connection() { redisContext *c; + int wdone = 0; __test_callback_flags = 0; test("Calls command callback when command is issued: "); @@ -227,6 +229,26 @@ static void test_nonblocking_connection() { redisSetFreeCallback(c,__test_callback,(const void*)4); redisFree(c); test_cond(__test_callback_flags == ((2 << 8) | 4)); + + test("redisBufferWrite against empty write buffer: "); + c = redisConnectNonBlock("127.0.0.1", 6379, NULL); + test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1); + redisFree(c); + + test("redisBufferWrite against not yet connected fd: "); + c = redisConnectNonBlock("127.0.0.1", 6379, NULL); + redisCommand(c,"PING"); + test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && + strncmp(c->error,"write:",6) == 0); + redisFree(c); + + test("redisBufferWrite against closed fd: "); + c = redisConnectNonBlock("127.0.0.1", 6379, NULL); + redisCommand(c,"PING"); + redisDisconnect(c); + test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && + strncmp(c->error,"write:",6) == 0); + redisFree(c); } int main(void) {