コード例 #1
0
ファイル: connect.c プロジェクト: kreshano/curl
/* singleipconnect() connects to the given IP only, and it may return without
   having connected if used from the multi interface. */
static curl_socket_t
singleipconnect(struct connectdata *conn,
                const Curl_addrinfo *ai,
                long timeout_ms,
                bool *connected)
{
    struct Curl_sockaddr_ex addr;
    char addr_buf[128];
    int rc;
    int error;
    bool isconnected;
    struct SessionHandle *data = conn->data;
    curl_socket_t sockfd;
    CURLcode res;
    const void *iptoprint;
    struct sockaddr_in * const sa4 = (void *)&addr.sa_addr;
#ifdef ENABLE_IPV6
    struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
#endif

    /*
     * The Curl_sockaddr_ex structure is basically libcurl's external API
     * curl_sockaddr structure with enough space available to directly hold
     * any protocol-specific address structures. The variable declared here
     * will be used to pass / receive data to/from the fopensocket callback
     * if this has been set, before that, it is initialized from parameters.
     */

    addr.family = ai->ai_family;
    addr.socktype = conn->socktype;
    addr.protocol = ai->ai_protocol;
    addr.addrlen = ai->ai_addrlen;

    if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
        addr.addrlen = sizeof(struct Curl_sockaddr_storage);
    memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);

    *connected = FALSE; /* default is not connected */

    if(data->set.fopensocket)
        /*
         * If the opensocket callback is set, all the destination address
         * information is passed to the callback. Depending on this information the
         * callback may opt to abort the connection, this is indicated returning
         * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
         * the callback returns a valid socket the destination address information
         * might have been changed and this 'new' address will actually be used
         * here to connect.
         */
        sockfd = data->set.fopensocket(data->set.opensocket_client,
                                       CURLSOCKTYPE_IPCXN,
                                       (struct curl_sockaddr *)&addr);
    else
        /* opensocket callback not set, so simply create the socket now */
        sockfd = socket(addr.family, addr.socktype, addr.protocol);

    if(sockfd == CURL_SOCKET_BAD)
        /* no socket, no connection */
        return CURL_SOCKET_BAD;

#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
    if (conn->scope && (addr.family == AF_INET6))
        sa6->sin6_scope_id = conn->scope;
