From 3313bcd1912abdced96bc995ede22836c67bcd9d Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 27 Jun 2011 23:52:29 +0200 Subject: [PATCH] Change prototype of connect callback This commit adds a status argument to the connect callback. It will be called in the event of an unsuccessful connection as well, where the status argument is set to REDIS_ERR. It is set to REDIS_OK otherwise. --- async.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ async.h | 2 +- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/async.c b/async.c index 94c55f1..b293ecd 100644 --- a/async.c +++ b/async.c @@ -34,7 +34,9 @@ #include #include #include +#include #include "async.h" +#include "net.h" #include "dict.c" #include "sds.h" @@ -419,12 +421,43 @@ void redisProcessCallbacks(redisAsyncContext *ac) { __redisAsyncDisconnect(ac); } +/* Internal helper function to detect socket status the first time a read or + * write event fires. When connecting was not succesful, the connect callback + * is called with a REDIS_ERR status and the context is free'd. */ +static int __redisAsyncHandleConnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + if (redisCheckSocketError(c,c->fd) == REDIS_ERR) { + /* Try again later when connect(2) is still in progress. */ + if (errno == EINPROGRESS) + return REDIS_OK; + + if (ac->onConnect) ac->onConnect(ac,REDIS_ERR); + __redisAsyncDisconnect(ac); + return REDIS_ERR; + } + + /* Mark context as connected. */ + c->flags |= REDIS_CONNECTED; + if (ac->onConnect) ac->onConnect(ac,REDIS_OK); + return REDIS_OK; +} + /* This function should be called when the socket is readable. * It processes all replies that can be read and executes their callbacks. */ void redisAsyncHandleRead(redisAsyncContext *ac) { redisContext *c = &(ac->c); + if (!(c->flags & REDIS_CONNECTED)) { + /* Abort connect was not successful. */ + if (__redisAsyncHandleConnect(ac) != REDIS_OK) + return; + /* Try again later when the context is still not connected. */ + if (!(c->flags & REDIS_CONNECTED)) + return; + } + if (redisBufferRead(c) == REDIS_ERR) { __redisAsyncDisconnect(ac); } else { @@ -438,6 +471,15 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) { redisContext *c = &(ac->c); int done = 0; + if (!(c->flags & REDIS_CONNECTED)) { + /* Abort connect was not successful. */ + if (__redisAsyncHandleConnect(ac) != REDIS_OK) + return; + /* Try again later when the context is still not connected. */ + if (!(c->flags & REDIS_CONNECTED)) + return; + } + if (redisBufferWrite(c,&done) == REDIS_ERR) { __redisAsyncDisconnect(ac); } else { @@ -449,12 +491,6 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) { /* Always schedule reads after writes */ _EL_ADD_READ(ac); - - /* Fire onConnect when this is the first write event. */ - if (!(c->flags & REDIS_CONNECTED)) { - c->flags |= REDIS_CONNECTED; - if (ac->onConnect) ac->onConnect(ac); - } } } diff --git a/async.h b/async.h index bb5c87d..268274e 100644 --- a/async.h +++ b/async.h @@ -55,7 +55,7 @@ typedef struct redisCallbackList { /* Connection callback prototypes */ typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); -typedef void (redisConnectCallback)(const struct redisAsyncContext*); +typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); /* Context for an async connection to Redis */ typedef struct redisAsyncContext {