Exemplo n.º 1
0
/* 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)
{
  char addr_buf[128];
  int rc;
  int error;
  bool isconnected;
  struct SessionHandle *data = conn->data;
  curl_socket_t sockfd;
  CURLcode res;

  sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
  if (sockfd == CURL_SOCKET_BAD)
    return CURL_SOCKET_BAD;

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

  Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
  infof(data, "  Trying %s... ", addr_buf);

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

  nosigpipe(conn, 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);
  if(res) {
    sclose(sockfd); /* close socket and bail out */
    return CURL_SOCKET_BAD;
  }

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

  /* Connect TCP sockets, bind UDP */
  if(conn->socktype == SOCK_STREAM)
    rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
  else
    rc = 0;

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

    switch (error) {
    case EINPROGRESS:
    case EWOULDBLOCK:
#if defined(EAGAIN) && 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
      rc = waitconnect(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");
    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;
}
Exemplo n.º 2
0
/* 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;
}
Exemplo n.º 3
0
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;
  long allow_total = 0;
  long has_passed;

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

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

  /* Evaluate in milliseconds how much time that has passed */
  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);

  /* subtract the most strict timeout of the ones */
  if(data->set.timeout && data->set.connecttimeout) {
    if (data->set.timeout < data->set.connecttimeout)
      allow_total = allow = data->set.timeout*1000;
    else
      allow = data->set.connecttimeout*1000;
  }
  else if(data->set.timeout) {
    allow_total = allow = data->set.timeout*1000;
  }
  else if(data->set.connecttimeout) {
    allow = data->set.connecttimeout*1000;
  }

  if(has_passed > allow ) {
    /* time-out, bail out, go home */
    failf(data, "Connection time-out after %ld ms", has_passed);
    return CURLE_OPERATION_TIMEOUTED;
  }
  if(conn->bits.tcpconnect) {
    /* we are connected already! */
    Curl_expire(data, allow_total);
    *connected = TRUE;
    return CURLE_OK;
  }

  Curl_expire(data, allow);

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

  if(WAITCONN_CONNECTED == rc) {
    int error;
    if (verifyconnect(sockfd, &error)) {
      /* we are connected, awesome! */
      *connected = TRUE;
      return CURLE_OK;
    }
    /* nope, not connected for real */
    data->state.os_errno = error;
    infof(data, "Connection failed\n");
    if(trynextip(conn, sockindex, connected)) {
      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 = Curl_sockerrno();
      data->state.os_errno = error;
      failf(data, "Failed connect to %s:%d; %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;
}
Exemplo n.º 4
0
/*
 * 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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
/*
 * 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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
void main(int argc,char *argv[]) {
    int going=TRUE,forsok=2,car=1,x,connectbps, i, tmp;
    struct NodeType *nt;
    char *tmppscreen,commandstring[100], configname[50] = "NiKom:DatoCfg/SerNode.cfg";
    FILE *fil;
    if(argc>1) for(x=1; x<argc; x++) {
            if(argv[x][0]=='-') {
                if(argv[x][1]=='G') getty=TRUE;
                else if(argv[x][1]=='B') gettybps=atoi(&argv[x][2]);
                else if(argv[x][1]=='C') connectbps = atoi(&argv[x][2]);
            } else strcpy(configname,argv[x]);
        }
    if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0)))
        cleanup(ERROR,"Kunde inte öppna intuition.library\n");
    if(!(UtilityBase=OpenLibrary("utility.library",37L)))
        cleanup(ERROR,"Kunde inte öppna utility.library\n");
    if(!(NiKomBase=OpenLibrary("nikom.library",0L)))
        cleanup(ERROR,"Kunde inte öppna nikom.library\n");
    if(!initnode(NODSER)) cleanup(ERROR,"Kunde inte registrera noden i Servern\n");
    if(!(nikomnodeport = CreateMsgPort()))
        cleanup(ERROR,"Kunde inte skapa NiKomNode-porten");
    sprintf(nikomnodeportnamn,"NiKomNode%d",nodnr);
    nikomnodeport->mp_Node.ln_Name = nikomnodeportnamn;
    nikomnodeport->mp_Node.ln_Pri = 1;
    AddPort(nikomnodeport);
    sprintf(rexxportnamn,"NiKomPreRexx%d",nodnr);
    if(!(rexxport=(struct MsgPort *)CreateMsgPort()))
        cleanup(ERROR,"Kunde inte öppna RexxPort\n");
    rexxport->mp_Node.ln_Name=rexxportnamn;
    rexxport->mp_Node.ln_Pri=50;
    AddPort(rexxport);
    if(!(RexxSysBase=(struct RsxLib *)OpenLibrary("rexxsyslib.library",0L)))
        cleanup(ERROR,"Kunde inte öppna rexxsyslib.library\n");
    getnodeconfig(configname);
    if(pubscreen[0]=='-') tmppscreen=NULL;
    else tmppscreen=pubscreen;
    if(!(NiKwind=openmywindow(tmppscreen)))
        cleanup(ERROR,"Kunde inte öppna fönstret\n");
    if(getty) dtespeed = gettybps;
    else dtespeed = highbaud;
    if(!OpenIO(NiKwind)) cleanup(ERROR,"Couldn't setup IO");
    strcpy(Servermem->nodid[nodnr],nodid);
    conreqtkn();
    serreqtkn();
    Delay(50);
    for(;;) {
        inloggad=-1;
        Servermem->idletime[nodnr] = time(NULL);
        Servermem->inloggad[nodnr]=-1;
        if(getty) Servermem->connectbps[nodnr] = connectbps;
        else waitconnect();
        Servermem->idletime[nodnr] = time(NULL);
        Servermem->inloggad[nodnr]=-2; /* Sätt till <Uppringd> för att även hantera -getty-fallet */
reloginspec:
        updateinactive();
        Servermem->inne[nodnr].flaggor = Servermem->cfg.defaultflags;
        if(!getty) Delay(100);
        Servermem->inne[nodnr].rader=0;
        Servermem->inne[nodnr].chrset = CHRS_LATIN1;
        sendfile("NiKom:Texter/Inlogg.txt");
        if(Servermem->cfg.ar.preinlogg) sendrexx(Servermem->cfg.ar.preinlogg);
        car=TRUE;
        Servermem->inne[nodnr].chrset = 0;
        memset(commandhistory,0,1000);
        going=1;
        while(going && going<=Servermem->cfg.logintries) {
            putstring("\r\nNamn: ",-1,0);
            if(getstring(EKO,40,NULL)) {
                car=FALSE;
                break;
            }
            if(!stricmp(inmat,Servermem->cfg.ny)
                    && !(Servermem->cfg.cfgflags & NICFG_CLOSEDBBS)) {
                tmp = RegisterNewUser();
                if(tmp == 2) {
                    goto panik;
                }
                car = tmp ? 0 : 1;
                going=FALSE;
            } else if((inloggad=parsenamn(inmat))>=0) {
                if(readuser(inloggad,&Servermem->inne[nodnr])) {
                    puttekn("Error reading user data.\r\n", -1);
                    goto panik;
                }
                // TODO: Extract password loop. Should be identical to in NiKomCon.c
                forsok=2;
                while(forsok) {
                    puttekn("\r\nLösen: ",-1);
                    if(Servermem->inne[nodnr].flaggor & STAREKOFLAG)
                    {
                        if(getstring(STAREKO,15,NULL)) {
                            car=FALSE;
                            break;
                        }
                    }
                    else
                    {
                        if(getstring(EJEKO,15,NULL)) {
                            car=FALSE;
                            break;
                        }
                    }
                    if(CheckPassword(inmat, Servermem->inne[nodnr].losen))
                    {
                        forsok=FALSE;
                        going=FALSE;
                    } else forsok--;
                }
                if(going && (Servermem->cfg.logmask & LOG_FAILINLOGG)) {
                    LogEvent(USAGE_LOG, WARN, "Nod %d, %s angivet som namn, fel lösen.",
                             nodnr, getusername(inloggad));
                }
                if(going) going++;
            } else if(inloggad==-1) puttekn("\r\nHittar ej namnet\r\n",-1);
        }
        if(!car) {
            if(getty) cleanup(OK,"");
            disconnect();
            continue;
        }
        if(going) {
            putstring("\n\n\rTyvärr. Du har försökt maximalt antal gånger att logga in. Kopplar ned.\n\r",-1,0);
            goto panik;      /* Urrk vad fult. :-) */
        }
        Servermem->inloggad[nodnr]=inloggad;
        Servermem->idletime[nodnr] = time(NULL);
        if((nt = selectNodeType()) == NULL) {
            goto panik;
        }
        abortinactive();
        abortserial();

        sprintf(commandstring,"%s -N%d -B%d %s",nt->path,nodnr,dtespeed,configname);
        CloseConsole();
        CloseWindow(NiKwind);
        NiKwind = NULL;
        RemPort(nikomnodeport);

        i = 0;
        if(Servermem->connectbps[nodnr] > 0)
        {
            while(Servermem->info.bps[i] != Servermem->connectbps[nodnr] && Servermem->info.bps[i] > 0 && i<49)
                i++;

            if(i<49)
            {
                if(Servermem->info.bps[i] == Servermem->connectbps[nodnr])
                    Servermem->info.antbps[i]++;
                else
                {
                    Servermem->info.bps[i] = Servermem->connectbps[nodnr];
                    Servermem->info.antbps[i]++;
                }
            }

            if(!(fil = fopen("NiKom:datocfg/sysinfo.dat","w")))
            {
                /* putstring("Kunde inte spara nya sysinfo.dat..\n",-1,0); */
            }

            if(fwrite((void *)&Servermem->info,sizeof(Servermem->info),1,fil) != 1)
            {
                /* putstring("Kunde inte skriva till nya sysinfo.dat....\n",-1,0); */
            }
            fclose(fil);
        }

        nodestate = SystemTags(commandstring, SYS_UserShell, TRUE, TAG_DONE);
        AddPort(nikomnodeport);
        if(!getty || (nodestate & NIKSTATE_RELOGIN)) {
            if(!(NiKwind = openmywindow(tmppscreen))) cleanup(ERROR,"Kunde inte öppna fönstret\n");
            OpenConsole(NiKwind);
        }
        serreqtkn();
        if(nodestate & NIKSTATE_RELOGIN) goto reloginspec;
panik:
        Delay(hangupdelay);
        if(getty) cleanup(OK,"");
        disconnect();
    }
}
Exemplo n.º 9
0
/* 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,
                Curl_addrinfo *ai,
                long timeout_ms,
                bool *connected)
{
  char addr_buf[128];
  int rc;
  int error;
  bool conected;
  struct SessionHandle *data = conn->data;
  curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
                                ai->ai_protocol);
  if (sockfd == CURL_SOCKET_BAD)
    return CURL_SOCKET_BAD;

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

  Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
  infof(data, "  Trying %s... ", addr_buf);

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

#ifdef SO_NOSIGPIPE
  nosigpipe(conn, sockfd);
#endif
  if(conn->data->set.device) {
    /* user selected to bind the outgoing socket to a specified "device"
       before doing connect */
    CURLcode res = bindlocal(conn, sockfd);
    if(res) {
      sclose(sockfd); /* close socket and bail out */
      return CURL_SOCKET_BAD;
    }
  }

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

  rc = connect(sockfd, ai->ai_addr, (socklen_t)ai->ai_addrlen);

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

    switch (error) {
    case EINPROGRESS:
    case EWOULDBLOCK:
#if defined(EAGAIN) && 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
      rc = waitconnect(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;
  }

  conected = verifyconnect(sockfd, &error);

  if(!rc && conected) {
    /* we are connected, awesome! */
    *connected = TRUE; /* this is a true connect */
    infof(data, "connected\n");
    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;
}
Exemplo n.º 10
0
CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
                          struct Curl_dns_entry *remotehost, /* use this one */
                          int port,                  /* connect to this */
                          curl_socket_t *sockconn,   /* the connected socket */
                          Curl_ipconnect **addr,     /* the one we used */
                          bool *connected)           /* really connected? */
{
  struct SessionHandle *data = conn->data;
  int rc;
  curl_socket_t sockfd= CURL_SOCKET_BAD;
  int aliasindex=0;
  char *hostname;

  struct timeval after;
  struct timeval before = Curl_tvnow();

#ifdef ENABLE_IPV6
  struct addrinfo *ai;
#endif  

  /*************************************************************
   * Figure out what maximum time we have left
   *************************************************************/
  long timeout_ms=300000; /* milliseconds, default to five minutes */

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

  if(data->set.timeout || data->set.connecttimeout) {
    double has_passed;

    /* Evaluate in milliseconds how much time that has passed */
    has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);

#ifndef min
#define min(a, b)   ((a) < (b) ? (a) : (b))
#endif

    /* get the most strict timeout of the ones converted to milliseconds */
    if(data->set.timeout && data->set.connecttimeout) {
      if (data->set.timeout < data->set.connecttimeout)
        timeout_ms = data->set.timeout*1000;
      else 
        timeout_ms = data->set.connecttimeout*1000;
    }
    else if(data->set.timeout)
      timeout_ms = data->set.timeout*1000;
    else
      timeout_ms = data->set.connecttimeout*1000;

    /* subtract the passed time */
    timeout_ms -= (long)has_passed;

    if(timeout_ms < 0) {
      /* a precaution, no need to continue if time already is up */
      failf(data, "Connection time-out");
      return CURLE_OPERATION_TIMEOUTED;
    }
  }

  hostname = data->change.proxy?conn->proxyhost:conn->hostname;
  infof(data, "About to connect() to %s port %d\n",
        hostname, port);