#endif

    /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
       argument? */
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
    if(addr.family == AF_UNIX) {
        infof(data, "  Trying %s... ",
              ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
        snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
                 ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
        strcpy(conn->ip_addr_str, data->info.ip);
    }
    else
#endif
    {
#ifdef ENABLE_IPV6
        if(addr.family == AF_INET6) {
            iptoprint = &sa6->sin6_addr;
            conn->bits.ipv6 = TRUE;
        }
        else
#endif
        {
            iptoprint = &sa4->sin_addr;
        }

        if(Curl_inet_ntop(addr.family, iptoprint, addr_buf,
                          sizeof(addr_buf)) != NULL) {
            infof(data, "  Trying %s... ", addr_buf);
            snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
            strcpy(conn->ip_addr_str, data->info.ip);
        }
    }

    if(data->set.tcp_nodelay)
        tcpnodelay(conn, sockfd);

    nosigpipe(conn, sockfd);

    Curl_sndbufset(sockfd);

    if(data->set.fsockopt) {
        /* activate callback for setting socket options */
        error = data->set.fsockopt(data->set.sockopt_client,
                                   sockfd,
                                   CURLSOCKTYPE_IPCXN);
        if(error) {
            sclose(sockfd); /* close the socket and bail out */
            return CURL_SOCKET_BAD;
        }
    }

    /* possibly bind the local end to an IP, interface or port */
    res = bindlocal(conn, sockfd, addr.family);
    if(res) {
        sclose(sockfd); /* close socket and bail out */
        return CURL_SOCKET_BAD;
    }

    /* set socket non-blocking */
    curlx_nonblock(sockfd, TRUE);

    /* Connect TCP sockets, bind UDP */
    if(conn->socktype == SOCK_STREAM)
        rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
    else
        rc = 0;

    if(-1 == rc) {
        error = SOCKERRNO;

        switch (error) {
        case EINPROGRESS:
        case EWOULDBLOCK:
#if defined(EAGAIN)
#if (EAGAIN) != (EWOULDBLOCK)
        /* On some platforms EAGAIN and EWOULDBLOCK are the
         * same value, and on others they are different, hence
         * the odd #if
         */
        case EAGAIN:
#endif
#endif
            rc = waitconnect(conn, sockfd, timeout_ms);
            break;
        default:
            /* unknown error, fallthrough and try another address! */
            failf(data, "Failed to connect to %s: %s",
                  addr_buf, Curl_strerror(conn,error));
            data->state.os_errno = error;
            break;
        }
    }

    /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
       connect(). We can be sure of this since connect() cannot return 1. */
    if((WAITCONN_TIMEOUT == rc) &&
            (data->state.used_interface == Curl_if_multi)) {
        /* Timeout when running the multi interface */
        return sockfd;
    }

    isconnected = verifyconnect(sockfd, &error);

    if(!rc && isconnected) {
        /* we are connected, awesome! */
        *connected = TRUE; /* this is a true connect */
        infof(data, "connected\n");
        Curl_updateconninfo(conn, sockfd);
        return sockfd;
    }
    else if(WAITCONN_TIMEOUT == rc)
        infof(data, "Timeout\n");
    else {
        data->state.os_errno = error;
        infof(data, "%s\n", Curl_strerror(conn, error));
    }

    /* connect failed or timed out */
    sclose(sockfd);

    return CURL_SOCKET_BAD;
}
コード例 #2
0
ファイル: connect.c プロジェクト: kreshano/curl
CURLcode Curl_is_connected(struct connectdata *conn,
                           int sockindex,
                           bool *connected)
{
    int rc;
    struct SessionHandle *data = conn->data;
    CURLcode code = CURLE_OK;
    curl_socket_t sockfd = conn->sock[sockindex];
    long allow = DEFAULT_CONNECT_TIMEOUT;

    DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);

    *connected = FALSE; /* a very negative world view is best */

    if(conn->bits.tcpconnect) {
        /* we are connected already! */
        long allow_total = 0;

        /* subtract the most strict timeout of the ones */
        if(data->set.timeout)
            allow_total = data->set.timeout;

        Curl_expire(data, allow_total);
        *connected = TRUE;
        return CURLE_OK;
    }

    /* figure out how long time we have left to connect */
    allow = Curl_timeleft(conn, NULL, TRUE);

    if(allow < 0) {
        /* time-out, bail out, go home */
        failf(data, "Connection time-out");
        return CURLE_OPERATION_TIMEDOUT;
    }

    Curl_expire(data, allow);

    /* check for connect without timeout as we want to return immediately */
    rc = waitconnect(conn, sockfd, 0);

    if(WAITCONN_CONNECTED == rc) {
        int error;
        if(verifyconnect(sockfd, &error)) {
            /* we are connected, awesome! */
            conn->bits.tcpconnect = TRUE;
            *connected = TRUE;
            Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
            Curl_verboseconnect(conn);
            Curl_updateconninfo(conn, sockfd);

            return CURLE_OK;
        }
        /* nope, not connected for real */
        data->state.os_errno = error;
        infof(data, "Connection failed\n");
        if(trynextip(conn, sockindex, connected)) {
            failf(data, "Failed connect to %s:%ld; %s",
                  conn->host.name, conn->port, Curl_strerror(conn, error));
            code = CURLE_COULDNT_CONNECT;
        }
    }
    else if(WAITCONN_TIMEOUT != rc) {
        int error = 0;

        /* nope, not connected  */
        if(WAITCONN_FDSET_ERROR == rc) {
            (void)verifyconnect(sockfd, &error);
            data->state.os_errno = error;
            infof(data, "%s\n",Curl_strerror(conn,error));
        }
        else
            infof(data, "Connection failed\n");

        if(trynextip(conn, sockindex, connected)) {
            error = SOCKERRNO;
            data->state.os_errno = error;
            failf(data, "Failed connect to %s:%ld; %s",
                  conn->host.name, conn->port, Curl_strerror(conn, error));
            code = CURLE_COULDNT_CONNECT;
        }
    }
    /*
     * If the connection failed here, we should attempt to connect to the "next
     * address" for the given host.
     */

    return code;
}
コード例 #3
0
ファイル: connect.c プロジェクト: BishopGIS/cmake4libs
CURLcode Curl_is_connected(struct connectdata *conn,
                           int sockindex,
                           bool *connected)
{
  struct SessionHandle *data = conn->data;
  CURLcode result = CURLE_OK;
  long allow;
  int error = 0;
  struct timeval now;
  int rc;
  int i;

  DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);

  *connected = FALSE; /* a very negative world view is best */

  if(conn->bits.tcpconnect[sockindex]) {
    /* we are connected already! */
    *connected = TRUE;
    return CURLE_OK;
  }

  now = Curl_tvnow();

  /* figure out how long time we have left to connect */
  allow = Curl_timeleft(data, &now, TRUE);

  if(allow < 0) {
    /* time-out, bail out, go home */
    failf(data, "Connection time-out");
    return CURLE_OPERATION_TIMEDOUT;
  }

  for(i=0; i<2; i++) {
    if(conn->tempsock[i] == CURL_SOCKET_BAD)
      continue;

#ifdef mpeix
    /* Call this function once now, and ignore the results. We do this to
       "clear" the error state on the socket so that we can later read it
       reliably. This is reported necessary on the MPE/iX operating system. */
    (void)verifyconnect(conn->tempsock[i], NULL);
#endif

    /* check socket for connect */
    rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);

    if(rc == 0) { /* no connection yet */
      if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
        infof(data, "After %ldms connect time, move on!\n",
              conn->timeoutms_per_addr);
        error = ETIMEDOUT;
      }

      /* should we try another protocol family? */
      if(i == 0 && conn->tempaddr[1] == NULL &&
         curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
        trynextip(conn, sockindex, 1);
      }
    }
    else if(rc == CURL_CSELECT_OUT) {
      if(verifyconnect(conn->tempsock[i], &error)) {
        /* we are connected with TCP, awesome! */
        int other = i ^ 1;

        /* use this socket from now on */
        conn->sock[sockindex] = conn->tempsock[i];
        conn->ip_addr = conn->tempaddr[i];
        conn->tempsock[i] = CURL_SOCKET_BAD;

        /* close the other socket, if open */
        if(conn->tempsock[other] != CURL_SOCKET_BAD) {
          Curl_closesocket(conn, conn->tempsock[other]);
          conn->tempsock[other] = CURL_SOCKET_BAD;
        }

        /* see if we need to do any proxy magic first once we connected */
        result = Curl_connected_proxy(conn, sockindex);
        if(result)
          return result;

        conn->bits.tcpconnect[sockindex] = TRUE;

        *connected = TRUE;
        if(sockindex == FIRSTSOCKET)
          Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
        Curl_updateconninfo(conn, conn->sock[sockindex]);
        Curl_verboseconnect(conn);

        return CURLE_OK;
      }
      else
        infof(data, "Connection failed\n");
    }
    else if(rc & CURL_CSELECT_ERR)
      (void)verifyconnect(conn->tempsock[i], &error);

    /*
     * The connection failed here, we should attempt to connect to the "next
     * address" for the given host. But first remember the latest error.
     */
    if(error) {
      data->state.os_errno = error;
      SET_SOCKERRNO(error);
      if(conn->tempaddr[i]) {
        char ipaddress[MAX_IPADR_LEN];
        Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
        infof(data, "connect to %s port %ld failed: %s\n",
              ipaddress, conn->port, Curl_strerror(conn, error));

        conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
                                   allow : allow / 2;

        result = trynextip(conn, sockindex, i);
      }
    }
  }

  if(result) {
    /* no more addresses to try */

    /* if the first address family runs out of addresses to try before
       the happy eyeball timeout, go ahead and try the next family now */
    if(conn->tempaddr[1] == NULL) {
      result = trynextip(conn, sockindex, 1);
      if(!result)
        return result;
    }

    failf(data, "Failed to connect to %s port %ld: %s",
          conn->bits.proxy?conn->proxy.name:conn->host.name,
          conn->port, Curl_strerror(conn, error));
  }

  return result;
}
コード例 #4
0
ファイル: connect.c プロジェクト: AnupBansod/Nutrino_Stack
/*
 * singleipconnect()
 *
 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
 * CURL_SOCKET_BAD. Other errors will however return proper errors.
 *
 * singleipconnect() connects to the given IP only, and it may return without
 * having connected if used from the multi interface.
 */
