summaryrefslogtreecommitdiff
path: root/net.c
diff options
context:
space:
mode:
authorMark Nunberg <mnunberg@users.noreply.github.com>2018-10-03 06:53:42 -0400
committerGitHub <noreply@github.com>2018-10-03 06:53:42 -0400
commit67036ef70c9b332c51fe24489fc9f9cdaa09dbe3 (patch)
treed0c133ad2b3cc92a43045a61ae0dfe956f464add /net.c
parent747d78beaa66ef1666de7ea0153f2bc2504b8ee5 (diff)
parent3cb4fb2395919ff91d29c7ab66634f5211eaca89 (diff)
Merge pull request #578 from mnunberg/connfix
Proper error reporting for connect failures
Diffstat (limited to 'net.c')
-rw-r--r--net.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/net.c b/net.c
index 5d50f7c..a4b3abc 100644
--- a/net.c
+++ b/net.c
@@ -221,8 +221,10 @@ static int redisContextWaitReady(redisContext *c, long msec) {
return REDIS_ERR;
}
- if (redisCheckSocketError(c) != REDIS_OK)
+ if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
+ redisCheckSocketError(c);
return REDIS_ERR;
+ }
return REDIS_OK;
}
@@ -232,8 +234,28 @@ static int redisContextWaitReady(redisContext *c, long msec) {
return REDIS_ERR;
}
+int redisCheckConnectDone(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 err = 0;
+ int err = 0, errno_saved = errno;
socklen_t errlen = sizeof(err);
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
@@ -241,6 +263,10 @@ int redisCheckSocketError(redisContext *c) {
return REDIS_ERR;
}
+ if (err == 0) {
+ err = errno_saved;
+ }
+
if (err) {
errno = err;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
@@ -373,12 +399,27 @@ addrretry:
goto error;
}
}
+
+ /* For repeat connection */
+ if (c->saddr) {
+ free(c->saddr);
+ }
+ c->saddr = malloc(p->ai_addrlen);
+ 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 (errno == EHOSTUNREACH) {
redisContextCloseFd(c);
continue;
- } else if (errno == EINPROGRESS && !blocking) {
- /* This is ok. */
+ } else if (errno == EINPROGRESS) {
+ if (blocking) {
+ goto wait_for_ready;
+ }
+ /* This is ok.
+ * Note that even when it's in blocking mode, we unset blocking
+ * for `connect()`
+ */
} else if (errno == EADDRNOTAVAIL && reuseaddr) {
if (++reuses >= REDIS_CONNECT_RETRIES) {
goto error;
@@ -387,6 +428,7 @@ addrretry:
goto addrretry;
}
} else {
+ wait_for_ready:
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
goto error;
}