#ifdef ENABLE_IPV6
  /*
   * Connecting with a getaddrinfo chain
   */
  for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
    sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (sockfd == CURL_SOCKET_BAD)
      continue;
#else
  /*
   * Connecting with old style IPv4-only support
   */

  /* This is the loop that attempts to connect to all IP-addresses we
     know for the given host. One by one. */
  for(rc=-1, aliasindex=0;
      rc && (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
      aliasindex++) {
    struct sockaddr_in serv_addr;

    /* create an IPv4 TCP socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(CURL_SOCKET_BAD == sockfd) {
      failf(data, "couldn't create socket");
      return CURLE_COULDNT_CONNECT; /* big time error */
    }

    /* nasty address work before connect can be made */
    memset((char *) &serv_addr, '\0', sizeof(serv_addr));
    memcpy((char *)&(serv_addr.sin_addr),
           (struct in_addr *)remotehost->addr->h_addr_list[aliasindex],
           sizeof(struct in_addr));
    serv_addr.sin_family = remotehost->addr->h_addrtype;
    serv_addr.sin_port = htons((unsigned short)port);
#endif

    if(conn->data->set.device) {
      /* user selected to bind the outgoing socket to a specified "device"
         before doing connect */
      CURLcode res = bindlocal(conn, sockfd);
      if(res)
        return res;
    }

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

    /* do not use #ifdef within the function arguments below, as connect() is
       a defined macro on some platforms and some compilers don't like to mix
       #ifdefs with macro usage! (AmigaOS is one such platform) */
#ifdef ENABLE_IPV6
    rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
#else
    rc = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
#endif

    if(-1 == rc) {
      int error=Curl_ourerrno();

      switch (error) {
      case EINPROGRESS:
      case EWOULDBLOCK:
#if defined(EAGAIN) && 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
        /* asynchronous connect, wait for connect or timeout */
        if(data->state.used_interface == Curl_if_multi)
          /* don't hang when doing multi */
          timeout_ms = 0;
        
        rc = waitconnect(sockfd, timeout_ms);
        break;
      default:
        /* unknown error, fallthrough and try another address! */
        failf(data, "Failed to connect to %s IP number %d: %d",
              hostname, aliasindex+1, error);
        break;
      }
    }

    /* The '1 == rc' comes from the waitconnect(), and not from connect().
       We can be sure of this since connect() cannot return 1. */
    if((1 == rc) && (data->state.used_interface == Curl_if_multi)) {
      /* Timeout when running the multi interface, we return here with a
         CURLE_OK return code. */
      rc = 0;
      break;
    }
      
    if(0 == rc) {
      if (verifyconnect(sockfd)) {
        /* we are connected, awesome! */
        *connected = TRUE; /* this is a true connect */
        break;
      }
      /* nope, not connected for real */
      rc = -1;
    }

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

    /* get a new timeout for next attempt */
    after = Curl_tvnow();
    timeout_ms -= Curl_tvdiff(after, before);
    if(timeout_ms < 0) {
      failf(data, "connect() timed out!");
      return CURLE_OPERATION_TIMEOUTED;
    }
    before = after;
  }
  if (sockfd == CURL_SOCKET_BAD) {
    /* no good connect was made */
    *sockconn = -1;
    failf(data, "Connect failed");
    return CURLE_COULDNT_CONNECT;
  }

  /* leave the socket in non-blocking mode */

  /* store the address we use */
  if(addr) {
#ifdef ENABLE_IPV6
    *addr = ai;
#else
    *addr = (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
#endif
  }

  /* allow NULL-pointers to get passed in */
  if(sockconn)
    *sockconn = sockfd;    /* the socket descriptor we've connected */

  return CURLE_OK;
}
Exemplo n.º 11
0
CURLcode Curl_is_connected(struct connectdata *conn,
                           curl_socket_t sockfd,
                           bool *connected)
{
  int rc;
  struct SessionHandle *data = conn->data;

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

  if(data->set.timeout || data->set.connecttimeout) {
    /* there is a timeout set */

    /* Evaluate in milliseconds how much time that has passed */
    long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);

    /* subtract the most strict timeout of the ones */
    if(data->set.timeout && data->set.connecttimeout) {
      if (data->set.timeout < data->set.connecttimeout)
        has_passed -= data->set.timeout*1000;
      else 
        has_passed -= data->set.connecttimeout*1000;
    }
    else if(data->set.timeout)
      has_passed -= data->set.timeout*1000;
    else
      has_passed -= data->set.connecttimeout*1000;

    if(has_passed > 0 ) {
      /* time-out, bail out, go home */
      failf(data, "Connection time-out");
      return CURLE_OPERATION_TIMEOUTED;
    }
  }
  if(conn->bits.tcpconnect) {
    /* we are connected already! */
    *connected = TRUE;
    return CURLE_OK;
  }

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

  if(0 == rc) {
    if (verifyconnect(sockfd)) {
      /* we are connected, awesome! */
      *connected = TRUE;
      return CURLE_OK;
    }
    /* nope, not connected for real */
    failf(data, "Connection failed");
    return CURLE_COULDNT_CONNECT;
  }
  else if(1 != rc) {
    int error = Curl_ourerrno();
    failf(data, "Failed connect to %s:%d, errno: %d",
          conn->hostname, conn->port, error);
    return CURLE_COULDNT_CONNECT;
  }
  /*
   * If the connection phase is "done" here, we should attempt to connect
   * to the "next address" in the Curl_hostaddr structure that we resolved
   * before. But we don't have that struct around anymore and we can't just
   * keep a pointer since the cache might in fact have gotten pruned by the
   * time we want to read this... Alas, we don't do this yet.
   */

  return CURLE_OK;
}
Exemplo n.º 12
0
CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
                          struct Curl_dns_entry *remotehost, /* use this one */
                          int port,                  /* connect to this */
                          int *sockconn,             /* the connected socket */
                          Curl_ipconnect **addr,     /* the one we used */
                          bool *connected)           /* really connected? */
{
  struct SessionHandle *data = conn->data;
  int rc;
  int sockfd=-1;
  int aliasindex=0;
  char *hostname;

  struct timeval after;
  struct timeval before = Curl_tvnow();

  /*************************************************************
   * Figure out what maximum time we have left
   *************************************************************/
  long timeout_ms=300000; /* milliseconds, default to five minutes */

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

  if(data->set.timeout || data->set.connecttimeout) {
    double has_passed;

    /* Evaluate in milliseconds how much time that has passed */
    has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);

#ifndef min
#define min(a, b)   ((a) < (b) ? (a) : (b))
#endif

    /* get the most strict timeout of the ones converted to milliseconds */
    if(data->set.timeout && data->set.connecttimeout) {
      if (data->set.timeout < data->set.connecttimeout)
        timeout_ms = data->set.timeout*1000;
      else 
        timeout_ms = data->set.connecttimeout*1000;
    }
    else if(data->set.timeout)
      timeout_ms = data->set.timeout*1000;
    else
      timeout_ms = data->set.connecttimeout*1000;

    /* subtract the passed time */
    timeout_ms -= (long)has_passed;

    if(timeout_ms < 0) {
      /* a precaution, no need to continue if time already is up */
      failf(data, "Connection time-out");
      return CURLE_OPERATION_TIMEOUTED;
    }
  }

  hostname = data->change.proxy?conn->proxyhost:conn->hostname;
  infof(data, "About to connect() to %s%s%s:%d\n",
        conn->bits.ipv6_ip?"[":"",
        hostname,
        conn->bits.ipv6_ip?"]":"",
        port);

