diff options
| author | Mark Nunberg <mnunberg@users.noreply.github.com> | 2018-10-03 06:53:42 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-03 06:53:42 -0400 | 
| commit | 67036ef70c9b332c51fe24489fc9f9cdaa09dbe3 (patch) | |
| tree | d0c133ad2b3cc92a43045a61ae0dfe956f464add /net.c | |
| parent | 747d78beaa66ef1666de7ea0153f2bc2504b8ee5 (diff) | |
| parent | 3cb4fb2395919ff91d29c7ab66634f5211eaca89 (diff) | |
| download | hiredict-67036ef70c9b332c51fe24489fc9f9cdaa09dbe3.tar.xz | |
Merge pull request #578 from mnunberg/connfix
Proper error reporting for connect failures
Diffstat (limited to 'net.c')
| -rw-r--r-- | net.c | 50 | 
1 files changed, 46 insertions, 4 deletions
| @@ -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;              } | 