static CURLcode
singleipconnect(struct connectdata *conn,
                const Curl_addrinfo *ai,
                long timeout_ms,
                curl_socket_t *sockp,
                bool *connected)
{
  struct Curl_sockaddr_ex addr;
  int rc;
  int error = 0;
  bool isconnected = FALSE;
  struct SessionHandle *data = conn->data;
  curl_socket_t sockfd;
  CURLcode res = CURLE_OK;

  *sockp = CURL_SOCKET_BAD;
  *connected = FALSE; /* default is not connected */

  res = Curl_socket(conn, ai, &addr, &sockfd);
  if(res)
    /* Failed to create the socket, but still return OK since we signal the
       lack of socket as well. This allows the parent function to keep looping
       over alternative addresses/socket families etc. */
    return CURLE_OK;

  /* store remote address and port used in this connection attempt */
  if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
                     conn->primary_ip, &conn->primary_port)) {
    /* malformed address or bug in inet_ntop, try next address */
    error = ERRNO;
    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
          error, Curl_strerror(conn, error));
    Curl_closesocket(conn, sockfd);
    return CURLE_OK;
  }
  memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
  infof(data, "  Trying %s...\n", conn->ip_addr_str);

  Curl_persistconninfo(conn);

  if(data->set.tcp_nodelay)
    tcpnodelay(conn, sockfd);

  nosigpipe(conn, sockfd);

  Curl_sndbufset(sockfd);

  if(data->set.tcp_keepalive)
    tcpkeepalive(data, sockfd);

  if(data->set.fsockopt) {
    /* activate callback for setting socket options */
    error = data->set.fsockopt(data->set.sockopt_client,
                               sockfd,
                               CURLSOCKTYPE_IPCXN);

    if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
      isconnected = TRUE;
    else if(error) {
      Curl_closesocket(conn, sockfd); /* close the socket and bail out */
      return CURLE_ABORTED_BY_CALLBACK;
    }
  }

  /* possibly bind the local end to an IP, interface or port */
  res = bindlocal(conn, sockfd, addr.family);
  if(res) {
    Curl_closesocket(conn, sockfd); /* close socket and bail out */
    return res;
  }

  /* set socket non-blocking */
  curlx_nonblock(sockfd, TRUE);

  /* Connect TCP sockets, bind UDP */
  if(!isconnected && (conn->socktype == SOCK_STREAM)) {
    rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
    if(-1 == rc)
      error = SOCKERRNO;
    conn->connecttime = Curl_tvnow();
    if(conn->num_addr > 1)
      Curl_expire(data, conn->timeoutms_per_addr);
  }
  else
    rc = 0;

  if(-1 == rc) {
    switch (error) {
    case EINPROGRESS:
    case EWOULDBLOCK:
#if defined(EAGAIN)
#if (EAGAIN) != (EWOULDBLOCK)
      /* On some platforms EAGAIN and EWOULDBLOCK are the
       * same value, and on others they are different, hence
       * the odd #if
       */
    case EAGAIN:
#endif
#endif
      rc = waitconnect(conn, sockfd, timeout_ms);
      if(WAITCONN_ABORTED == rc) {
        Curl_closesocket(conn, sockfd);
        return CURLE_ABORTED_BY_CALLBACK;
      }
      break;
    default:
      /* unknown error, fallthrough and try another address! */
      failf(data, "Failed to connect to %s: %s",
            conn->ip_addr_str, Curl_strerror(conn,error));
      data->state.os_errno = error;
      break;
    }
  }

  /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
     connect(). We can be sure of this since connect() cannot return 1. */
  if((WAITCONN_TIMEOUT == rc) &&
     (data->state.used_interface == Curl_if_multi)) {
    /* Timeout when running the multi interface */
    *sockp = sockfd;
    return CURLE_OK;
  }

  if(!isconnected)
    isconnected = verifyconnect(sockfd, &error);

  if(!rc && isconnected) {
    /* we are connected, awesome! */
    *connected = TRUE; /* this is a true connect */
    infof(data, "connected\n");
#ifdef ENABLE_IPV6
    conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
#endif

    Curl_updateconninfo(conn, sockfd);
    *sockp = sockfd;
    return CURLE_OK;
  }
  else if(WAITCONN_TIMEOUT == rc)
    infof(data, "Timeout\n");
  else {
    data->state.os_errno = error;
    infof(data, "%s\n", Curl_strerror(conn, error));
  }

  /* connect failed or timed out */
  Curl_closesocket(conn, sockfd);

  return CURLE_OK;
}
コード例 #5
0
ファイル: connect.c プロジェクト: AnupBansod/Nutrino_Stack
CURLcode Curl_is_connected(struct connectdata *conn,
                           int sockindex,
                           bool *connected)
{
  int rc;
  struct SessionHandle *data = conn->data;
  CURLcode code = CURLE_OK;
  curl_socket_t sockfd = conn->sock[sockindex];
  long allow = DEFAULT_CONNECT_TIMEOUT;
  int error = 0;
  struct timeval now;

  DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);

  *connected = FALSE; /* a very negative world view is best */

  if(conn->bits.tcpconnect[sockindex]) {
    /* we are connected already! */
    *connected = TRUE;
    return CURLE_OK;
  }

  now = Curl_tvnow();

  /* figure out how long time we have left to connect */
  allow = Curl_timeleft(data, &now, TRUE);

  if(allow < 0) {
    /* time-out, bail out, go home */
    failf(data, "Connection time-out");
    return CURLE_OPERATION_TIMEDOUT;
  }

  /* check for connect without timeout as we want to return immediately */
  rc = waitconnect(conn, sockfd, 0);
  if(WAITCONN_TIMEOUT == rc) {
    if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
      infof(data, "After %ldms connect time, move on!\n",
            conn->timeoutms_per_addr);
      goto next;
    }

    /* not an error, but also no connection yet */
    return code;
  }

  if(WAITCONN_CONNECTED == rc) {
    if(verifyconnect(sockfd, &error)) {
      /* we are connected with TCP, awesome! */

      /* see if we need to do any proxy magic first once we connected */
      code = Curl_connected_proxy(conn);
      if(code)
        return code;

      conn->bits.tcpconnect[sockindex] = TRUE;
      *connected = TRUE;
      if(sockindex == FIRSTSOCKET)
        Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
      Curl_verboseconnect(conn);
      Curl_updateconninfo(conn, sockfd);

      return CURLE_OK;
    }
    /* nope, not connected for real */
  }
  else {
    /* nope, not connected  */
    if(WAITCONN_FDSET_ERROR == rc) {
      (void)verifyconnect(sockfd, &error);
      infof(data, "%s\n",Curl_strerror(conn, error));
    }
    else
      infof(data, "Connection failed\n");
  }

  /*
   * The connection failed here, we should attempt to connect to the "next
   * address" for the given host. But first remember the latest error.
   */
  if(error) {
    data->state.os_errno = error;
    SET_SOCKERRNO(error);
  }
  next:

  conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
                             allow : allow / 2;
  code = trynextip(conn, sockindex, connected);

  if(code) {
    error = SOCKERRNO;
    data->state.os_errno = error;
    failf(data, "Failed connect to %s:%ld; %s",
          conn->host.name, conn->port, Curl_strerror(conn, error));
  }

  return code;
}
コード例 #6
0
ファイル: connect.c プロジェクト: LuaDist/curl
/*
 * singleipconnect()
 *
 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
 * CURL_SOCKET_BAD. Other errors will however return proper errors.
 *
 * singleipconnect() connects to the given IP only, and it may return without
 * having connected if used from the multi interface.
 */
