Skip to content
Snippets Groups Projects
url.c 55.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Stenberg's avatar
    Daniel Stenberg committed
    /*****************************************************************************
     *                                  _   _ ____  _     
     *  Project                     ___| | | |  _ \| |    
     *                             / __| | | | |_) | |    
     *                            | (__| |_| |  _ <| |___ 
     *                             \___|\___/|_| \_\_____|
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * In order to be useful for every potential user, curl and libcurl are
     * dual-licensed under the MPL and the MIT/X-derivate licenses.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     * copies of the Software, and permit persons to whom the Software is
     * furnished to do so, under the terms of the MPL or the MIT/X-derivate
     * licenses. You may pick one of these licenses.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     * KIND, either express or implied.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * $Id$
     *****************************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    /* -- WIN32 approved -- */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #include <stdio.h>
    #include <string.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #include <errno.h>
    
    #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
    #include <winsock.h>
    #include <time.h>
    #include <io.h>
    #else
    #ifdef HAVE_SYS_SOCKET_H
    #include <sys/socket.h>
    #endif
    #include <netinet/in.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #include <netdb.h>
    #ifdef HAVE_ARPA_INET_H
    #include <arpa/inet.h>
    #endif
    #ifdef HAVE_NET_IF_H
    #include <net/if.h>
    #endif
    #include <sys/ioctl.h>
    #include <signal.h>
    
    #ifdef HAVE_SYS_PARAM_H
    #include <sys/param.h>
    #endif
    
    #ifdef HAVE_SYS_SELECT_H
    #include <sys/select.h>
    #endif
    
    #ifndef HAVE_SELECT
    #error "We can't compile without select() support!"
    #endif
    #ifndef HAVE_SOCKET
    #error "We can't compile without socket() support!"
    #endif
    
    #endif
    
    #include "urldata.h"
    #include "netrc.h"
    
    #include "formdata.h"
    #include "base64.h"
    #include "ssluse.h"
    #include "hostip.h"
    #include "if2ip.h"
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #include "sendf.h"
    #include "getpass.h"
    #include "progress.h"
    #include "cookie.h"
    
    #include "strequal.h"
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    /* And now for the protocols */
    #include "ftp.h"
    #include "dict.h"
    #include "telnet.h"
    #include "http.h"
    #include "file.h"
    #include "ldap.h"
    
    
    #include <curl/types.h>
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    #define _MPRINTF_REPLACE /* use our functions only */
    #include <curl/mprintf.h>
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef KRB4
    #include "security.h"
    #endif
    
    /* The last #include file should be: */
    #ifdef MALLOCDEBUG
    #include "memdebug.h"
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    /* Local static prototypes */
    static int ConnectionKillOne(struct UrlData *data);
    static bool ConnectionExists(struct UrlData *data,
                                 struct connectdata *needle,
                                 struct connectdata **usethis);
    static unsigned int ConnectionStore(struct UrlData *data,
                                        struct connectdata *conn);
    
    CURLcode Curl_close(CURL *curl)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      struct UrlData *data=(struct UrlData *)curl;
      
      /* Loop through all open connections and kill them one by one */
      while(-1 != ConnectionKillOne(data));
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if(data->bits.proxystringalloc) {
    
        data->bits.proxystringalloc=FALSE;;
    
        free(data->proxy);
        data->proxy=NULL;
    
    
        /* Since we allocated the string the previous round, it means that we
           "discovered" the proxy in the environment variables and thus we must
           switch off that knowledge again... */
        data->bits.httpproxy=FALSE;
    
      if(data->bits.rangestringalloc) {
        free(data->range);
        data->range=NULL;
    
        data->bits.rangestringalloc=0; /* free now */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /* check for allocated [URL] memory to free: */
      if(data->freethis)
        free(data->freethis);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if(data->headerbuff)
        free(data->headerbuff);
    
      if(data->free_referer)
        free(data->referer);
    
      if(data->bits.urlstringalloc)
        /* the URL is allocated, free it! */
        free(data->url);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      Curl_cookie_cleanup(data->cookies);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /* free the connection cache */
      free(data->connects);
    
      return CURLE_OK;
    }
    
    int my_getpass(void *clientp, char *prompt, char* buffer, int buflen )
    {
    
      char *retbuf;
      retbuf = getpass_r(prompt, buffer, buflen);
      if(NULL == retbuf)
        return 1;
      else
        return 0; /* success */
    
    CURLcode Curl_open(CURL **curl, char *url)
    
    {
      /* We don't yet support specifying the URL at this point */
    
      struct UrlData *data;
    
    
      /* Very simple start-up: alloc the struct, init it with zeroes and return */
    
      data = (struct UrlData *)malloc(sizeof(struct UrlData));
    
        memset(data, 0, sizeof(struct UrlData));
    
        /* We do some initial setup here, all those fields that can't be just 0 */
    
        data-> headerbuff=(char*)malloc(HEADERSIZE);
        if(!data->headerbuff) {
          free(data); /* free the memory again */
          return CURLE_OUT_OF_MEMORY;
        }
    
    
    
        data->out = stdout; /* default output to stdout */
        data->in  = stdin;  /* default input from stdin */
        data->err  = stderr;  /* default stderr to stderr */
    
        /* use fwrite as default function to store output */
        data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite;
    
        /* use fread as default function to read input */
        data->fread = (size_t (*)(char *, size_t, size_t, FILE *))fread;
    
    
        /* set the default passwd function */
        data->fpasswd = my_getpass;
    
    
        data->infilesize = -1; /* we don't know any size */
    
        data->current_speed = -1; /* init to negative == impossible */
    
    
        data->httpreq = HTTPREQ_GET; /* Default HTTP request */
    
    
        /* create an array with connection data struct pointers */
        data->numconnects = 5; /* hard-coded right now */
        data->connects = (struct connectdata **)
          malloc(sizeof(struct connectdata *) * data->numconnects);
    
        if(!data->connects) {
          free(data);
          return CURLE_OUT_OF_MEMORY;
        }
    
        memset(data->connects, 0, sizeof(struct connectdata *)*data->numconnects);
    
    
        return CURLE_OK;
    
      }
    
      /* this is a very serious error */
    
      return CURLE_OUT_OF_MEMORY;
    
    CURLcode Curl_setopt(CURL *curl, CURLoption option, ...)
    
    {
      struct UrlData *data = curl;
      va_list param;
      char *cookiefile;
    
      va_start(param, option);
    
      switch(option) {
    
      case CURLOPT_VERBOSE:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.verbose = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_HEADER:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_include_header = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_NOPROGRESS:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.hide_progress = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.hide_progress)
          data->progress.flags |= PGRS_HIDE;
        break;
      case CURLOPT_NOBODY:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.no_body = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FAILONERROR:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_UPLOAD:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.upload = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.upload)
          /* If this is HTTP, PUT is what's needed to "upload" */
          data->httpreq = HTTPREQ_PUT;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      case CURLOPT_FILETIME:
        data->bits.get_filetime = va_arg(param, long)?TRUE:FALSE;
        break;
    
      case CURLOPT_FTPLISTONLY:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FTPAPPEND:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.ftp_append = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_NETRC:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.use_netrc = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FOLLOWLOCATION:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_follow_location = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_FTPASCII:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_PUT:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.http_put = va_arg(param, long)?TRUE:FALSE;
    
        if(data->bits.http_put)
          data->httpreq = HTTPREQ_PUT;
    
        break;
      case CURLOPT_MUTE:
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        data->bits.mute = va_arg(param, long)?TRUE:FALSE;
    
        break;
      case CURLOPT_TIMECONDITION:
    
        data->timecondition = va_arg(param, long);
        break;
    
      case CURLOPT_TIMEVALUE:
    
        data->timevalue = va_arg(param, long);
        break;
    
      case CURLOPT_SSLVERSION:
    
        data->ssl.version = va_arg(param, long);
    
      case CURLOPT_COOKIEFILE:
    
        cookiefile = (char *)va_arg(param, void *);
        if(cookiefile) {
    
          data->cookies = Curl_cookie_init(cookiefile);
    
      case CURLOPT_WRITEHEADER:
    
        data->writeheader = (FILE *)va_arg(param, FILE *);
        break;
    
      case CURLOPT_COOKIE:
    
        data->cookie = va_arg(param, char *);
        break;
    
      case CURLOPT_ERRORBUFFER:
    
        data->errorbuffer = va_arg(param, char *);
        break;
    
      case CURLOPT_FILE:
    
        data->out = va_arg(param, FILE *);
        break;
    
      case CURLOPT_FTPPORT:
    
        data->ftpport = va_arg(param, char *);
    
        data->bits.ftp_use_port = data->ftpport?1:0;
    
      case CURLOPT_HTTPHEADER:
    
        data->headers = va_arg(param, struct curl_slist *);
    
      case CURLOPT_CUSTOMREQUEST:
    
        data->customrequest = va_arg(param, char *);
    
        if(data->customrequest)
          data->httpreq = HTTPREQ_CUSTOM;
    
      case CURLOPT_HTTPPOST:
    
        data->httppost = va_arg(param, struct HttpPost *);
    
        data->bits.http_formpost = data->httppost?1:0;
    
        if(data->bits.http_formpost)
          data->httpreq = HTTPREQ_POST_FORM;
    
      case CURLOPT_INFILE:
    
        data->in = va_arg(param, FILE *);
        break;
    
      case CURLOPT_INFILESIZE:
    
        data->infilesize = va_arg(param, long);
        break;
    
      case CURLOPT_LOW_SPEED_LIMIT:
    
        data->low_speed_limit=va_arg(param, long);
        break;
    
      case CURLOPT_LOW_SPEED_TIME:
    
        data->low_speed_time=va_arg(param, long);
        break;
    
      case CURLOPT_URL:
    
        data->url = va_arg(param, char *);
        break;
    
      case CURLOPT_PORT:
    
        data->use_port = va_arg(param, long);
    
      case CURLOPT_POST:
        /* Does this option serve a purpose anymore? */
        data->bits.http_post = va_arg(param, long)?TRUE:FALSE;
        if(data->bits.http_post)
          data->httpreq = HTTPREQ_POST;
        break;
    
      case CURLOPT_POSTFIELDS:
    
        data->postfields = va_arg(param, char *);
    
        data->bits.http_post = data->postfields?TRUE:FALSE;
        if(data->bits.http_post)
          data->httpreq = HTTPREQ_POST;
    
      case CURLOPT_POSTFIELDSIZE:
        data->postfieldsize = va_arg(param, long);
        break;
    
      case CURLOPT_REFERER:
    
        data->referer = va_arg(param, char *);
    
        data->bits.http_set_referer = (data->referer && *data->referer)?1:0;
    
      case CURLOPT_AUTOREFERER:
        data->bits.http_auto_referer = va_arg(param, long)?1:0;
        break;
    
      case CURLOPT_PROXY:
    
        data->proxy = va_arg(param, char *);
    
        data->bits.httpproxy = data->proxy?1:0;
    
      case CURLOPT_HTTPPROXYTUNNEL:
        data->bits.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
        break;
    
      case CURLOPT_PROXYPORT:
        data->proxyport = va_arg(param, long);
    
      case CURLOPT_TIMEOUT:
    
        data->timeout = va_arg(param, long);
        break;
    
      case CURLOPT_MAXREDIRS:
        data->maxredirs = va_arg(param, long);
        break;
    
      case CURLOPT_USERAGENT:
    
        data->useragent = va_arg(param, char *);
        break;
    
      case CURLOPT_USERPWD:
    
        data->userpwd = va_arg(param, char *);
    
        data->bits.user_passwd = data->userpwd?1:0;
    
      case CURLOPT_POSTQUOTE:
    
        data->postquote = va_arg(param, struct curl_slist *);
        break;
    
      case CURLOPT_PROGRESSFUNCTION:
        data->fprogress = va_arg(param, curl_progress_callback);
    
        data->progress.callback = TRUE; /* no longer internal */
    
        break;
      case CURLOPT_PROGRESSDATA:
        data->progress_client = va_arg(param, void *);
        break;
    
      case CURLOPT_PASSWDFUNCTION:
        data->fpasswd = va_arg(param, curl_passwd_callback);
        break;
      case CURLOPT_PASSWDDATA:
        data->passwd_client = va_arg(param, void *);
        break;
    
      case CURLOPT_PROXYUSERPWD:
    
        data->proxyuserpwd = va_arg(param, char *);
    
        data->bits.proxy_user_passwd = data->proxyuserpwd?1:0;
    
      case CURLOPT_RANGE:
    
        data->range = va_arg(param, char *);
    
        data->bits.set_range = data->range?1:0;
    
      case CURLOPT_RESUME_FROM:
    
        data->resume_from = va_arg(param, long);
        break;
    
      case CURLOPT_STDERR:
    
        data->err = va_arg(param, FILE *);
        break;
    
      case CURLOPT_WRITEFUNCTION:
    
        data->fwrite = va_arg(param, curl_write_callback);
    
      case CURLOPT_READFUNCTION:
    
        data->fread = va_arg(param, curl_read_callback);
    
      case CURLOPT_SSLCERT:
    
        data->cert = va_arg(param, char *);
        break;
    
      case CURLOPT_SSLCERTPASSWD:
    
        data->cert_passwd = va_arg(param, char *);
        break;
    
      case CURLOPT_CRLF:
    
        data->crlf = va_arg(param, long);
        break;
    
      case CURLOPT_QUOTE:
    
        data->quote = va_arg(param, struct curl_slist *);
        break;
    
      case CURLOPT_INTERFACE:
        data->device = va_arg(param, char *);
        break;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      case CURLOPT_KRB4LEVEL:
        data->krb4_level = va_arg(param, char *);
        data->bits.krb4=data->krb4_level?TRUE:FALSE;
        break;
    
      case CURLOPT_SSL_VERIFYPEER:
        data->ssl.verifypeer = va_arg(param, long);
        break;
      case CURLOPT_CAINFO:
        data->ssl.CAfile = va_arg(param, char *);
        data->ssl.CApath = NULL; /*This does not work on windows.*/
        break;
    
      case CURLOPT_TELNETOPTIONS:
        data->telnet_options = va_arg(param, struct curl_slist *);
        break;
    
      default:
        /* unknown tag and its companion, just ignore: */
    
        return CURLE_READ_ERROR; /* correct this */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      }
    
      return CURLE_OK;
    
    #if !defined(WIN32)||defined(__CYGWIN32__)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifndef RETSIGTYPE
    #define RETSIGTYPE void
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    RETSIGTYPE alarmfunc(int signal)
    {
      /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
      (void)signal;
      return;
    }
    #endif
    
    
    CURLcode Curl_disconnect(struct connectdata *conn)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(conn->curl_disconnect)
        /* This is set if protocol-specific cleanups should be made */
        conn->curl_disconnect(conn);
    
    
      if(conn->proto.generic)
        free(conn->proto.generic);
    
    #ifdef ENABLE_IPV6
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(conn->hp) /* host name info */
        freeaddrinfo(conn->hp);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      if(conn->hostent_buf) /* host name info */
        free(conn->hostent_buf);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      if(conn->path) /* the URL path part */
        free(conn->path);
    
    
    #ifdef USE_SSLEAY
      if (conn->ssl.use) {
        if(conn->ssl.handle) {
          (void)SSL_shutdown(conn->ssl.handle);
          SSL_set_connect_state(conn->ssl.handle);
    
          SSL_free (conn->ssl.handle);
          conn->ssl.handle = NULL;
        }
        if(conn->ssl.ctx) {
          SSL_CTX_free (conn->ssl.ctx);
          conn->ssl.ctx = NULL;
        }
        conn->ssl.use = FALSE; /* get back to ordinary socket usage */
      }
    #endif /* USE_SSLEAY */
    
      /* close possibly still open sockets */
    
      if(-1 != conn->secondarysocket)
    
        sclose(conn->secondarysocket);
    
      if(-1 != conn->firstsocket)
    
        sclose(conn->firstsocket);
    
    
      if(conn->allocptr.proxyuserpwd)
        free(conn->allocptr.proxyuserpwd);
      if(conn->allocptr.uagent)
        free(conn->allocptr.uagent);
      if(conn->allocptr.userpwd)
        free(conn->allocptr.userpwd);
      if(conn->allocptr.rangeline)
        free(conn->allocptr.rangeline);
      if(conn->allocptr.ref)
        free(conn->allocptr.ref);
      if(conn->allocptr.cookie)
        free(conn->allocptr.cookie);
      if(conn->allocptr.host)
        free(conn->allocptr.host);
    
    
      if(conn->proxyhost)
        free(conn->proxyhost);
    
    
      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(int 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 = 1; 
    
      sval = select(sock + 1, &check_set, 0, 0, &to);
      if(sval == 0) 
        /* timeout */
        ret_val = FALSE; 
      
      return ret_val;
    }
    
    
    /*
     * Given one filled in connection struct, this function should detect if there
     * already is one that have all the significant details exactly the same and
     * thus should be used instead.
     */
    static bool
    ConnectionExists(struct UrlData *data,
                     struct connectdata *needle,
                     struct connectdata **usethis)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      size_t i;
      struct connectdata *check;
    
      for(i=0; i< data->numconnects; i++) {
        /*
         * Note that if we use a HTTP proxy, we check connections to that
         * proxy and not to the actual remote server.
         */
        check = data->connects[i];
        if(!check)
          /* NULL pointer means not filled-in entry */
          continue;
    
        if(!needle->bits.httpproxy) {
          /* The requested connection does not use a HTTP proxy */
    
          if(strequal(needle->protostr, check->protostr) &&
             strequal(needle->name, check->name) &&
             (needle->port == check->port) ) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            bool dead;
    
            if(strequal(needle->protostr, "FTP")) {
              /* This is FTP, verify that we're using the same name and
                 password as well */
              if(!strequal(needle->data->user, check->proto.ftp->user) ||
                 !strequal(needle->data->passwd, check->proto.ftp->passwd)) {
                /* one of them was different */
                continue;
              }
            }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
            dead = SocketIsDead(check->firstsocket);
            if(dead) {
              infof(data, "Connection %d seems to be dead!\n", i);
    
              Curl_disconnect(check); /* disconnect resources */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
              data->connects[i]=NULL; /* nothing here */
              continue; /* try another one now */
            }
          }
    
          *usethis = check;
          return TRUE; /* yes, we found one to use! */
        }
    
        else { /* The requested needle connection is using a proxy,
                  is the checked one using the same? */
          if(check->bits.httpproxy &&
             strequal(needle->proxyhost, check->proxyhost) &&
             needle->port == check->port) {
            /* This is the same proxy connection, use it! */
            *usethis = check;
            return TRUE;
          }
        }
    
      }
      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 UrlData *data)
    {
      size_t i;
    
      struct connectdata *conn;
    
      int highscore=-1;
      int connindex=-1;
      int score;
      CURLcode result;
    
      for(i=0; i< data->numconnects; i++) {
        conn = data->connects[i];
        
        if(!conn)
          continue;
    
        /*
         * By using the set policy, we score each connection.
         */
        switch(data->closepolicy) {
        default:
          score = 1; /* not implemented yet */
          break;
        }
    
        if(score > highscore) {
          highscore = score;
          connindex = i;
        }
      }
      if(connindex >= 0) {
    
        /* the winner gets the honour of being disconnected */
    
        result = Curl_disconnect(data->connects[connindex]);
    
    
        /* clean the array entry */
        data->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 UrlData *data,
                    struct connectdata *conn)
    {
      size_t i;
      for(i=0; i< data->numconnects; i++) {
        if(!data->connects[i])
          break;
      }
    
      if(i == data->numconnects) {
    
        /* there was no room available, kill one */
        i = ConnectionKillOne(data);
    
        infof(data, "Connection (#%d) was killed to make room\n", i);
      }
    
    
      data->connects[i] = conn; /* fill in this */
      conn->connectindex = i; /* make the child know where the pointer to this
                                 particular data is stored */
    
      return i;
    }
    
    static CURLcode ConnectPlease(struct UrlData *data,
                                  struct connectdata *conn)
    {
    
    #ifndef ENABLE_IPV6
      conn->firstsocket = socket(AF_INET, SOCK_STREAM, 0);
    
      memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
      memcpy((char *)&(conn->serv_addr.sin_addr),
             conn->hp->h_addr, conn->hp->h_length);
      conn->serv_addr.sin_family = conn->hp->h_addrtype;
    
      conn->serv_addr.sin_port = htons(conn->port);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #else
      /* IPv6-style */
      struct addrinfo *ai;
    
    
    #if !defined(WIN32)||defined(__CYGWIN32__)
      /* We don't generally like checking for OS-versions, we should make this
         HAVE_XXXX based, although at the moment I don't have a decent test for
         this! */
    
    #ifdef HAVE_INET_NTOA
    
    #ifndef INADDR_NONE
    #define INADDR_NONE (unsigned long) ~0
    
    #ifndef ENABLE_IPV6
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
    
       * Select device to bind socket to
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
       *************************************************************/
    
      if (data->device && (strlen(data->device)<255)) {
        struct sockaddr_in sa;
        struct hostent *h=NULL;
        char *hostdataptr=NULL;
        size_t size;
        char myhost[256] = "";
        unsigned long in;
    
        if(Curl_if2ip(data->device, myhost, sizeof(myhost))) {
          h = Curl_gethost(data, myhost, &hostdataptr);
        }
        else {
          if(strlen(data->device)>1) {
            h = Curl_gethost(data, data->device, &hostdataptr);
          }
          if(h) {
            /* we know data->device is shorter than the myhost array */
            strcpy(myhost, data->device);
          }
        }
    
        if(! *myhost) {
          /* need to fix this
             h=Curl_gethost(data,
             getmyhost(*myhost,sizeof(myhost)),
             hostent_buf,
             sizeof(hostent_buf));
          */
          printf("in here\n");
        }
    
        infof(data, "We connect from %s\n", myhost);
    
        if ( (in=inet_addr(myhost)) != INADDR_NONE ) {
    
          if ( h ) {
            memset((char *)&sa, 0, sizeof(sa));
            memcpy((char *)&sa.sin_addr,
                   h->h_addr,
                   h->h_length);
            sa.sin_family = AF_INET;
            sa.sin_addr.s_addr = in;
            sa.sin_port = 0; /* get any port */
    	
            if( bind(conn->firstsocket, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
              /* we succeeded to bind */
              struct sockaddr_in add;
    	
              size = sizeof(add);
              if(getsockname(conn->firstsocket, (struct sockaddr *) &add,
    
                             (socklen_t *)&size)<0) {
    
                failf(data, "getsockname() failed");
                return CURLE_HTTP_PORT_FAILED;
              }
            }
            else {
              switch(errno) {
              case EBADF:
                failf(data, "Invalid descriptor: %d", errno);
                break;
              case EINVAL:
                failf(data, "Invalid request: %d", errno);
                break;
              case EACCES:
                failf(data, "Address is protected, user not superuser: %d", errno);
                break;
              case ENOTSOCK:
                failf(data,
                      "Argument is a descriptor for a file, not a socket: %d",
                      errno);
                break;
              case EFAULT:
                failf(data, "Inaccessable memory error: %d", errno);
                break;
              case ENAMETOOLONG:
                failf(data, "Address too long: %d", errno);
                break;
              case ENOMEM:
                failf(data, "Insufficient kernel memory was available: %d", errno);
                break;
              default:
                failf(data,"errno %d\n");
              } /* end of switch */
    	
              return CURLE_HTTP_PORT_FAILED;
            } /* end of else */
    	
          } /* end of if  h */
          else {
    	failf(data,"could't find my own IP address (%s)", myhost);
    	return CURLE_HTTP_PORT_FAILED;
          }
        } /* end of inet_addr */
    
        else {
          failf(data, "could't find my own IP address (%s)", myhost);
          return CURLE_HTTP_PORT_FAILED;
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
        if(hostdataptr)
          free(hostdataptr); /* allocated by Curl_gethost() */
    
      } /* end of device selection support */
    #endif  /* end of HAVE_INET_NTOA */
    #endif /* end of not WIN32 */
    #endif /*ENABLE_IPV6*/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /*************************************************************
    
       * Connect to server/proxy
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
       *************************************************************/
    
    #ifdef ENABLE_IPV6
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      conn->firstsocket = -1;
      for (ai = conn->hp; ai; ai = ai->ai_next) {
        conn->firstsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        if (conn->firstsocket < 0)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        if (connect(conn->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
          close(conn->firstsocket);
          conn->firstsocket = -1;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      conn->ai = ai;
      if (conn->firstsocket < 0) {
    
        failf(data, strerror(errno));
        return CURLE_COULDNT_CONNECT;
      }
    #else
      if (connect(conn->firstsocket,
                  (struct sockaddr *) &(conn->serv_addr),
                  sizeof(conn->serv_addr)
                  ) < 0) {
        switch(errno) {
    #ifdef ECONNREFUSED
          /* this should be made nicer */
        case ECONNREFUSED:
          failf(data, "Connection refused");
          break;
        case EFAULT:
          failf(data, "Invalid socket address: %d",errno);
          break;
        case EISCONN:
          failf(data, "Socket already connected: %d",errno);
          break;
        case ETIMEDOUT:
          failf(data, "Timeout while accepting connection, server busy: %d",errno);
          break;
        case ENETUNREACH:
          failf(data, "Network is unreachable: %d",errno);
          break;
        case EADDRINUSE:
          failf(data, "Local address already in use: %d",errno);
          break;
        case EINPROGRESS:
          failf(data, "Socket is nonblocking and connection can not be completed immediately: %d",errno);
          break;
        case EALREADY:
          failf(data, "Socket is nonblocking and a previous connection attempt not completed: %d",errno);
          break;
        case EAGAIN:
          failf(data, "No more free local ports: %d",errno);
          break;
        case EACCES:
        case EPERM:
          failf(data, "Attempt to connect to broadcast address without socket broadcast flag or local firewall rule violated: %d",errno);
          break;
    #endif
        case EINTR:
          failf(data, "Connection timed out");
          break;
        default:
          failf(data, "Can't connect to server: %d", errno);
          break;
        }
        return CURLE_COULDNT_CONNECT;
      }
    #endif
    
      return CURLE_OK;
    }
    
    
    static CURLcode Connect(struct UrlData *data,
                            struct connectdata **in_connect,
                            bool allow_port) /* allow data->use_port ? */
    
    {
      char *tmp;
      char *buf;
      CURLcode result;
      char resumerange[40]="";
      struct connectdata *conn;
      struct connectdata *conn_temp;
      char endbracket;
    
      struct sigaction sigact;
    
      /*************************************************************
       * Check input data
       *************************************************************/
    
      if(!data->url)
        return CURLE_URL_MALFORMAT;
    
      /* First, split up the current URL in parts so that we can use the
         parts for checking against the already present connections. In order
         to not have to modify everything at once, we allocate a temporary
         connection data struct and fill in for comparison purposes. */
    
      conn = (struct connectdata *)malloc(sizeof(struct connectdata));
      if(!conn) {
        *in_connect = NULL; /* clear the pointer */
        return CURLE_OUT_OF_MEMORY;
      }
    
      /* We must set the return variable as soon as possible, so that our
         parent can cleanup any possible allocs we may have done before
         any failure */
      *in_connect = conn;
    
    
      /* we have to init the struct */
      memset(conn, 0, sizeof(struct connectdata));
    
      /* and we setup a few fields in case we end up actually using this struct */
      conn->data = data;           /* remember our daddy */
      conn->upload_bufsize = UPLOAD_BUFSIZE; /* default upload buffer size */
      conn->firstsocket = -1;     /* no file descriptor */
      conn->secondarysocket = -1; /* no file descriptor */
      conn->connectindex = -1;    /* no index */
    
      conn->bits.httpproxy = data->bits.httpproxy; /* proxy-or-not status */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
      /* Default protocol-indepent behaveiour doesn't support persistant
         connections, so we set this to force-close. Protocols that support
         this need to set this to FALSE in their "curl_do" functions. */
      conn->bits.close = TRUE;
    
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      /***********************************************************
       * We need to allocate memory to store the path in. We get the size of the