#ifdef ENABLE_IPV6
  /*
   * Connecting with IPv6 support is so much easier and cleanly done
   */
  {
    struct addrinfo *ai;
    port =0; /* prevent compiler warning */

    for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
      sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
      if (sockfd < 0)
        continue;

      if(conn->data->set.device) {
        /* user selected to bind the outgoing socket to a specified "device"
           before doing connect */
        CURLcode res = bindlocal(conn, sockfd);
        if(res)
          return res;
      }

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

      rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);

      if(-1 == rc) {
        int error=Curl_ourerrno();

        switch (error) {
        case EINPROGRESS:
        case EWOULDBLOCK:
#if defined(EAGAIN) && 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
        case EINTR:
          /* asynchronous connect, wait for connect or timeout */
          if(data->state.used_interface == Curl_if_multi)
            /* don't hang when doing multi */
            timeout_ms = 0;

          rc = waitconnect(sockfd, timeout_ms);
          break;
        case ECONNREFUSED: /* no one listening */
        default:
          /* unknown error, fallthrough and try another address! */
          failf(data, "Failed connect to %s: %d", hostname, error);
          break;
        }
      }

      if(0 == rc) {
        /* we might be connected, if the socket says it is OK! Ask it! */
        int err;

        err = socketerror(sockfd);
        if ((0 == err) || (EISCONN == err)) {
          /* we are connected, awesome! */
          *connected = TRUE; /* this is truly a connect */
          break;
	}
        failf(data, "socket error: %d", err);
        /* we are _not_ connected, it was a false alert, continue please */
      }
      else if(2 == rc)
        /* waitconnect() returned error */
        ;
      else if(data->state.used_interface == Curl_if_multi) {
        /* When running the multi interface, we bail out here */
        rc = 0;
        break;
      }

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

      /* get a new timeout for next attempt */
      after = Curl_tvnow();
      timeout_ms -= Curl_tvdiff(after, before);
      if(timeout_ms < 0) {
        failf(data, "connect() timed out!");
        return CURLE_OPERATION_TIMEOUTED;
      }
      before = after;
      continue;
    }
    if (sockfd < 0)
      return CURLE_COULDNT_CONNECT;

    /* leave the socket in non-blocking mode */

    if(addr)
      *addr = ai; /* the address we ended up connected to */
  }
