Newer
Older
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
* 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.
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
* $Id$
*****************************************************************************/
#include "setup.h"
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#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
#ifdef VMS
#include <in.h>
#include <inet.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
committed
#include "transfer.h"
#include "sendf.h"
#include "getpass.h"
#include "progress.h"
#include "cookie.h"
#include "escape.h"
/* And now for the protocols */
#include "ftp.h"
#include "dict.h"
#include "telnet.h"
#include "http.h"
#include "file.h"
#include "ldap.h"
Daniel Stenberg
committed
#include "url.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
#ifdef MALLOCDEBUG
#include "memdebug.h"
#endif
/* Local static prototypes */
Daniel Stenberg
committed
static int ConnectionKillOne(struct SessionHandle *data);
static bool ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis);
Daniel Stenberg
committed
static unsigned int ConnectionStore(struct SessionHandle *data,
#if !defined(WIN32)||defined(__CYGWIN32__)
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
static
RETSIGTYPE alarmfunc(int signal)
{
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void)signal;
return;
}
#endif
Daniel Stenberg
committed
CURLcode Curl_close(struct SessionHandle *data)
/* Loop through all open connections and kill them one by one */
while(-1 != ConnectionKillOne(data));
#ifdef USE_SSLEAY
/* Close down all open info open SSL and sessions */
Curl_SSL_Close_All(data);
#endif
Daniel Stenberg
committed
if(data->change.proxy_alloc)
free(data->change.proxy);
if(data->change.referer_alloc)
free(data->change.referer);
if(data->change.url_alloc)
free(data->change.url);
Daniel Stenberg
committed
if(data->state.headerbuff)
free(data->state.headerbuff);
Daniel Stenberg
committed
if(data->set.cookiejar)
/* we have a "destination" for all the cookies to get dumped to */
Daniel Stenberg
committed
Curl_cookie_output(data->cookies, data->set.cookiejar);
Curl_cookie_cleanup(data->cookies);
/* free the connection cache */
Daniel Stenberg
committed
free(data->state.connects);
static
int my_getpass(void *clientp, const char *prompt, char* buffer, int buflen )
clientp=NULL; /* prevent compiler warning */
retbuf = getpass_r(prompt, buffer, buflen);
if(NULL == retbuf)
return 1;
else
return 0; /* success */
}
Daniel Stenberg
committed
CURLcode Curl_open(struct SessionHandle **curl)
{
/* We don't yet support specifying the URL at this point */
Daniel Stenberg
committed
struct SessionHandle *data;
#ifdef HAVE_SIGACTION
struct sigaction sigact;
#endif
/* Very simple start-up: alloc the struct, init it with zeroes and return */
Daniel Stenberg
committed
data = (struct SessionHandle *)malloc(sizeof(struct SessionHandle));
Daniel Stenberg
committed
memset(data, 0, sizeof(struct SessionHandle));
/* We do some initial setup here, all those fields that can't be just 0 */
Daniel Stenberg
committed
data->state.headerbuff=(char*)malloc(HEADERSIZE);
if(!data->state.headerbuff) {
free(data); /* free the memory again */
return CURLE_OUT_OF_MEMORY;
}
Daniel Stenberg
committed
data->state.headersize=HEADERSIZE;
Daniel Stenberg
committed
data->set.out = stdout; /* default output to stdout */
data->set.in = stdin; /* default input from stdin */
data->set.err = stderr; /* default stderr to stderr */
/* use fwrite as default function to store output */
Daniel Stenberg
committed
data->set.fwrite = (curl_write_callback)fwrite;
/* use fread as default function to read input */
Daniel Stenberg
committed
data->set.fread = (curl_read_callback)fread;
/* set the default passwd function */
Daniel Stenberg
committed
data->set.fpasswd = my_getpass;
Daniel Stenberg
committed
data->set.infilesize = -1; /* we don't know any size */
Daniel Stenberg
committed
data->state.current_speed = -1; /* init to negative == impossible */
Daniel Stenberg
committed
data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
Daniel Stenberg
committed
/* make libcurl quiet by default: */
Daniel Stenberg
committed
data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
data->progress.flags |= PGRS_HIDE;
/* Set the default size of the SSL session ID cache */
Daniel Stenberg
committed
data->set.ssl.numsessions = 5;
/* create an array with connection data struct pointers */
Daniel Stenberg
committed
data->state.numconnects = 5; /* hard-coded right now */
data->state.connects = (struct connectdata **)
malloc(sizeof(struct connectdata *) * data->state.numconnects);
Daniel Stenberg
committed
if(!data->state.connects) {
free(data);
return CURLE_OUT_OF_MEMORY;
}
Daniel Stenberg
committed
memset(data->state.connects, 0,
sizeof(struct connectdata *)*data->state.numconnects);
/*************************************************************
* Set signal handler
*************************************************************/
#ifdef HAVE_SIGACTION
sigaction(SIGALRM, NULL, &sigact);
sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
/* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
sigact.sa_flags &= ~SA_RESTART;
#endif
sigaction(SIGALRM, &sigact, NULL);
#else
/* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL
signal(SIGALRM, alarmfunc);
#endif
#endif
}
/* this is a very serious error */
Daniel Stenberg
committed
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
{
va_list param;
char *cookiefile;
va_start(param, option);
switch(option) {
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
data->set.ssl.cipher_list = va_arg(param, char *);
break;
case CURLOPT_RANDOM_FILE:
/*
* This is the path name to a file that contains random data to seed
* the random SSL stuff with. The file is only used for reading.
*/
Daniel Stenberg
committed
data->set.ssl.random_file = va_arg(param, char *);
break;
case CURLOPT_EGDSOCKET:
/*
* The Entropy Gathering Daemon socket pathname
*/
Daniel Stenberg
committed
data->set.ssl.egdsocket = va_arg(param, char *);
break;
case CURLOPT_MAXCONNECTS:
/*
* Set the absolute number of maximum simultaneous alive connection that
* libcurl is allowed to have.
*/
{
long newconnects= va_arg(param, long);
struct connectdata **newptr;
Daniel Stenberg
committed
if(newconnects < data->state.numconnects) {
/* Since this number is *decreased* from the existing number, we must
close the possibly open connections that live on the indexes that
are being removed! */
int i;
Daniel Stenberg
committed
for(i=newconnects; i< data->state.numconnects; i++)
Curl_disconnect(data->state.connects[i]);
}
if(newconnects) {
newptr= (struct connectdata **)
Daniel Stenberg
committed
realloc(data->state.connects,
sizeof(struct connectdata *) * newconnects);
if(!newptr)
/* we closed a few connections in vain, but so what? */
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
data->state.connects = newptr;
data->state.numconnects = newconnects;
}
else {
/* zero makes NO cache at all */
Daniel Stenberg
committed
if(data->state.connects)
free(data->state.connects);
data->state.connects=NULL;
data->state.numconnects=0;
}
}
break;
case CURLOPT_FORBID_REUSE:
/*
* When this transfer is done, it must not be left to be reused by a
* subsequent transfer but shall be closed immediately.
*/
Daniel Stenberg
committed
data->set.reuse_forbid = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FRESH_CONNECT:
/*
* This transfer shall not use a previously cached connection but
* should be made with a fresh new connect!
*/
Daniel Stenberg
committed
data->set.reuse_fresh = va_arg(param, long)?TRUE:FALSE;
/*
* Verbose means infof() calls that give a lot of information about
* the connection and transfer procedures as well as internal choices.
*/
Daniel Stenberg
committed
data->set.verbose = va_arg(param, long)?TRUE:FALSE;
/*
* Set to include the header in the general data output stream.
*/
Daniel Stenberg
committed
data->set.http_include_header = va_arg(param, long)?TRUE:FALSE;
/*
* Shut off the internal supported progress meter
*/
Daniel Stenberg
committed
data->set.hide_progress = va_arg(param, long)?TRUE:FALSE;
if(data->set.hide_progress)
else
data->progress.flags &= ~PGRS_HIDE;
/*
* Do not include the body part in the output data stream.
*/
Daniel Stenberg
committed
data->set.no_body = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FAILONERROR:
/*
* Don't output the >=300 error code HTML-page, but instead only
* return error.
*/
Daniel Stenberg
committed
data->set.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
/*
* We want to sent data to the remote host
*/
Daniel Stenberg
committed
data->set.upload = va_arg(param, long)?TRUE:FALSE;
if(data->set.upload)
/* If this is HTTP, PUT is what's needed to "upload" */
Daniel Stenberg
committed
data->set.httpreq = HTTPREQ_PUT;
/*
* Try to get the file time of the remote document. The time will
* later (possibly) become available using curl_easy_getinfo().
*/
Daniel Stenberg
committed
data->set.get_filetime = va_arg(param, long)?TRUE:FALSE;
/*
* An FTP option that changes the command to one that asks for a list
* only, no file info details.
*/
Daniel Stenberg
committed
data->set.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
/*
* We want to upload and append to an existing (FTP) file.
*/
Daniel Stenberg
committed
data->set.ftp_append = va_arg(param, long)?TRUE:FALSE;
/*
* Parse the $HOME/.netrc file
*/
Daniel Stenberg
committed
data->set.use_netrc = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FOLLOWLOCATION:
/*
* Follow Location: header hints on a HTTP-server.
*/
Daniel Stenberg
committed
data->set.http_follow_location = va_arg(param, long)?TRUE:FALSE;
case CURLOPT_TRANSFERTEXT:
* This option was previously named 'FTPASCII'. Renamed to work with
* more protocols than merely FTP.
*
* Transfer using ASCII (instead of BINARY).
Daniel Stenberg
committed
data->set.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
* Use the HTTP PUT request to transfer data if this is TRUE. If this is
* FALSE, don't set the httpreq. We can't know what to revert it to!
Daniel Stenberg
committed
data->set.httpreq = HTTPREQ_PUT;
#if 0
/* obsolete stuff, kept here a while for informational purposes */
/*
* Stay absolutely quiet.
*/
Daniel Stenberg
committed
data->set.mute = va_arg(param, long)?TRUE:FALSE;
/*
* Set HTTP time condition. This must be one of the defines in the
* curl/curl.h header file.
*/
Daniel Stenberg
committed
data->set.timecondition = va_arg(param, long);
/*
* This is the value to compare with the remote document with the
* method set with CURLOPT_TIMECONDITION
*/
Daniel Stenberg
committed
data->set.timevalue = va_arg(param, long);
/*
* Set explicit SSL version to try to connect with, as some SSL
* implementations are lame.
*/
Daniel Stenberg
committed
data->set.ssl.version = va_arg(param, long);
* Set cookie file to read and parse. Can be used multiple times.
cookiefile = (char *)va_arg(param, void *);
Daniel Stenberg
committed
if(cookiefile)
data->cookies = Curl_cookie_init(cookiefile, data->cookies);
case CURLOPT_COOKIEJAR:
/*
* Set cookie file name to dump all cookies to when we're done.
*/
Daniel Stenberg
committed
data->set.cookiejar = cookiefile = (char *)va_arg(param, void *);
* Custom pointer to pass the header write callback function
Daniel Stenberg
committed
data->set.writeheader = (void *)va_arg(param, void *);
/*
* Cookie string to send to the remote server in the request.
*/
Daniel Stenberg
committed
data->set.cookie = va_arg(param, char *);
/*
* Error buffer provided by the caller to get the human readable
* error string in.
*/
Daniel Stenberg
committed
data->set.errorbuffer = va_arg(param, char *);
/*
* FILE pointer to write to or include in the data write callback
*/
Daniel Stenberg
committed
data->set.out = va_arg(param, FILE *);
/*
* Use FTP PORT, this also specifies which IP address to use
*/
Daniel Stenberg
committed
data->set.ftpport = va_arg(param, char *);
data->set.ftp_use_port = data->set.ftpport?1:0;
/*
* Set a list with HTTP headers to use (or replace internals with)
*/
Daniel Stenberg
committed
data->set.headers = va_arg(param, struct curl_slist *);
/*
* Set a custom string to use as request
*/
Daniel Stenberg
committed
data->set.customrequest = va_arg(param, char *);
if(data->set.customrequest)
data->set.httpreq = HTTPREQ_CUSTOM;
/*
* Set to make us do HTTP POST
*/
Daniel Stenberg
committed
data->set.httppost = va_arg(param, struct HttpPost *);
if(data->set.httppost)
data->set.httpreq = HTTPREQ_POST_FORM;
case CURLOPT_HTTPGET:
/*
* Set to force us do HTTP GET
*/
if(va_arg(param, long))
Daniel Stenberg
committed
data->set.httpreq = HTTPREQ_GET;
/*
* FILE pointer to read the file to be uploaded from. Or possibly
* used as argument to the read callback.
*/
Daniel Stenberg
committed
data->set.in = va_arg(param, FILE *);
/*
* If known, this should inform curl about the file size of the
* to-be-uploaded file.
*/
Daniel Stenberg
committed
data->set.infilesize = va_arg(param, long);
/*
* The low speed limit that if transfers are below this for
* CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
*/
Daniel Stenberg
committed
data->set.low_speed_limit=va_arg(param, long);
/*
* The low speed time that if transfers are below the set
* CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
*/
Daniel Stenberg
committed
data->set.low_speed_time=va_arg(param, long);
/*
* The URL to fetch.
*/
Daniel Stenberg
committed
if(data->change.url_alloc) {
Daniel Stenberg
committed
/* the already set URL is allocated, free it first! */
Daniel Stenberg
committed
free(data->change.url);
data->change.url_alloc=FALSE;
Daniel Stenberg
committed
}
Daniel Stenberg
committed
data->set.set_url = va_arg(param, char *);
data->change.url = data->set.set_url;
/*
* The port number to use when getting the URL
*/
Daniel Stenberg
committed
data->set.use_port = va_arg(param, long);
case CURLOPT_POST:
/* Does this option serve a purpose anymore? */
Daniel Stenberg
committed
data->set.httpreq = HTTPREQ_POST;
break;
/*
* A string with POST data. Makes curl HTTP POST.
*/
Daniel Stenberg
committed
data->set.postfields = va_arg(param, char *);
if(data->set.postfields)
data->set.httpreq = HTTPREQ_POST;
/*
* The size of the POSTFIELD data, if curl should now do a strlen
* to find out. Enables binary posts.
*/
Daniel Stenberg
committed
data->set.postfieldsize = va_arg(param, long);
/*
* String to set in the HTTP Referer: field.
*/
Daniel Stenberg
committed
if(data->change.referer_alloc) {
free(data->change.referer);
data->change.referer_alloc = FALSE;
}
data->set.set_referer = va_arg(param, char *);
data->change.referer = data->set.set_referer;
case CURLOPT_AUTOREFERER:
/*
* Switch on automatic referer that gets set if curl follows locations.
*/
Daniel Stenberg
committed
data->set.http_auto_referer = va_arg(param, long)?1:0;
/*
* Set proxy server:port to use as HTTP proxy
*/
Daniel Stenberg
committed
if(data->change.proxy_alloc) {
Daniel Stenberg
committed
/*
* The already set string is allocated, free that first
*/
Daniel Stenberg
committed
data->change.proxy_alloc=FALSE;;
free(data->change.proxy);
Daniel Stenberg
committed
}
Daniel Stenberg
committed
data->set.set_proxy = va_arg(param, char *);
data->change.proxy = data->set.set_proxy;
case CURLOPT_HTTPPROXYTUNNEL:
/*
* Tunnel operations through the proxy instead of normal proxy use
*/
Daniel Stenberg
committed
data->set.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
/*
* Explicitly set HTTP proxy port number.
*/
Daniel Stenberg
committed
data->set.proxyport = va_arg(param, long);
/*
* The maximum time you allow curl to use for a single transfer
* operation.
*/
Daniel Stenberg
committed
data->set.timeout = va_arg(param, long);
case CURLOPT_CONNECTTIMEOUT:
/*
* The maximum time you allow curl to use to connect.
*/
Daniel Stenberg
committed
data->set.connecttimeout = va_arg(param, long);
/*
* The maximum amount of hops you allow curl to follow Location:
* headers. This should mostly be used to detect never-ending loops.
*/
Daniel Stenberg
committed
data->set.maxredirs = va_arg(param, long);
/*
* String to use in the HTTP User-Agent field
*/
Daniel Stenberg
committed
data->set.useragent = va_arg(param, char *);
/*
* user:password to use in the operation
*/
Daniel Stenberg
committed
data->set.userpwd = va_arg(param, char *);
/*
* List of RAW FTP commands to use after a transfer
*/
Daniel Stenberg
committed
data->set.postquote = va_arg(param, struct curl_slist *);
case CURLOPT_QUOTE:
/*
* List of RAW FTP commands to use before a transfer
*/
Daniel Stenberg
committed
data->set.quote = va_arg(param, struct curl_slist *);
case CURLOPT_PROGRESSFUNCTION:
/*
* Progress callback function
*/
Daniel Stenberg
committed
data->set.fprogress = va_arg(param, curl_progress_callback);
data->progress.callback = TRUE; /* no longer internal */
break;
case CURLOPT_PROGRESSDATA:
/*
* Custom client data to pass to the progress callback
*/
Daniel Stenberg
committed
data->set.progress_client = va_arg(param, void *);
break;
case CURLOPT_PASSWDFUNCTION:
/*
* Password prompt callback
*/
Daniel Stenberg
committed
data->set.fpasswd = va_arg(param, curl_passwd_callback);
break;
case CURLOPT_PASSWDDATA:
/*
* Custom client data to pass to the password callback
*/
Daniel Stenberg
committed
data->set.passwd_client = va_arg(param, void *);
/*
* user:password needed to use the proxy
*/
Daniel Stenberg
committed
data->set.proxyuserpwd = va_arg(param, char *);
/*
* What range of the file you want to transfer
*/
Daniel Stenberg
committed
data->set.set_range = va_arg(param, char *);
/*
* Resume transfer at the give file position
*/
Daniel Stenberg
committed
data->set.set_resume_from = va_arg(param, long);
/*
* Set to a FILE * that should receive all error writes. This
* defaults to stderr for normal operations.
*/
Daniel Stenberg
committed
data->set.err = va_arg(param, FILE *);
case CURLOPT_HEADERFUNCTION:
/*
* Set header write callback
*/
Daniel Stenberg
committed
data->set.fwrite_header = va_arg(param, curl_write_callback);
/*
* Set data write callback
*/
Daniel Stenberg
committed
data->set.fwrite = va_arg(param, curl_write_callback);
/*
* Read data callback
*/
Daniel Stenberg
committed
data->set.fread = va_arg(param, curl_read_callback);
/*
* String that holds file name of the SSL certificate to use
*/
Daniel Stenberg
committed
data->set.cert = va_arg(param, char *);
/*
* String that holds the SSL certificate password.
*/
Daniel Stenberg
committed
data->set.cert_passwd = va_arg(param, char *);
Daniel Stenberg
committed
* Kludgy option to enable CRLF convertions. Subject for removal.
Daniel Stenberg
committed
data->set.crlf = va_arg(param, long)?TRUE:FALSE;
/*
* Set what interface to bind to when performing an operation and thus
* what from-IP your connection will use.
*/
Daniel Stenberg
committed
data->set.device = va_arg(param, char *);
/*
* A string that defines the krb4 security level.
*/
Daniel Stenberg
committed
data->set.krb4_level = va_arg(param, char *);
data->set.krb4=data->set.krb4_level?TRUE:FALSE;
Daniel Stenberg
committed
case CURLOPT_SSL_VERIFYPEER:
/*
* Enable peer SSL verifying.
*/
Daniel Stenberg
committed
data->set.ssl.verifypeer = va_arg(param, long);
Daniel Stenberg
committed
break;
Daniel Stenberg
committed
case CURLOPT_SSL_VERIFYHOST:
/*
* Enable verification of the CN contained in the peer certificate
*/
Daniel Stenberg
committed
data->set.ssl.verifyhost = va_arg(param, long);
Daniel Stenberg
committed
break;
Daniel Stenberg
committed
case CURLOPT_CAINFO:
/*
* Set CA info for SSL connection. Specify file name of the CA certificate
*/
Daniel Stenberg
committed
data->set.ssl.CAfile = va_arg(param, char *);
data->set.ssl.CApath = NULL; /*This does not work on windows.*/
Daniel Stenberg
committed
break;
case CURLOPT_TELNETOPTIONS:
/*
* Set a linked list of telnet options
*/
Daniel Stenberg
committed
data->set.telnet_options = va_arg(param, struct curl_slist *);
default:
/* unknown tag and its companion, just ignore: */
return CURLE_READ_ERROR; /* correct this */
CURLcode Curl_disconnect(struct connectdata *conn)
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;
}
Daniel Stenberg
committed
/* unlink ourselves! */
infof(conn->data, "Closing live connection (#%d)\n", conn->connectindex);
Daniel Stenberg
committed
conn->data->state.connects[conn->connectindex] = NULL;
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);
if(conn->hp) /* host name info */
freeaddrinfo(conn->hp);
if(conn->hostent_buf) /* host name info */
free(conn->hostent_buf);
Daniel Stenberg
committed
if(conn->newurl)
free(conn->newurl);
if(conn->path) /* the URL path part */
free(conn->path);
Curl_SSL_Close(conn);
#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 */
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
/*
* 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
Daniel Stenberg
committed
ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis)
struct connectdata *check;
Daniel Stenberg
committed
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.
*/
Daniel Stenberg
committed
check = data->state.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->remote_port == check->remote_port) ) {
if(strequal(needle->protostr, "FTP")) {
/* This is FTP, verify that we're using the same name and
password as well */
Daniel Stenberg
committed
if(!strequal(needle->data->state.user, check->proto.ftp->user) ||
!strequal(needle->data->state.passwd, check->proto.ftp->passwd)) {
/* one of them was different */
continue;
}
}
dead = SocketIsDead(check->firstsocket);
if(dead) {
infof(data, "Connection %d seems to be dead!\n", i);
Curl_disconnect(check); /* disconnect resources */
Daniel Stenberg
committed
data->state.connects[i]=NULL; /* nothing here */
Daniel Stenberg
committed
*usethis = check;
return TRUE; /* yes, we found one to use! */