Skip to content
Snippets Groups Projects
url.c 107 KiB
Newer Older
  • Learn to ignore specific revisions
  •     data->set.set_resume_from = va_arg(param, curl_off_t);
    
      case CURLOPT_DEBUGFUNCTION:
        /*
         * stderr write callback.
         */
        data->set.fdebug = va_arg(param, curl_debug_callback);
        /*
         * if the callback provided is NULL, it'll use the default callback
         */
        break;
      case CURLOPT_DEBUGDATA:
        /*
         * Set to a void * that should receive all error writes. This
         * defaults to CURLOPT_STDERR for normal operations.
         */
        data->set.debugdata = va_arg(param, void *);
    
      case CURLOPT_STDERR:
    
        /*
         * Set to a FILE * that should receive all error writes. This
         * defaults to stderr for normal operations.
         */
    
        data->set.err = va_arg(param, FILE *);
    
        if(!data->set.err)
          data->set.err = stderr;
    
      case CURLOPT_HEADERFUNCTION:
        /*
         * Set header write callback
         */
    
        data->set.fwrite_header = va_arg(param, curl_write_callback);
    
      case CURLOPT_WRITEFUNCTION:
    
        data->set.fwrite = va_arg(param, curl_write_callback);
    
        if(!data->set.fwrite)
          /* When set to NULL, reset to our internal default function */
          data->set.fwrite = (curl_write_callback)fwrite;
    
      case CURLOPT_READFUNCTION:
    
        data->set.fread = va_arg(param, curl_read_callback);
    
        if(!data->set.fread)
          /* When set to NULL, reset to our internal default function */
          data->set.fread = (curl_read_callback)fread;
    
      case CURLOPT_SSLCERT:
    
        /*
         * String that holds file name of the SSL certificate to use
         */
    
        data->set.cert = va_arg(param, char *);
    
      case CURLOPT_SSLCERTTYPE:
    
         * String that holds file type of the SSL certificate to use
    
        data->set.cert_type = va_arg(param, char *);
        break;
      case CURLOPT_SSLKEY:
        /*
         * String that holds file name of the SSL certificate to use
         */
        data->set.key = va_arg(param, char *);
        break;
      case CURLOPT_SSLKEYTYPE:
        /*
         * String that holds file type of the SSL certificate to use
         */
        data->set.key_type = va_arg(param, char *);
        break;
      case CURLOPT_SSLKEYPASSWD:
        /*
         * String that holds the SSL private key password.
         */
        data->set.key_passwd = va_arg(param, char *);
        break;
      case CURLOPT_SSLENGINE:
        /*
         * String that holds the SSL crypto engine.
         */
    #ifdef HAVE_OPENSSL_ENGINE_H
        {
          const char *cpTemp = va_arg(param, char *);
          ENGINE     *e;
          if (cpTemp && cpTemp[0]) {
            e = ENGINE_by_id(cpTemp);
            if (e) {
              if (data->engine) {
                ENGINE_free(data->engine);
              }
              data->engine = e;
            }
            else {
              failf(data, "SSL Engine '%s' not found", cpTemp);
              return CURLE_SSL_ENGINE_NOTFOUND;
            }
          }
        }
    
    #else
        return CURLE_SSL_ENGINE_NOTFOUND;
    #endif
      case CURLOPT_SSLENGINE_DEFAULT:
        /*
         * flag to set engine as default.
         */
    #ifdef HAVE_OPENSSL_ENGINE_H
        if (data->engine) {
          if (ENGINE_set_default(data->engine, ENGINE_METHOD_ALL) > 0) {
    #ifdef DEBUG
            fprintf(stderr,"set default crypto engine\n");
    #endif
          }
          else {
    #ifdef DEBUG
            failf(data, "set default crypto engine failed");
    #endif
            return CURLE_SSL_ENGINE_SETFAILED;
          }
        }
    #endif
    
      case CURLOPT_CRLF:
    
         * Kludgy option to enable CRLF convertions. Subject for removal.
    
        data->set.crlf = va_arg(param, long)?TRUE:FALSE;
    
      case CURLOPT_INTERFACE:
    
        /*
         * Set what interface to bind to when performing an operation and thus
         * what from-IP your connection will use.
         */
    
        data->set.device = va_arg(param, char *);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      case CURLOPT_KRB4LEVEL:
    
        /*
         * A string that defines the krb4 security level.
         */
    
        data->set.krb4_level = va_arg(param, char *);
        data->set.krb4=data->set.krb4_level?TRUE:FALSE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        break;
    
        data->set.ssl.verifypeer = va_arg(param, long);
    
      case CURLOPT_SSL_VERIFYHOST:
        /*
         * Enable verification of the CN contained in the peer certificate
         */
    
        data->set.ssl.verifyhost = va_arg(param, long);
    
      case CURLOPT_SSL_CTX_FUNCTION:
        /*
         * Set a SSL_CTX callback
         */
           data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
        break;
      case CURLOPT_SSL_CTX_DATA:
        /*
         * Set a SSL_CTX callback parameter pointer
         */
        data->set.ssl.fsslctxp = va_arg(param, void *);
        break;
    
        /*
         * Set CA info for SSL connection. Specify file name of the CA certificate
         */
    
        data->set.ssl.CAfile = va_arg(param, char *);
    
        break;
      case CURLOPT_CAPATH:
        /*
    
         * Set CA path info for SSL connection. Specify directory name of the CA
         * certificates which have been prepared using openssl c_rehash utility.
    
        /* This does not work on windows. */
        data->set.ssl.CApath = va_arg(param, char *);
    
      case CURLOPT_TELNETOPTIONS:
    
        /*
         * Set a linked list of telnet options
         */
    
        data->set.telnet_options = va_arg(param, struct curl_slist *);
    
    
      case CURLOPT_BUFFERSIZE:
        /*
         * The application kindly asks for a differently sized receive buffer.
         * If it seems reasonable, we'll use it.
         */
        data->set.buffer_size = va_arg(param, long);
    
    
        if((data->set.buffer_size> (BUFSIZE -1 )) ||
           (data->set.buffer_size < 1))
    
          data->set.buffer_size = 0; /* huge internal default */
    
        break;
    
    
      case CURLOPT_NOSIGNAL:
        /*
         * The application asks not to set any signal() or alarm() handlers,
         * even when using a timeout.
         */
        data->set.no_signal = va_arg(param, long) ? TRUE : FALSE;
        break;
    
    
          struct Curl_share *set;
          set = va_arg(param, struct Curl_share *);
    
    
          /* disconnect from old share, if any */
          if(data->share) {
    
            Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
    
            if(data->share->hostcache == data->hostcache)
              data->hostcache = NULL;
    
    
            if(data->share->cookies == data->cookies)
              data->cookies = NULL;
    
            data->share->dirty--;
    
            Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
    
          data->share = set;
    
          if(data->share) {
    
            Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
    
            if(data->share->hostcache) {
              /* use shared host cache, first free own one if any */
              if(data->hostcache)
                Curl_hash_destroy(data->hostcache);
    
              data->hostcache = data->share->hostcache;
            }
            
            if(data->share->cookies) {
              /* use shared cookie list, first free own one if any */
              if (data->cookies)
                Curl_cookie_cleanup(data->cookies);
              data->cookies = data->share->cookies;
            }
    
            Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
            
    
          /* check cookie list is set */
          if(!data->cookies)
    
            data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE );
    
          
          /* check for host cache not needed,
           * it will be done by curl_easy_perform */ 
    
      case CURLOPT_PROXYTYPE:
        /*
         * Set proxy type. HTTP/SOCKS4/SOCKS5
         */
    
        data->set.proxytype = (curl_proxytype)va_arg(param, long);
    
      case CURLOPT_PRIVATE:
        /*
         * Set private data pointer.
         */
        data->set.private = va_arg(param, char *);
        break;
    
    
      case CURLOPT_HTTP200ALIASES:
        /*
         * Set a list of aliases for HTTP 200 in response header
         */
        data->set.http200aliases = va_arg(param, struct curl_slist *);
        break;
    
      case CURLOPT_MAXFILESIZE:
        /*
         * Set the maximum size of a file to download.
         */
        data->set.max_filesize = va_arg(param, long);
        break;
    
    
      case CURLOPT_FTP_SSL:
        /*
         * Make FTP transfers attempt to use SSL/TLS.
         */
    
        data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long);
    
      case CURLOPT_IPRESOLVE:
        data->set.ip_version = va_arg(param, long);
        break;
    
    
      case CURLOPT_MAXFILESIZE_LARGE:
        /*
         * Set the maximum size of a file to download.
         */
    
        data->set.max_filesize = va_arg(param, curl_off_t);
    
      case CURLOPT_TCP_NODELAY:
        /*
         * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
         * algorithm
         */
    
        data->set.tcp_nodelay = (bool)va_arg(param, long);
    
      default:
        /* unknown tag and its companion, just ignore: */
    
        return CURLE_FAILED_INIT; /* correct this */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      return CURLE_OK;
    
    CURLcode Curl_disconnect(struct connectdata *conn)
    
      struct SessionHandle *data;
    
      if(!conn)
        return CURLE_OK; /* this is closed and fine already */
    
    
      /*
       * The range string is usually freed in curl_done(), but we might
       * get here *instead* if we fail prematurely. Thus we need to be able
       * to free this resource here as well.
       */
      if(conn->bits.rangestringalloc) {
        free(conn->range);
        conn->bits.rangestringalloc = FALSE;
      }
    
    
      if((conn->ntlm.state != NTLMSTATE_NONE) ||
    
         (conn->proxyntlm.state != NTLMSTATE_NONE)) {
    
        /* Authentication data is a mix of connection-related and sessionhandle-
           related stuff. NTLM is connection-related so when we close the shop
           we shall forget. */
    
        data->state.authhost.done = FALSE;
        data->state.authhost.picked = 
          data->state.authhost.want;
    
        data->state.authproxy.done = FALSE;
        data->state.authproxy.picked = 
          data->state.authhost.want;
    
        data->state.authproblem = FALSE;
      }
    
      if(conn->curl_disconnect)
        /* This is set if protocol-specific cleanups should be made */
        conn->curl_disconnect(conn);
    
    
      if(-1 != conn->connectindex) {
    
        infof(data, "Closing connection #%d\n", conn->connectindex);
        data->state.connects[conn->connectindex] = NULL;
    
      Curl_safefree(conn->proto.generic);
      Curl_safefree(conn->newurl);
    
      Curl_safefree(conn->pathbuffer); /* the URL path buffer */
    
    
      Curl_safefree(conn->host.rawalloc); /* host name buffer */
      Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
      if(conn->host.encalloc)
        (free)(conn->host.encalloc); /* encoded host name buffer, must be freed
                                        with free() since this was allocated by
                                        libidn */
      if(conn->proxy.encalloc)
        (free)(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed
                                         with free() since this was allocated by
                                         libidn */
    
    
      /* close possibly still open sockets */
    
      if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
    
      if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
    
      Curl_safefree(conn->user);
      Curl_safefree(conn->passwd);
      Curl_safefree(conn->proxyuser);
      Curl_safefree(conn->proxypasswd);
      Curl_safefree(conn->allocptr.proxyuserpwd);
      Curl_safefree(conn->allocptr.uagent);
      Curl_safefree(conn->allocptr.userpwd);
      Curl_safefree(conn->allocptr.accept_encoding);
      Curl_safefree(conn->allocptr.rangeline);
      Curl_safefree(conn->allocptr.ref);
      Curl_safefree(conn->allocptr.cookie);
      Curl_safefree(conn->allocptr.host);
      Curl_safefree(conn->allocptr.cookiehost);
    
    #if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
        defined(USE_THREADING_GETADDRINFO)
    
      /* possible left-overs from the async name resolve */
      Curl_safefree(conn->async.hostname);
    
      Curl_safefree(conn->async.os_specific);
    
      Curl_free_ssl_config(&conn->ssl_config);
    
      free(conn); /* free all the connection oriented data */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    /*
     * This function should return TRUE if the socket is to be assumed to
     * be dead. Most commonly this happens when the server has closed the
     * connection due to inactivity.
     */
    
    static bool SocketIsDead(curl_socket_t sock)
    
    {
      int sval;
      bool ret_val = TRUE;
      fd_set check_set;
      struct timeval to;
    
      FD_ZERO(&check_set);
    
      FD_SET(sock, &check_set);
    
      to.tv_sec = 0;
      to.tv_usec = 0;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
      sval = select(sock + 1, &check_set, 0, 0, &to);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* timeout */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      return ret_val;
    }
    
    
     * Given one filled in connection struct (named needle), this function should
     * detect if there already is one that have all the significant details
     * exactly the same and thus should be used instead.
    
    ConnectionExists(struct SessionHandle *data,
    
                     struct connectdata *needle,
                     struct connectdata **usethis)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      struct connectdata *check;
    
    
      for(i=0; i< data->state.numconnects; i++) {
    
        /*
         * Note that if we use a HTTP proxy, we check connections to that
         * proxy and not to the actual remote server.
         */
    
        if(!check)
          /* NULL pointer means not filled-in entry */
          continue;
    
    
        if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
          /* don't do mixed SSL and non-SSL connections */
          continue;
    
    
        if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
          /* The requested connection does not use a HTTP proxy or it
             uses SSL. */
    
          if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
            /* we don't do SSL but the cached connection has a proxy,
               then don't match this */
            continue;
    
    
          if(strequal(needle->protostr, check->protostr) &&
    
             strequal(needle->host.name, check->host.name) &&
    
             (needle->remote_port == check->remote_port) ) {
    
            if(needle->protocol & PROT_SSL) {
              /* This is SSL, verify that we're using the same
                 ssl options as well */
    
              if(!Curl_ssl_config_matches(&needle->ssl_config,
                                          &check->ssl_config)) {
    
            if((needle->protocol & PROT_FTP) ||
               ((needle->protocol & PROT_HTTP) &&
    
                (needle->data->state.authhost.want==CURLAUTH_NTLM))) {
    
              /* This is FTP or HTTP+NTLM, verify that we're using the same name
                 and password as well */
    
              if(!strequal(needle->user, check->user) ||
                 !strequal(needle->passwd, check->passwd)) {
    
                /* one of them was different */
                continue;
              }
            }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          }
    
        else { /* The requested needle connection is using a proxy,
                  is the checked one using the same? */
          if(check->bits.httpproxy &&
    
             strequal(needle->proxy.name, check->proxy.name) &&
    
             needle->port == check->port) {
            /* This is the same proxy connection, use it! */
    
          bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
    
          if(dead) {
            /*
             */
            infof(data, "Connection %d seems to be dead!\n", i);
            Curl_disconnect(check); /* disconnect resources */
            data->state.connects[i]=NULL; /* nothing here */
    
            /* There's no need to continue searching, because we only store
               one connection for each unique set of identifiers */
            return FALSE;
    
    
          *usethis = check;
          return TRUE; /* yes, we found one to use! */
    
      }
      return FALSE; /* no matching connecting exists */
    }
    
    /*
     * This function frees/closes a connection in the connection cache. This
     * should take the previously set policy into account when deciding which
     * of the connections to kill.
     */
    static int
    
    ConnectionKillOne(struct SessionHandle *data)
    
      struct connectdata *conn;
    
      int highscore=-1;
      int connindex=-1;
      int score;
    
      struct timeval now;
    
      now = Curl_tvnow();
    
      for(i=0; i< data->state.numconnects; i++) {
        conn = data->state.connects[i];
    
        if(!conn)
          continue;
    
        /*
         * By using the set policy, we score each connection.
         */
    
        case CURLCLOSEPOLICY_LEAST_RECENTLY_USED:
    
          /*
           * Set higher score for the age passed since the connection
           * was used.
           */
    
          score = Curl_tvdiff(now, conn->now);
    
          break;
        case CURLCLOSEPOLICY_OLDEST:
          /*
           * Set higher score for the age passed since the connection
           * was created.
           */
    
          score = Curl_tvdiff(now, conn->created);
    
          break;
        }
    
        if(score > highscore) {
          highscore = score;
          connindex = i;
        }
      }
      if(connindex >= 0) {
    
        /* the winner gets the honour of being disconnected */
    
        (void) Curl_disconnect(data->state.connects[connindex]);
    
    
        /* clean the array entry */
    
        data->state.connects[connindex] = NULL;
    
      }
    
      return connindex; /* return the available index or -1 */
    }
    
    /*
     * The given input connection struct pointer is to be stored. If the "cache"
     * is already full, we must clean out the most suitable using the previously
     * set policy.
     *
     * The given connection should be unique. That must've been checked prior to
     * this call.
     */
    static unsigned int
    
    ConnectionStore(struct SessionHandle *data,
    
                    struct connectdata *conn)
    {
    
      for(i=0; i< data->state.numconnects; i++) {
        if(!data->state.connects[i])
    
        /* there was no room available, kill one */
        i = ConnectionKillOne(data);
    
        infof(data, "Connection (#%d) was killed to make room\n", i);
      }
    
      if(-1 != i) {
        /* only do this if a true index was returned, if -1 was returned there
           is no room in the cache for an unknown reason and we cannot store
           this there. */
        data->state.connects[i] = conn; /* fill in this */
        conn->connectindex = i; /* make the child know where the pointer to this
                                   particular data is stored */
      }
    
    /*
     * This function logs in to a SOCKS5 proxy and sends the specifies the final
     * desitination server.
     */
    
    static int handleSock5Proxy(const char *proxy_name,
                                const char *proxy_password,
                                struct connectdata *conn)
    
      /*
        According to the RFC1928, section "6.  Replies". This is what a SOCK5
        replies:
    
            +----+-----+-------+------+----------+----------+
            |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
            +----+-----+-------+------+----------+----------+
            | 1  |  1  | X'00' |  1   | Variable |    2     |
            +----+-----+-------+------+----------+----------+
    
        Where:
    
        o  VER    protocol version: X'05'
        o  REP    Reply field:
        o  X'00' succeeded
      */
    
    
      unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
    
    
      Curl_nonblock(sock, FALSE);
    
      socksreq[0] = 5; /* version */
    
      socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
    
      socksreq[2] = 0; /* no authentication */
      socksreq[3] = 2; /* username/password */
    
    
      code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
    
      if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
    
        failf(conn->data, "Unable to send initial SOCKS5 request.");
        return 1;
      }
    
      result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
      if ((result != CURLE_OK) || (actualread != 2)) {
        failf(conn->data, "Unable to receive initial SOCKS5 response.");
        return 1;
      }
    
      if (socksreq[0] != 5) {
        failf(conn->data, "Received invalid version in initial SOCKS5 response.");
        return 1;
      }
      if (socksreq[1] == 0) {
        /* Nothing to do, no authentication needed */
        ;
      }
      else if (socksreq[1] == 2) {
        /* Needs user name and password */
        int userlen, pwlen, len;
    
        userlen = strlen(proxy_name);
    
        pwlen = proxy_password?strlen(proxy_password):0;
    
    
        /*   username/password request looks like
         * +----+------+----------+------+----------+
         * |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
         * +----+------+----------+------+----------+
         * | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
         * +----+------+----------+------+----------+
         */
        len = 0;
        socksreq[len++] = 1;    /* username/pw subnegotiation version */
        socksreq[len++] = (char) userlen;
        memcpy(socksreq + len, proxy_name, (int) userlen);
        len += userlen;
        socksreq[len++] = (char) pwlen;
        memcpy(socksreq + len, proxy_password, (int) pwlen);
        len += pwlen;
    
    
        code = Curl_write(conn, sock, (char *)socksreq, len, &written);
        if ((code != CURLE_OK) || (len != written)) {
    
          failf(conn->data, "Failed to send SOCKS5 sub-negotiation request.");
          return 1;
        }
    
        result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
        if ((result != CURLE_OK) || (actualread != 2)) {
          failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response.");
          return 1;
        }
    
    
        if ((socksreq[0] != 5) || /* version */
    
            (socksreq[1] != 0)) { /* status */
          failf(conn->data, "User was rejected by the SOCKS5 server (%d %d).",
                socksreq[0], socksreq[1]);
          return 1;
        }
    
        /* Everything is good so far, user was authenticated! */
      }
      else {
        /* error */
        if (socksreq[1] == 1) {
          failf(conn->data,
                "SOCKS5 GSSAPI per-message authentication is not supported.");
          return 1;
        }
        else if (socksreq[1] == 255) {
          if (proxy_name[0] == 0) {
            failf(conn->data,
                  "No authentication method was acceptable. (It is quite likely"
                  " that the SOCKS5 server wanted a username/password, since none"
                  " was supplied to the server on this connection.)");
          }
    
          else {
    
            failf(conn->data, "No authentication method was acceptable.");
          }
          return 1;
        }
        else {
          failf(conn->data,
                "Undocumented SOCKS5 mode attempted to be used by server.");
          return 1;
        }
      }
    
      /* Authentication is complete, now specify destination to the proxy */
      socksreq[0] = 5; /* version (SOCKS5) */
      socksreq[1] = 1; /* connect */
      socksreq[2] = 0; /* must be zero */
      socksreq[3] = 1; /* IPv4 = 1 */
    
    #ifndef ENABLE_IPV6
        struct Curl_dns_entry *dns;
        Curl_addrinfo *hp=NULL;
    
        int rc = Curl_resolv(conn, conn->host.name, conn->remote_port, &dns);
    
          /* this requires that we're in "wait for resolve" state */
          rc = Curl_wait_for_resolv(conn, &dns);
        
    
        /*
         * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
         * returns a Curl_addrinfo pointer that may not always look the same.
         */
    
        if (hp && hp->h_addr_list[0]) {
          socksreq[4] = ((char*)hp->h_addr_list[0])[0];
          socksreq[5] = ((char*)hp->h_addr_list[0])[1];
          socksreq[6] = ((char*)hp->h_addr_list[0])[2];
          socksreq[7] = ((char*)hp->h_addr_list[0])[3];
    
          Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */
    
        }
        else {
          failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
    
          return 1;
        }
    #else
        failf(conn->data,
              "%s:%d has an internal error an needs to be fixed to work",
              __FILE__, __LINE__);
    #endif
      }
    
      *((unsigned short*)&socksreq[8]) = htons(conn->remote_port);
    
      {
        const int packetsize = 10;
    
    
        code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
        if ((code != CURLE_OK) || (written != packetsize)) {
    
          failf(conn->data, "Failed to send SOCKS5 connect request.");
          return 1;
        }
    
        result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
        if ((result != CURLE_OK) || (actualread != packetsize)) {
          failf(conn->data, "Failed to receive SOCKS5 connect request ack.");
          return 1;
        }
    
        if (socksreq[0] != 5) { /* version */
          failf(conn->data,
                "SOCKS5 reply has wrong version, version should be 5.");
          return 1;
        }
        if (socksreq[1] != 0) { /* Anything besides 0 is an error */
            failf(conn->data,
                  "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
                  (unsigned char)socksreq[4], (unsigned char)socksreq[5],
                  (unsigned char)socksreq[6], (unsigned char)socksreq[7],
                  (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
                  socksreq[1]);
            return 1;
        }
      }
    
      Curl_nonblock(sock, TRUE);
      return 0; /* Proxy was successful! */
    }
    
    
    static CURLcode ConnectPlease(struct connectdata *conn,
    
      CURLcode result;
      Curl_ipconnect *addr;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /*************************************************************
    
       * Connect to server/proxy
    
       *************************************************************/
    
      result= Curl_connecthost(conn,
    
                               conn->port,
    
      if(CURLE_OK == result) {
        /* All is cool, then we store the current information from the hostaddr
           struct to the serv_addr, as it might be needed later. The address
           returned from the function above is crucial here. */
    
    #ifdef ENABLE_IPV6
        conn->serv_addr = addr;
    #else
        memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
        memcpy((char *)&(conn->serv_addr.sin_addr),
               (struct in_addr *)addr, sizeof(struct in_addr));
    
        conn->serv_addr.sin_family = hostaddr->addr->h_addrtype;
    
        conn->serv_addr.sin_port = htons((unsigned short)conn->port);
    
    
        if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
    
          return handleSock5Proxy(conn->proxyuser,
                                  conn->proxypasswd,
    
            CURLE_COULDNT_CONNECT : CURLE_OK;
        }
        else if (conn->data->set.proxytype == CURLPROXY_HTTP) {
          /* do nothing here. handled later. */
        }
        else {
          failf(conn->data, "unknown proxytype option given");
    
          return CURLE_COULDNT_CONNECT;
    
      return result;
    
     * verboseconnect() displays verbose information after a connect
    
    static void verboseconnect(struct connectdata *conn)
    
      /* Get a printable version of the network address. */
    
      struct addrinfo *ai = conn->serv_addr;
      host = Curl_printable_address(ai->ai_family, ai->ai_addr,
                                    addrbuf, sizeof(addrbuf));
    
      struct in_addr in;
      (void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
      host = Curl_inet_ntop(AF_INET, &in, addrbuf, sizeof(addrbuf));
    
      infof(data, "Connected to %s (%s) port %d\n",
    
            conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname,
    
    /*
     * We have discovered that the TCP connection has been successful, we can now
     * proceed with some action.
     *
     * If we're using the multi interface, this host address pointer is most
     * likely NULL at this point as we can't keep the resolved info around. This
     * may call for some reworking, like a reference counter in the struct or
    
    CURLcode Curl_protocol_connect(struct connectdata *conn)
    
    {
      struct SessionHandle *data = conn->data;
    
      if(conn->bits.tcpconnect)
        /* We already are connected, get back. This may happen when the connect
           worked fine in the first call, like when we connect to a local server
           or proxy. */
        return CURLE_OK;
    
    
      Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
    
      if(data->set.verbose)
    
    
      if(conn->curl_connect) {
        /* is there a protocol-specific connect() procedure? */
    
        /* set start time here for timeout purposes in the
         * connect procedure, it is later set again for the
         * progress meter purpose */
        conn->now = Curl_tvnow();
    
        /* Call the protocol-specific connect function */
        result = conn->curl_connect(conn);
      }
    
      return result; /* pass back status */
    }
    
    
    /*
     * Helpers for IDNA convertions.
     */
    #ifdef USE_LIBIDN
    static bool is_ASCII_name (const char *hostname)
    {
      const unsigned char *ch = (const unsigned char*)hostname;
    
      while (*ch) {
        if (*ch++ & 0x80)
          return FALSE;
      }
      return TRUE;
    }
    #endif
    
    static void fix_hostname(struct connectdata *conn, struct hostname *host)
    {
      /* set the name we use to display the host name */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      host->dispname = host->name;
    
    
    #ifdef USE_LIBIDN
      /*************************************************************
       * Check name for non-ASCII and convert hostname to ACE form.
       *************************************************************/
      if (!is_ASCII_name(host->name)) {
        char *ace_hostname = NULL;
        struct SessionHandle *data = conn->data;
        int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
        infof (data, "Input domain encoded as `%s'\n",
               stringprep_locale_charset ());
        if (rc != IDNA_SUCCESS)
          infof(data, "Failed to convert %s to ACE; IDNA error %d\n",
                host->name, rc);
        else {