#else
  /*
   * Connecting with IPv4-only support
   */
  if(!remotehost->addr->h_addr_list[0]) {
    /* If there is no addresses in the address list, then we return
       error right away */
    failf(data, "no address available");
    return CURLE_COULDNT_CONNECT;
  }
  /* create an IPv4 TCP socket */
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == sockfd) {
    failf(data, "couldn't create socket");
    return CURLE_COULDNT_CONNECT; /* big time error */
  }
  
  if(conn->data->set.device) {
    /* user selected to bind the outgoing socket to a specified "device"
       before doing connect */
    CURLcode res = bindlocal(conn, sockfd);
    if(res)
      return res;
  }

  /* Convert socket to non-blocking type */
  Curl_nonblock(sockfd, TRUE);

  /* This is the loop that attempts to connect to all IP-addresses we
     know for the given host. One by one. */
  for(rc=-1, aliasindex=0;
      rc && (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
      aliasindex++) {
    struct sockaddr_in serv_addr;

    /* do this nasty work to do the connect */
    memset((char *) &serv_addr, '\0', sizeof(serv_addr));
    memcpy((char *)&(serv_addr.sin_addr),
           (struct in_addr *)remotehost->addr->h_addr_list[aliasindex],
           sizeof(struct in_addr));
    serv_addr.sin_family = remotehost->addr->h_addrtype;
    serv_addr.sin_port = htons((unsigned short)port);
  
    rc = connect(sockfd, (struct sockaddr *)&serv_addr,
                 sizeof(serv_addr));

    if(-1 == rc) {
      int error=Curl_ourerrno();

      switch (error) {
      case EINPROGRESS:
      case EWOULDBLOCK:
#if defined(EAGAIN) && 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
        /* asynchronous connect, wait for connect or timeout */
        if(data->state.used_interface == Curl_if_multi)
          /* don't hang when doing multi */
          timeout_ms = 0;

        rc = waitconnect(sockfd, timeout_ms);
        break;
      default:
        /* unknown error, fallthrough and try another address! */
        failf(data, "Failed to connect to %s IP number %d: %d",
              hostname, aliasindex+1, error);
        break;
      }
    }

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

    if(0 == rc) {
      int err = socketerror(sockfd);
      if ((0 == err) || (EISCONN == err)) {
        /* we are connected, awesome! */
        *connected = TRUE; /* this is a true connect */
        break;
      }
      /* nope, not connected for real */
      rc = -1;
    }

    if(0 != rc) {
      /* get a new timeout for next attempt */
      after = Curl_tvnow();
      timeout_ms -= Curl_tvdiff(after, before);
      if(timeout_ms < 0) {
        failf(data, "Connect timeout on IP number %d", aliasindex+1);
        break;
      }
      before = after;
      continue; /* try next address */
    }
    break;
  }
  if(0 != rc) {
    /* no good connect was made */
    sclose(sockfd);
    *sockconn = -1;
    failf(data, "Connect failed");
    return CURLE_COULDNT_CONNECT;
  }

  /* leave the socket in non-blocking mode */

  if(addr)
    /* this is the address we've connected to */
    *addr = (struct in_addr *)remotehost->addr->h_addr_list[aliasindex];
#endif

  /* allow NULL-pointers to get passed in */
  if(sockconn)
    *sockconn = sockfd;    /* the socket descriptor we've connected */

  return CURLE_OK;
}