static CURLcode
singleipconnect(struct connectdata *conn,
                const Curl_addrinfo *ai,
                long timeout_ms,
                curl_socket_t *sockp,
                bool *connected)
{
  struct Curl_sockaddr_ex addr;
  int rc;
  int error;
  bool isconnected = FALSE;
  struct SessionHandle *data = conn->data;
  curl_socket_t sockfd;
  CURLcode res = CURLE_OK;
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
  struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
#endif

  *sockp = CURL_SOCKET_BAD;

  /*
   * The Curl_sockaddr_ex structure is basically libcurl's external API
   * curl_sockaddr structure with enough space available to directly hold
   * any protocol-specific address structures. The variable declared here
   * will be used to pass / receive data to/from the fopensocket callback
   * if this has been set, before that, it is initialized from parameters.
   */

  addr.family = ai->ai_family;
  addr.socktype = conn->socktype;
  addr.protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
  addr.addrlen = ai->ai_addrlen;

  if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
     addr.addrlen = sizeof(struct Curl_sockaddr_storage);
  memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);

  *connected = FALSE; /* default is not connected */

  if(data->set.fopensocket)
   /*
    * If the opensocket callback is set, all the destination address
    * information is passed to the callback. Depending on this information the
    * callback may opt to abort the connection, this is indicated returning
    * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
    * the callback returns a valid socket the destination address information
    * might have been changed and this 'new' address will actually be used
    * here to connect.
    */
    sockfd = data->set.fopensocket(data->set.opensocket_client,
                                   CURLSOCKTYPE_IPCXN,
                                   (struct curl_sockaddr *)&addr);
  else
    /* opensocket callback not set, so simply create the socket now */
    sockfd = socket(addr.family, addr.socktype, addr.protocol);

  if(sockfd == CURL_SOCKET_BAD)
    /* no socket, no connection */
    return CURLE_OK;

