Call connect(2) again for non-blocking connect
This retrieves the actual error which occurred, as getsockopt is not always reliable in this regard.
This commit is contained in:
parent
685030652c
commit
49974c9359
24
async.c
24
async.c
@ -506,22 +506,22 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
|
|||||||
* write event fires. When connecting was not successful, the connect callback
|
* write event fires. When connecting was not successful, the connect callback
|
||||||
* is called with a REDIS_ERR status and the context is free'd. */
|
* is called with a REDIS_ERR status and the context is free'd. */
|
||||||
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
|
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
|
||||||
|
int completed = 0;
|
||||||
redisContext *c = &(ac->c);
|
redisContext *c = &(ac->c);
|
||||||
|
if (redisFinishAsyncConnect(c, &completed) == REDIS_ERR) {
|
||||||
if (redisCheckSocketError(c) == REDIS_ERR) {
|
/* Error! */
|
||||||
/* Try again later when connect(2) is still in progress. */
|
redisCheckSocketError(c);
|
||||||
if (errno == EINPROGRESS)
|
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
|
||||||
return REDIS_OK;
|
|
||||||
|
|
||||||
if (ac->onConnect) ac->onConnect(ac,REDIS_ERR);
|
|
||||||
__redisAsyncDisconnect(ac);
|
__redisAsyncDisconnect(ac);
|
||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
|
} else if (completed == 1) {
|
||||||
|
/* connected! */
|
||||||
|
if (ac->onConnect) ac->onConnect(ac, REDIS_OK);
|
||||||
|
c->flags |= REDIS_CONNECTED;
|
||||||
|
return REDIS_OK;
|
||||||
|
} else {
|
||||||
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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.
|
/* This function should be called when the socket is readable.
|
||||||
|
4
async.h
4
async.h
@ -93,6 +93,10 @@ typedef struct redisAsyncContext {
|
|||||||
/* Regular command callbacks */
|
/* Regular command callbacks */
|
||||||
redisCallbackList replies;
|
redisCallbackList replies;
|
||||||
|
|
||||||
|
/* Address used for connect() */
|
||||||
|
struct sockaddr *saddr;
|
||||||
|
size_t addrlen;
|
||||||
|
|
||||||
/* Subscription callbacks */
|
/* Subscription callbacks */
|
||||||
struct {
|
struct {
|
||||||
redisCallbackList invalid;
|
redisCallbackList invalid;
|
||||||
|
@ -606,12 +606,14 @@ void redisFree(redisContext *c) {
|
|||||||
return;
|
return;
|
||||||
if (c->fd > 0)
|
if (c->fd > 0)
|
||||||
close(c->fd);
|
close(c->fd);
|
||||||
|
|
||||||
sdsfree(c->obuf);
|
sdsfree(c->obuf);
|
||||||
redisReaderFree(c->reader);
|
redisReaderFree(c->reader);
|
||||||
free(c->tcp.host);
|
free(c->tcp.host);
|
||||||
free(c->tcp.source_addr);
|
free(c->tcp.source_addr);
|
||||||
free(c->unix_sock.path);
|
free(c->unix_sock.path);
|
||||||
free(c->timeout);
|
free(c->timeout);
|
||||||
|
free(c->saddr);
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +134,9 @@ typedef struct redisContext {
|
|||||||
char *path;
|
char *path;
|
||||||
} unix_sock;
|
} unix_sock;
|
||||||
|
|
||||||
|
/* For non-blocking connect */
|
||||||
|
struct sockadr *saddr;
|
||||||
|
size_t addrlen;
|
||||||
} redisContext;
|
} redisContext;
|
||||||
|
|
||||||
redisContext *redisConnect(const char *ip, int port);
|
redisContext *redisConnect(const char *ip, int port);
|
||||||
|
35
net.c
35
net.c
@ -232,8 +232,28 @@ static int redisContextWaitReady(redisContext *c, long msec) {
|
|||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int redisFinishAsyncConnect(redisContext *c, int *completed) {
|
||||||
|
int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen);
|
||||||
|
if (rc == 0) {
|
||||||
|
*completed = 1;
|
||||||
|
return REDIS_OK;
|
||||||
|
}
|
||||||
|
switch (errno) {
|
||||||
|
case EISCONN:
|
||||||
|
*completed = 1;
|
||||||
|
return REDIS_OK;
|
||||||
|
case EALREADY:
|
||||||
|
case EINPROGRESS:
|
||||||
|
case EWOULDBLOCK:
|
||||||
|
*completed = 0;
|
||||||
|
return REDIS_OK;
|
||||||
|
default:
|
||||||
|
return REDIS_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int redisCheckSocketError(redisContext *c) {
|
int redisCheckSocketError(redisContext *c) {
|
||||||
int err = 0;
|
int err = 0, errno_saved = errno;
|
||||||
socklen_t errlen = sizeof(err);
|
socklen_t errlen = sizeof(err);
|
||||||
|
|
||||||
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
||||||
@ -241,6 +261,10 @@ int redisCheckSocketError(redisContext *c) {
|
|||||||
return REDIS_ERR;
|
return REDIS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (err == 0) {
|
||||||
|
err = errno_saved;
|
||||||
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
errno = err;
|
errno = err;
|
||||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||||
@ -373,6 +397,15 @@ addrretry:
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For repeat connection */
|
||||||
|
if (c->saddr) {
|
||||||
|
free(c->saddr);
|
||||||
|
}
|
||||||
|
c->saddr = malloc(sizeof(*p->ai_addr));
|
||||||
|
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
|
||||||
|
c->addrlen = p->ai_addrlen;
|
||||||
|
|
||||||
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
|
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
|
||||||
if (errno == EHOSTUNREACH) {
|
if (errno == EHOSTUNREACH) {
|
||||||
redisContextCloseFd(c);
|
redisContextCloseFd(c);
|
||||||
|
1
net.h
1
net.h
@ -45,5 +45,6 @@ int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
|||||||
const char *source_addr);
|
const char *source_addr);
|
||||||
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
|
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
|
||||||
int redisKeepAlive(redisContext *c, int interval);
|
int redisKeepAlive(redisContext *c, int interval);
|
||||||
|
int redisFinishAsyncConnect(redisContext *c, int *completed);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user