#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
  if (conn->scope && (addr.family == AF_INET6))
    sa6->sin6_scope_id = conn->scope;
#endif

  /* store remote address and port used in this connection attempt */
  if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
                     conn->primary_ip, &conn->primary_port)) {
    /* malformed address or bug in inet_ntop, try next address */
    error = ERRNO;
    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
          error, Curl_strerror(conn, error));
    sclose(sockfd);
    return CURLE_OK;
  }
  memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
  infof(data, "  Trying %s... ", conn->ip_addr_str);

  Curl_persistconninfo(conn);

#ifdef ENABLE_IPV6
  if(addr.family == AF_INET6)
    conn->bits.ipv6 = TRUE;
#endif

  if(data->set.tcp_nodelay)
    tcpnodelay(conn, sockfd);

  nosigpipe(conn, sockfd);

  Curl_sndbufset(sockfd);

  if(data->set.fsockopt) {
    /* activate callback for setting socket options */
    error = data->set.fsockopt(data->set.sockopt_client,
                               sockfd,
                               CURLSOCKTYPE_IPCXN);

    if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
      isconnected = TRUE;
    else if(error) {
      sclose(sockfd); /* close the socket and bail out */
      return CURLE_ABORTED_BY_CALLBACK;
    }
  }

  /* possibly bind the local end to an IP, interface or port */
  res = bindlocal(conn, sockfd, addr.family);
  if(res) {
    sclose(sockfd); /* close socket and bail out */
    return res;
  }

  /* set socket non-blocking */
  curlx_nonblock(sockfd, TRUE);

  /* Connect TCP sockets, bind UDP */
  if(!isconnected && (conn->socktype == SOCK_STREAM)) {
    rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
    conn->connecttime = Curl_tvnow();
    if(conn->num_addr > 1)
      Curl_expire(data, conn->timeoutms_per_addr);
  }
  else
    rc = 0;

  if(-1 == rc) {
    error = SOCKERRNO;

    switch (error) {
    case EINPROGRESS:
    case EWOULDBLOCK:
#if defined(EAGAIN)
#if (EAGAIN) != (EWOULDBLOCK)
      /* On some platforms EAGAIN and EWOULDBLOCK are the
       * same value, and on others they are different, hence
       * the odd #if
       */
    case EAGAIN:
#endif
#endif
      rc = waitconnect(conn, sockfd, timeout_ms);
      if(WAITCONN_ABORTED == rc) {
        sclose(sockfd);
        return CURLE_ABORTED_BY_CALLBACK;
      }
      break;
    default:
      /* unknown error, fallthrough and try another address! */
      failf(data, "Failed to connect to %s: %s",
            conn->ip_addr_str, Curl_strerror(conn,error));
      data->state.os_errno = error;
      break;
    }
  }

  /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
     connect(). We can be sure of this since connect() cannot return 1. */
  if((WAITCONN_TIMEOUT == rc) &&
     (data->state.used_interface == Curl_if_multi)) {
    /* Timeout when running the multi interface */
    *sockp = sockfd;
    return CURLE_OK;
  }

  if(!isconnected)
    isconnected = verifyconnect(sockfd, &error);

  if(!rc && isconnected) {
    /* we are connected, awesome! */
    *connected = TRUE; /* this is a true connect */
    infof(data, "connected\n");
    Curl_updateconninfo(conn, sockfd);
    *sockp = sockfd;
    return CURLE_OK;
  }
  else if(WAITCONN_TIMEOUT == rc)
    infof(data, "Timeout\n");
  else {
    data->state.os_errno = error;
    infof(data, "%s\n", Curl_strerror(conn, error));
  }

  /* connect failed or timed out */
  sclose(sockfd);

  return CURLE_OK;
}