#include "setup.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <errno.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
#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>
#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 VMS
#include <in.h>
#include <inet.h>
#endif
#ifdef HAVE_SETJMP_H
#include <setjmp.h>
#endif
#ifndef HAVE_SOCKET
#error "We can't compile without socket() support!"
#endif
#endif
#ifdef USE_LIBIDN
#include <idna.h>
#include <tld.h>
#include <stringprep.h>
#ifdef HAVE_IDN_FREE_H
#include <idn-free.h>
#else
void idn_free (void *ptr);
#endif
#ifndef HAVE_IDN_FREE
#define idn_free(x) (free)(x)
#endif
#endif
#include "urldata.h"
#include "netrc.h"
#include "formdata.h"
#include "base64.h"
#include "ssluse.h"
#include "hostip.h"
#include "if2ip.h"
#include "transfer.h"
#include "sendf.h"
#include "progress.h"
#include "cookie.h"
#include "strequal.h"
#include "strerror.h"
#include "escape.h"
#include "strtok.h"
#include "share.h"
#include "content_encoding.h"
#include "http_digest.h"
#include "http_negotiate.h"
#include "select.h"
#include "multiif.h"
#include "ftp.h"
#include "dict.h"
#include "telnet.h"
#include "http.h"
#include "file.h"
#include "ldap.h"
#include "url.h"
#include "connect.h"
#include "inet_ntop.h"
#include <ca-bundle.h>
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
#endif
#define _MPRINTF_REPLACE
#include <curl/mprintf.h>
#ifdef HAVE_KRB4
#include "security.h"
#endif
#include "memory.h"
#include "memdebug.h"
static long ConnectionKillOne(struct SessionHandle *data);
static bool ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis);
static long ConnectionStore(struct SessionHandle *data,
struct connectdata *conn);
static bool safe_strequal(char* str1, char* str2);
#ifndef USE_ARES
#if !defined(WIN32) || defined(__CYGWIN32__)
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
#ifdef HAVE_SIGSETJMP
extern sigjmp_buf curl_jmpenv;
#endif
static
RETSIGTYPE alarmfunc(int sig)
{
(void)sig;
#ifdef HAVE_SIGSETJMP
siglongjmp(curl_jmpenv, 1);
#endif
return;
}
#endif
#endif
void Curl_safefree(void *ptr)
{
if(ptr)
free(ptr);
}
CURLcode Curl_close(struct SessionHandle *data)
{
if(data->multi) {
Curl_multi_rmeasy(data->multi, data);
}
while(-1 != ConnectionKillOne(data))
;
if ( ! (data->share && data->share->hostcache) ) {
if ( !Curl_global_host_cache_use(data)) {
Curl_hash_destroy(data->hostcache);
}
}
#ifdef USE_SSLEAY
Curl_SSL_Close_All(data);
#endif
Curl_safefree(data->state.first_host);
Curl_safefree(data->state.scratch);
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);
Curl_safefree(data->state.headerbuff);
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
if(data->change.cookielist)
curl_slist_free_all(data->change.cookielist);
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
if(data->set.cookiejar) {
if(Curl_cookie_output(data->cookies, data->set.cookiejar))
infof(data, "WARNING: failed to save cookies in %s\n",
data->set.cookiejar);
}
if( !data->share || (data->cookies != data->share->cookies) ) {
Curl_cookie_cleanup(data->cookies);
}
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
Curl_digest_cleanup(data);
#endif
free(data->state.connects);
Curl_safefree(data->info.contenttype);
#ifdef USE_ARES
ares_destroy(data->state.areschannel);
#endif
if (data->share)
data->share->dirty--;
free(data);
return CURLE_OK;
}
CURLcode Curl_open(struct SessionHandle **curl)
{
CURLcode res = CURLE_OK;
struct SessionHandle *data;
data = (struct SessionHandle *)calloc(1, sizeof(struct SessionHandle));
if(!data)
return CURLE_OUT_OF_MEMORY;
#ifdef USE_ARES
if(ARES_SUCCESS != ares_init(&data->state.areschannel)) {
free(data);
return CURLE_FAILED_INIT;
}
#endif
data->state.headerbuff=(char*)malloc(HEADERSIZE);
if(!data->state.headerbuff)
res = CURLE_OUT_OF_MEMORY;
else {
data->state.headersize=HEADERSIZE;
data->set.out = stdout;
data->set.in = stdin;
data->set.err = stderr;
data->set.fwrite = (curl_write_callback)fwrite;
data->set.fread = (curl_read_callback)fread;
data->set.infilesize = -1;
data->set.postfieldsize = -1;
data->state.current_speed = -1;
data->set.httpreq = HTTPREQ_GET;
data->set.ftp_use_epsv = TRUE;
data->set.ftp_use_eprt = TRUE;
data->set.ftp_use_lprt = TRUE;
data->set.dns_cache_timeout = 60;
data->set.hide_progress = TRUE;
data->progress.flags |= PGRS_HIDE;
data->set.ssl.numsessions = 5;
data->set.proxyport = 1080;
data->set.proxytype = CURLPROXY_HTTP;
data->set.httpauth = CURLAUTH_BASIC;
data->set.proxyauth = CURLAUTH_BASIC;
data->state.numconnects = 5;
data->state.connects = (struct connectdata **)
malloc(sizeof(struct connectdata *) * data->state.numconnects);
if(!data->state.connects)
res = CURLE_OUT_OF_MEMORY;
else
memset(data->state.connects, 0,
sizeof(struct connectdata *)*data->state.numconnects);
data->set.ssl.verifypeer = TRUE;
data->set.ssl.verifyhost = 2;
#ifdef CURL_CA_BUNDLE
data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
#endif
}
if(res) {
#ifdef USE_ARES
ares_destroy(data->state.areschannel);
#endif
if(data->state.headerbuff)
free(data->state.headerbuff);
free(data);
data = NULL;
}
*curl = data;
return CURLE_OK;
}
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
{
va_list param;
char *argptr;
CURLcode result = CURLE_OK;
va_start(param, option);
switch(option) {
case CURLOPT_DNS_CACHE_TIMEOUT:
data->set.dns_cache_timeout = va_arg(param, int);
break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
{
int use_cache = va_arg(param, int);
if (use_cache) {
Curl_global_host_cache_init();
}
data->set.global_dns_cache = use_cache;
}
break;
case CURLOPT_SSL_CIPHER_LIST:
data->set.ssl.cipher_list = va_arg(param, char *);
break;
case CURLOPT_RANDOM_FILE:
data->set.ssl.random_file = va_arg(param, char *);
break;
case CURLOPT_EGDSOCKET:
data->set.ssl.egdsocket = va_arg(param, char *);
break;
case CURLOPT_MAXCONNECTS:
{
long newconnects= va_arg(param, long);
struct connectdata **newptr;
long i;
if(newconnects < data->state.numconnects) {
for(i=newconnects; i< data->state.numconnects; i++)
Curl_disconnect(data->state.connects[i]);
}
if(newconnects) {
newptr= (struct connectdata **)
realloc(data->state.connects,
sizeof(struct connectdata *) * newconnects);
if(!newptr)
return CURLE_OUT_OF_MEMORY;
for(i=data->state.numconnects; i<newconnects; i++) {
newptr[i] = NULL;
}
data->state.connects = newptr;
data->state.numconnects = newconnects;
}
else {
if(data->state.connects)
free(data->state.connects);
data->state.connects=NULL;
data->state.numconnects=0;
}
}
break;
case CURLOPT_FORBID_REUSE:
data->set.reuse_forbid = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FRESH_CONNECT:
data->set.reuse_fresh = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_VERBOSE:
data->set.verbose = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_HEADER:
data->set.include_header = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_NOPROGRESS:
data->set.hide_progress = va_arg(param, long)?TRUE:FALSE;
if(data->set.hide_progress)
data->progress.flags |= PGRS_HIDE;
else
data->progress.flags &= ~PGRS_HIDE;
break;
case CURLOPT_NOBODY:
data->set.opt_no_body = va_arg(param, long)?TRUE:FALSE;
if(data->set.opt_no_body)
data->set.httpreq = HTTPREQ_HEAD;
break;
case CURLOPT_FAILONERROR:
data->set.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_UPLOAD:
case CURLOPT_PUT:
data->set.upload = va_arg(param, long)?TRUE:FALSE;
if(data->set.upload)
data->set.httpreq = HTTPREQ_PUT;
break;
case CURLOPT_FILETIME:
data->set.get_filetime = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FTP_CREATE_MISSING_DIRS:
data->set.ftp_create_missing_dirs = va_arg( param , long )?TRUE:FALSE;
break;
case CURLOPT_FTP_RESPONSE_TIMEOUT:
data->set.ftp_response_timeout = va_arg( param , long );
break;
case CURLOPT_FTPLISTONLY:
data->set.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FTPAPPEND:
data->set.ftp_append = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_NETRC:
data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
break;
case CURLOPT_NETRC_FILE:
data->set.netrc_file = va_arg(param, char *);
break;
case CURLOPT_TRANSFERTEXT:
data->set.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_TIMECONDITION:
data->set.timecondition = (curl_TimeCond)va_arg(param, long);
break;
case CURLOPT_TIMEVALUE:
data->set.timevalue = (time_t)va_arg(param, long);
break;
case CURLOPT_SSLVERSION:
data->set.ssl.version = va_arg(param, long);
break;
#ifndef CURL_DISABLE_HTTP
case CURLOPT_AUTOREFERER:
data->set.http_auto_referer = va_arg(param, long)?1:0;
break;
case CURLOPT_ENCODING:
data->set.encoding = va_arg(param, char *);
if(data->set.encoding && !*data->set.encoding)
data->set.encoding = (char*)ALL_CONTENT_ENCODINGS;
break;
case CURLOPT_FOLLOWLOCATION:
data->set.http_follow_location = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_UNRESTRICTED_AUTH:
data->set.http_disable_hostname_check_before_authentication =
va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_MAXREDIRS:
data->set.maxredirs = va_arg(param, long);
break;
case CURLOPT_POST:
if(va_arg(param, long))
data->set.httpreq = HTTPREQ_POST;
else
data->set.httpreq = HTTPREQ_GET;
break;
case CURLOPT_POSTFIELDS:
data->set.postfields = va_arg(param, char *);
data->set.httpreq = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDSIZE:
data->set.postfieldsize = va_arg(param, long);
break;
case CURLOPT_POSTFIELDSIZE_LARGE:
data->set.postfieldsize = va_arg(param, curl_off_t);
break;
case CURLOPT_HTTPPOST:
data->set.httppost = va_arg(param, struct curl_httppost *);
data->set.httpreq = HTTPREQ_POST_FORM;
break;
case CURLOPT_REFERER:
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;
break;
case CURLOPT_USERAGENT:
data->set.useragent = va_arg(param, char *);
break;
case CURLOPT_HTTPHEADER:
data->set.headers = va_arg(param, struct curl_slist *);
break;
case CURLOPT_HTTP200ALIASES:
data->set.http200aliases = va_arg(param, struct curl_slist *);
break;
#if !defined(CURL_DISABLE_COOKIES)
case CURLOPT_COOKIE:
data->set.cookie = va_arg(param, char *);
break;
case CURLOPT_COOKIEFILE:
argptr = (char *)va_arg(param, void *);
if(argptr) {
struct curl_slist *cl;
cl = curl_slist_append(data->change.cookielist, argptr);
if(!cl)
return CURLE_OUT_OF_MEMORY;
data->change.cookielist = cl;
}
break;
case CURLOPT_COOKIEJAR:
data->set.cookiejar = (char *)va_arg(param, void *);
data->cookies = Curl_cookie_init(data, NULL, data->cookies,
data->set.cookiesession);
break;
case CURLOPT_COOKIESESSION:
data->set.cookiesession = (bool)va_arg(param, long);
break;
#endif
case CURLOPT_HTTPGET:
if(va_arg(param, long)) {
data->set.httpreq = HTTPREQ_GET;
data->set.upload = FALSE;
}
break;
case CURLOPT_HTTP_VERSION:
data->set.httpversion = va_arg(param, long);
break;
case CURLOPT_HTTPPROXYTUNNEL:
data->set.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_CUSTOMREQUEST:
data->set.customrequest = va_arg(param, char *);
break;
case CURLOPT_PROXYPORT:
data->set.proxyport = va_arg(param, long);
break;
case CURLOPT_HTTPAUTH:
{
long auth = va_arg(param, long);
#ifndef USE_SSLEAY
auth &= ~CURLAUTH_NTLM;
#endif
#ifndef HAVE_GSSAPI
auth &= ~CURLAUTH_GSSNEGOTIATE;
#endif
if(!auth)
return CURLE_FAILED_INIT;
data->set.httpauth = auth;
}
break;
case CURLOPT_PROXYAUTH:
{
long auth = va_arg(param, long);
#ifndef USE_SSLEAY
auth &= ~CURLAUTH_NTLM;
#endif
#ifndef HAVE_GSSAPI
auth &= ~CURLAUTH_GSSNEGOTIATE;
#endif
if(!auth)
return CURLE_FAILED_INIT;
data->set.proxyauth = auth;
}
break;
#endif
case CURLOPT_PROXY:
if(data->change.proxy_alloc) {
data->change.proxy_alloc=FALSE;;
free(data->change.proxy);
}
data->set.set_proxy = va_arg(param, char *);
data->change.proxy = data->set.set_proxy;
break;
case CURLOPT_WRITEHEADER:
data->set.writeheader = (void *)va_arg(param, void *);
break;
case CURLOPT_ERRORBUFFER:
data->set.errorbuffer = va_arg(param, char *);
break;
case CURLOPT_FILE:
data->set.out = va_arg(param, FILE *);
break;
case CURLOPT_FTPPORT:
data->set.ftpport = va_arg(param, char *);
data->set.ftp_use_port = data->set.ftpport?1:0;
break;
case CURLOPT_FTP_USE_EPRT:
data->set.ftp_use_eprt = va_arg(param, long)?TRUE:FALSE;
data->set.ftp_use_lprt = data->set.ftp_use_eprt;
break;
case CURLOPT_FTP_USE_EPSV:
data->set.ftp_use_epsv = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_INFILE:
data->set.in = va_arg(param, FILE *);
break;
case CURLOPT_INFILESIZE:
data->set.infilesize = va_arg(param, long);
break;
case CURLOPT_INFILESIZE_LARGE:
data->set.infilesize = va_arg(param, curl_off_t);
break;
case CURLOPT_LOW_SPEED_LIMIT:
data->set.low_speed_limit=va_arg(param, long);
break;
case CURLOPT_LOW_SPEED_TIME:
data->set.low_speed_time=va_arg(param, long);
break;
case CURLOPT_URL:
if(data->change.url_alloc) {
free(data->change.url);
data->change.url_alloc=FALSE;
}
data->set.set_url = va_arg(param, char *);
data->change.url = data->set.set_url;
data->change.url_changed = TRUE;
break;
case CURLOPT_PORT:
data->set.use_port = va_arg(param, long);
break;
case CURLOPT_TIMEOUT:
data->set.timeout = va_arg(param, long);
break;
case CURLOPT_CONNECTTIMEOUT:
data->set.connecttimeout = va_arg(param, long);
break;
case CURLOPT_USERPWD:
data->set.userpwd = va_arg(param, char *);
break;
case CURLOPT_POSTQUOTE:
data->set.postquote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_PREQUOTE:
data->set.prequote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_QUOTE:
data->set.quote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_PROGRESSFUNCTION:
data->set.fprogress = va_arg(param, curl_progress_callback);
if(data->set.fprogress)
data->progress.callback = TRUE;
else
data->progress.callback = FALSE;
break;
case CURLOPT_PROGRESSDATA:
data->set.progress_client = va_arg(param, void *);
break;
case CURLOPT_PROXYUSERPWD:
data->set.proxyuserpwd = va_arg(param, char *);
break;
case CURLOPT_RANGE:
data->set.set_range = va_arg(param, char *);
break;
case CURLOPT_RESUME_FROM:
data->set.set_resume_from = va_arg(param, long);
break;
case CURLOPT_RESUME_FROM_LARGE:
data->set.set_resume_from = va_arg(param, curl_off_t);
break;
case CURLOPT_DEBUGFUNCTION:
data->set.fdebug = va_arg(param, curl_debug_callback);
break;
case CURLOPT_DEBUGDATA:
data->set.debugdata = va_arg(param, void *);
break;
case CURLOPT_STDERR:
data->set.err = va_arg(param, FILE *);
if(!data->set.err)
data->set.err = stderr;
break;
case CURLOPT_HEADERFUNCTION:
data->set.fwrite_header = va_arg(param, curl_write_callback);
break;
case CURLOPT_WRITEFUNCTION:
data->set.fwrite = va_arg(param, curl_write_callback);
if(!data->set.fwrite)
data->set.fwrite = (curl_write_callback)fwrite;
break;
case CURLOPT_READFUNCTION:
data->set.fread = va_arg(param, curl_read_callback);
if(!data->set.fread)
data->set.fread = (curl_read_callback)fread;
break;
case CURLOPT_IOCTLFUNCTION:
data->set.ioctl = va_arg(param, curl_ioctl_callback);
break;
case CURLOPT_IOCTLDATA:
data->set.ioctl_client = va_arg(param, void *);
break;
case CURLOPT_SSLCERT:
data->set.cert = va_arg(param, char *);
break;
case CURLOPT_SSLCERTTYPE:
data->set.cert_type = va_arg(param, char *);
break;
case CURLOPT_SSLKEY:
data->set.key = va_arg(param, char *);
break;
case CURLOPT_SSLKEYTYPE:
data->set.key_type = va_arg(param, char *);
break;
case CURLOPT_SSLKEYPASSWD:
data->set.key_passwd = va_arg(param, char *);
break;
case CURLOPT_SSLENGINE:
argptr = va_arg(param, char *);
if (argptr && argptr[0])
result = Curl_SSL_set_engine(data, argptr);
break;
case CURLOPT_SSLENGINE_DEFAULT:
result = Curl_SSL_set_engine_default(data);
break;
case CURLOPT_CRLF:
data->set.crlf = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_INTERFACE:
data->set.device = va_arg(param, char *);
break;
case CURLOPT_KRB4LEVEL:
data->set.krb4_level = va_arg(param, char *);
data->set.krb4=data->set.krb4_level?TRUE:FALSE;
break;
case CURLOPT_SSL_VERIFYPEER:
data->set.ssl.verifypeer = va_arg(param, long);
break;
case CURLOPT_SSL_VERIFYHOST:
data->set.ssl.verifyhost = va_arg(param, long);
break;
case CURLOPT_SSL_CTX_FUNCTION:
data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
break;
case CURLOPT_SSL_CTX_DATA:
data->set.ssl.fsslctxp = va_arg(param, void *);
break;
case CURLOPT_CAINFO:
data->set.ssl.CAfile = va_arg(param, char *);
break;
case CURLOPT_CAPATH:
data->set.ssl.CApath = va_arg(param, char *);
break;
case CURLOPT_TELNETOPTIONS:
data->set.telnet_options = va_arg(param, struct curl_slist *);
break;
case CURLOPT_BUFFERSIZE:
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;
break;
case CURLOPT_NOSIGNAL:
data->set.no_signal = va_arg(param, long) ? TRUE : FALSE;
break;
case CURLOPT_SHARE:
{
struct Curl_share *set;
set = va_arg(param, struct Curl_share *);
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 = NULL;
}
data->share = set;
if(data->share) {
Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
data->share->dirty++;
if(data->share->hostcache) {
if(data->hostcache)
Curl_hash_destroy(data->hostcache);
data->hostcache = data->share->hostcache;
}
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
if(data->share->cookies) {
if (data->cookies)
Curl_cookie_cleanup(data->cookies);
data->cookies = data->share->cookies;
}
#endif
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
if(!data->cookies)
data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE );
#endif
}
break;
case CURLOPT_PROXYTYPE:
data->set.proxytype = (curl_proxytype)va_arg(param, long);
break;
case CURLOPT_PRIVATE:
data->set.private_data = va_arg(param, char *);
break;
case CURLOPT_MAXFILESIZE:
data->set.max_filesize = va_arg(param, long);
break;
case CURLOPT_FTP_SSL:
data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long);
break;
case CURLOPT_FTPSSLAUTH:
data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long);
break;
case CURLOPT_IPRESOLVE:
data->set.ip_version = va_arg(param, long);
break;
case CURLOPT_MAXFILESIZE_LARGE:
data->set.max_filesize = va_arg(param, curl_off_t);
break;
case CURLOPT_TCP_NODELAY:
data->set.tcp_nodelay = (bool)va_arg(param, long);
break;
case CURLOPT_SOURCE_URL:
data->set.source_url = va_arg(param, char *);
data->set.printhost = (data->set.source_url != NULL);
break;
case CURLOPT_SOURCE_USERPWD:
data->set.source_userpwd = va_arg(param, char *);
break;
case CURLOPT_SOURCE_QUOTE:
data->set.source_quote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_SOURCE_PREQUOTE:
data->set.source_prequote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_SOURCE_POSTQUOTE:
data->set.source_postquote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_FTP_ACCOUNT:
data->set.ftp_account = va_arg(param, char *);
break;
default:
result = CURLE_FAILED_INIT;
break;
}
return result;
}
CURLcode Curl_disconnect(struct connectdata *conn)
{
struct SessionHandle *data;
if(!conn)
return CURLE_OK;
data = conn->data;
#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
Curl_hash_apply(data->hostcache,
NULL, Curl_scan_cache_used);
#endif
Curl_hostcache_prune(data);
if(conn->bits.rangestringalloc) {
free(conn->range);
conn->bits.rangestringalloc = FALSE;
}
if((conn->ntlm.state != NTLMSTATE_NONE) ||
(conn->proxyntlm.state != NTLMSTATE_NONE)) {
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)
conn->curl_disconnect(conn);
if(-1 != conn->connectindex) {
infof(data, "Closing connection #%ld\n", conn->connectindex);
data->state.connects[conn->connectindex] = NULL;
}
Curl_safefree(conn->proto.generic);
Curl_safefree(conn->newurl);
Curl_safefree(conn->pathbuffer);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->proxy.rawalloc);
#ifdef USE_LIBIDN
if(conn->host.encalloc)
idn_free(conn->host.encalloc);
if(conn->proxy.encalloc)
idn_free(conn->proxy.encalloc);
#endif
Curl_SSL_Close(conn);
if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
sclose(conn->sock[SECONDARYSOCKET]);
if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
sclose(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.host);
Curl_safefree(conn->allocptr.cookiehost);
Curl_safefree(conn->ip_addr_str);
#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
defined(USE_THREADING_GETADDRINFO)
Curl_safefree(conn->async.hostname);
Curl_safefree(conn->async.os_specific);
#endif
Curl_free_ssl_config(&conn->ssl_config);
free(conn);
return CURLE_OK;
}
static bool SocketIsDead(curl_socket_t sock)
{
int sval;
bool ret_val = TRUE;
sval = Curl_select(sock, CURL_SOCKET_BAD, 0);
if(sval == 0)
ret_val = FALSE;
return ret_val;
}
static bool
ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis)
{
long i;
struct connectdata *check;
for(i=0; i< data->state.numconnects; i++) {
bool match = FALSE;
check = data->state.connects[i];
if(!check)
continue;
if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
continue;
if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
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) {
if(!Curl_ssl_config_matches(&needle->ssl_config,
&check->ssl_config)) {
continue;
}
}
if((needle->protocol & PROT_FTP) ||
((needle->protocol & PROT_HTTP) &&
(needle->data->state.authhost.want==CURLAUTH_NTLM))) {
if(!strequal(needle->user, check->user) ||
!strequal(needle->passwd, check->passwd)) {
continue;
}
}
match = TRUE;
}
}
else {
if(check->bits.httpproxy &&
strequal(needle->proxy.name, check->proxy.name) &&
needle->port == check->port) {
match = TRUE;
}
}
if(match) {
bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
if(dead) {
infof(data, "Connection %d seems to be dead!\n", i);
Curl_disconnect(check);
data->state.connects[i]=NULL;
return FALSE;
}
*usethis = check;
return TRUE;
}
}
return FALSE;
}
static long
ConnectionKillOne(struct SessionHandle *data)
{
long i;
struct connectdata *conn;
long highscore=-1;
long connindex=-1;
long score;
struct timeval now;
now = Curl_tvnow();
for(i=0; i< data->state.numconnects; i++) {
conn = data->state.connects[i];
if(!conn)
continue;
switch(data->set.closepolicy) {
case CURLCLOSEPOLICY_LEAST_RECENTLY_USED:
default:
score = Curl_tvdiff(now, conn->now);
break;
case CURLCLOSEPOLICY_OLDEST:
score = Curl_tvdiff(now, conn->created);
break;
}
if(score > highscore) {
highscore = score;
connindex = i;
}
}
if(connindex >= 0) {
(void) Curl_disconnect(data->state.connects[connindex]);
data->state.connects[connindex] = NULL;
}
return connindex;
}
static long
ConnectionStore(struct SessionHandle *data,
struct connectdata *conn)
{
long i;
for(i=0; i< data->state.numconnects; i++) {
if(!data->state.connects[i])
break;
}
if(i == data->state.numconnects) {
i = ConnectionKillOne(data);
infof(data, "Connection (#%d) was killed to make room\n", i);
}
if(-1 != i) {
data->state.connects[i] = conn;
conn->connectindex = i;
}
return i;
}
static int handleSock5Proxy(const char *proxy_name,
const char *proxy_password,
struct connectdata *conn)
{
unsigned char socksreq[600];
ssize_t actualread;
ssize_t written;
int result;
CURLcode code;
int sock = conn->sock[FIRSTSOCKET];
Curl_nonblock(sock, FALSE);
socksreq[0] = 5;
socksreq[1] = (char)(proxy_name ? 2 : 1);
socksreq[2] = 0;
socksreq[3] = 2;
code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
&written);
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) {
;
}
else if (socksreq[1] == 2) {
int userlen, pwlen, len;
userlen = (int)strlen(proxy_name);
pwlen = proxy_password?(int)strlen(proxy_password):0;
len = 0;
socksreq[len++] = 1;
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[1] != 0) {
failf(conn->data, "User was rejected by the SOCKS5 server (%d %d).",
socksreq[0], socksreq[1]);
return 1;
}
}
else {
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;
}
}
socksreq[0] = 5;
socksreq[1] = 1;
socksreq[2] = 0;
socksreq[3] = 1;
{
struct Curl_dns_entry *dns;
Curl_addrinfo *hp=NULL;
int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
if(rc == CURLRESOLV_ERROR)
return 1;
if(rc == CURLRESOLV_PENDING)
rc = Curl_wait_for_resolv(conn, &dns);
if(dns)
hp=dns->addr;
if (hp) {
char buf[64];
unsigned short ip[4];
Curl_printable_address(hp, buf, sizeof(buf));
if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
&ip[0], &ip[1], &ip[2], &ip[3])) {
socksreq[4] = (unsigned char)ip[0];
socksreq[5] = (unsigned char)ip[1];
socksreq[6] = (unsigned char)ip[2];
socksreq[7] = (unsigned char)ip[3];
}
else
hp = NULL;
Curl_resolv_unlock(conn->data, dns);
}
if(!hp) {
failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
conn->host.name);
return 1;
}
}
*((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) {
failf(conn->data,
"SOCKS5 reply has wrong version, version should be 5.");
return 1;
}
if (socksreq[1] != 0) {
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;
}
static CURLcode ConnectPlease(struct connectdata *conn,
struct Curl_dns_entry *hostaddr,
bool *connected)
{
CURLcode result;
Curl_addrinfo *addr;
struct SessionHandle *data = conn->data;
char *hostname = data->change.proxy?conn->proxy.name:conn->host.name;
infof(data, "About to connect() to %s port %d\n",
hostname, conn->port);
result= Curl_connecthost(conn,
hostaddr,
&conn->sock[FIRSTSOCKET],
&addr,
connected);
if(CURLE_OK == result) {
conn->dns_entry = hostaddr;
conn->ip_addr = addr;
Curl_store_ip_addr(conn);
if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
return handleSock5Proxy(conn->proxyuser,
conn->proxypasswd,
conn) ?
CURLE_COULDNT_CONNECT : CURLE_OK;
}
else if (conn->data->set.proxytype == CURLPROXY_HTTP) {
}
else {
failf(conn->data, "unknown proxytype option given");
return CURLE_COULDNT_CONNECT;
}
}
return result;
}
static void verboseconnect(struct connectdata *conn)
{
infof(conn->data, "Connected to %s (%s) port %d\n",
conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname,
conn->ip_addr_str, conn->port);
}
CURLcode Curl_protocol_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
CURLcode res = CURLE_OK;
if(conn->curl_proto_fdset)
res = conn->curl_proto_fdset(conn, read_fd_set, write_fd_set, max_fdp);
return res;
}
CURLcode Curl_doing_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
int *max_fdp)
{
CURLcode res = CURLE_OK;
if(conn && conn->curl_doing_fdset)
res = conn->curl_doing_fdset(conn, read_fd_set, write_fd_set, max_fdp);
return res;
}
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_connecting) {
*done = FALSE;
result = conn->curl_connecting(conn, done);
}
else
*done = TRUE;
return result;
}
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_doing) {
*done = FALSE;
result = conn->curl_doing(conn, done);
}
else
*done = TRUE;
return result;
}
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *protocol_done)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
*protocol_done = FALSE;
if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
if(!conn->curl_connecting)
*protocol_done = TRUE;
return CURLE_OK;
}
if(!conn->bits.tcpconnect) {
Curl_pgrsTime(data, TIMER_CONNECT);
if(data->set.verbose)
verboseconnect(conn);
}
if(!conn->bits.protoconnstart) {
if(conn->curl_connect) {
conn->now = Curl_tvnow();
result = conn->curl_connect(conn, protocol_done);
}
else
*protocol_done = TRUE;
conn->bits.protoconnstart = TRUE;
}
return result;
}
#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;
}
static bool tld_check_name (struct SessionHandle *data,
const char *ace_hostname)
{
size_t err_pos;
char *uc_name = NULL;
int rc;
rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
if (rc != IDNA_SUCCESS)
return (FALSE);
rc = tld_check_lz(uc_name, &err_pos, NULL);
if (rc == TLD_INVALID)
infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
#ifdef HAVE_TLD_STRERROR
tld_strerror(rc),
#else
"<no msg>",
#endif
err_pos, uc_name[err_pos],
uc_name[err_pos] & 255);
else if (rc != TLD_SUCCESS)
infof(data, "WARNING: TLD check for %s failed; %s\n",
uc_name,
#ifdef HAVE_TLD_STRERROR
tld_strerror(rc)
#else
"<no msg>"
#endif
);
if (uc_name)
idn_free(uc_name);
return (rc == TLD_SUCCESS);
}
#endif
static void fix_hostname(struct connectdata *conn, struct hostname *host)
{
host->dispname = host->name;
#ifdef USE_LIBIDN
if (!is_ASCII_name(host->name) &&
stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
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; %s\n",
host->name, Curl_idn_strerror(conn,rc));
else {
tld_check_name(data, ace_hostname);
host->encalloc = ace_hostname;
host->name = host->encalloc;
}
}
#else
(void)conn;
#endif
}
static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata **in_connect,
struct Curl_dns_entry **addr,
bool *async)
{
char *tmp;
char *at;
CURLcode result=CURLE_OK;
struct connectdata *conn;
struct connectdata *conn_temp;
size_t urllen;
struct Curl_dns_entry *hostaddr;
#if defined(HAVE_ALARM) && !defined(USE_ARES)
unsigned int prev_alarm=0;
#endif
char endbracket;
char user[MAX_CURL_USER_LENGTH];
char passwd[MAX_CURL_PASSWORD_LENGTH];
int rc;
bool reuse;
#ifndef USE_ARES
#ifdef SIGALRM
#ifdef HAVE_SIGACTION
struct sigaction keep_sigact;
bool keep_copysig=FALSE;
#else
#ifdef HAVE_SIGNAL
void *keep_sigact;
#endif
#endif
#endif
#endif
*addr = NULL;
*async = FALSE;
if(!data->change.url)
return CURLE_URL_MALFORMAT;
conn = (struct connectdata *)calloc(sizeof(struct connectdata), 1);
if(!conn) {
*in_connect = NULL;
return CURLE_OUT_OF_MEMORY;
}
*in_connect = conn;
conn->data = data;
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
conn->connectindex = -1;
conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
(data->set.proxytype == CURLPROXY_HTTP))?
TRUE:FALSE;
conn->bits.close = TRUE;
conn->maxdownload = -1;
conn->created = Curl_tvnow();
conn->bits.use_range = data->set.set_range?TRUE:FALSE;
conn->range = data->set.set_range;
conn->resume_from = data->set.set_resume_from;
conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
conn->bits.no_body = data->set.opt_no_body;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
conn->bits.ftp_use_lprt = data->set.ftp_use_lprt;
#define LEAST_PATH_ALLOC 256
urllen=strlen(data->change.url);
if(urllen < LEAST_PATH_ALLOC)
urllen=LEAST_PATH_ALLOC;
conn->pathbuffer=(char *)malloc(urllen+3);
if(NULL == conn->pathbuffer)
return CURLE_OUT_OF_MEMORY;
conn->path = conn->pathbuffer;
conn->host.rawalloc=(char *)malloc(urllen+3);
if(NULL == conn->host.rawalloc)
return CURLE_OUT_OF_MEMORY;
conn->host.name = conn->host.rawalloc;
conn->host.name[0] = 0;
if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
conn->protostr,
conn->path)) && strequal(conn->protostr, "file")) {
if(conn->path[0] == '/' && conn->path[1] == '/') {
memmove(conn->path, conn->path + 2, strlen(conn->path + 2)+1);
}
if(conn->path[0] != '/') {
char *ptr=strchr(conn->path, '/');
if(ptr) {
if(ptr[1] && ('/' == ptr[1]))
ptr++;
memmove(conn->path, ptr, strlen(ptr)+1);
}
}
strcpy(conn->protostr, "file");
}
else {
strcpy(conn->path, "/");
if (2 > sscanf(data->change.url,
"%15[^\n:]://%[^\n/]%[^\n]",
conn->protostr,
conn->host.name, conn->path)) {
if((1 > sscanf(data->change.url, "%[^\n/]%[^\n]",
conn->host.name, conn->path)) ) {
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
if(checkprefix("GOPHER.", conn->host.name))
strcpy(conn->protostr, "gopher");
#ifdef USE_SSLEAY
else if(checkprefix("FTPS", conn->host.name))
strcpy(conn->protostr, "ftps");
#endif
else if(checkprefix("FTP.", conn->host.name))
strcpy(conn->protostr, "ftp");
else if(checkprefix("TELNET.", conn->host.name))
strcpy(conn->protostr, "telnet");
else if (checkprefix("DICT.", conn->host.name))
strcpy(conn->protostr, "DICT");
else if (checkprefix("LDAP.", conn->host.name))
strcpy(conn->protostr, "LDAP");
else {
strcpy(conn->protostr, "http");
}
conn->protocol |= PROT_MISSING;
}
}
at = strchr(conn->host.name, '@');
if(at)
tmp = strchr(at+1, '?');
else
tmp = strchr(conn->host.name, '?');
if(tmp) {
size_t len = strlen(tmp);
memmove(conn->path+len+1, conn->path, strlen(conn->path)+1);
conn->path[0]='/';
memcpy(conn->path+1, tmp, len);
*tmp=0;
}
if(conn->path[0] == '?') {
memmove(&conn->path[1], conn->path, strlen(conn->path)+1);
conn->path[0] = '/';
}
if(conn->bits.proxy_user_passwd) {
char proxyuser[MAX_CURL_USER_LENGTH]="";
char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
sscanf(data->set.proxyuserpwd,
"%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
proxyuser, proxypasswd);
conn->proxyuser = strdup(proxyuser);
if(!conn->proxyuser)
return CURLE_OUT_OF_MEMORY;
conn->proxypasswd = strdup(proxypasswd);
if(!conn->proxypasswd)
return CURLE_OUT_OF_MEMORY;
}
#ifndef CURL_DISABLE_HTTP
if(!data->change.proxy) {
char *no_proxy=NULL;
char *no_proxy_tok_buf;
char *proxy=NULL;
char proxy_env[128];
no_proxy=curl_getenv("no_proxy");
if(!no_proxy)
no_proxy=curl_getenv("NO_PROXY");
if(!no_proxy || !strequal("*", no_proxy)) {
char *nope;
nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
while(nope) {
size_t namelen;
char *endptr = strchr(conn->host.name, ':');
if(endptr)
namelen=endptr-conn->host.name;
else
namelen=strlen(conn->host.name);
if(strlen(nope) <= namelen) {
char *checkn=
conn->host.name + namelen - strlen(nope);
if(checkprefix(nope, checkn)) {
break;
}
}
nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
}
if(!nope) {
char *protop = conn->protostr;
char *envp = proxy_env;
char *prox;
while(*protop)
*envp++ = tolower((int)*protop++);
strcpy(envp, "_proxy");
prox=curl_getenv(proxy_env);
if(!prox && !strequal("http_proxy", proxy_env)) {
for(envp = proxy_env; *envp; envp++)
*envp = toupper((int)*envp);
prox=curl_getenv(proxy_env);
}
if(prox && *prox) {
proxy = prox;
}
else {
proxy = curl_getenv("all_proxy");
if(!proxy)
proxy=curl_getenv("ALL_PROXY");
}
if(proxy && *proxy) {
char *ptr;
char proxyuser[MAX_CURL_USER_LENGTH];
char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
char *fineptr;
ptr=strstr(proxy, "://");
if(ptr)
ptr += 3;
else
ptr = proxy;
fineptr = ptr;
ptr = strchr(ptr, '@');
if(ptr && (2 == sscanf(fineptr,
"%" MAX_CURL_USER_LENGTH_TXT"[^:]:"
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
proxyuser, proxypasswd))) {
CURLcode res = CURLE_OK;
Curl_safefree(conn->proxyuser);
conn->proxyuser = strdup(proxyuser);
if(!conn->proxyuser)
res = CURLE_OUT_OF_MEMORY;
else {
Curl_safefree(conn->proxypasswd);
conn->proxypasswd = strdup(proxypasswd);
if(!conn->proxypasswd)
res = CURLE_OUT_OF_MEMORY;
}
if(CURLE_OK == res) {
conn->bits.proxy_user_passwd = TRUE;
ptr = strdup(ptr+1);
if(ptr) {
free(proxy);
proxy = ptr;
}
else
res = CURLE_OUT_OF_MEMORY;
}
if(res) {
free(proxy);
return res;
}
}
data->change.proxy = proxy;
data->change.proxy_alloc=TRUE;
conn->bits.httpproxy = TRUE;
}
}
}
if(no_proxy)
free(no_proxy);
}
#endif
if(conn->protocol&PROT_MISSING) {
char *reurl;
reurl = aprintf("%s://%s", conn->protostr, data->change.url);
if(!reurl)
return CURLE_OUT_OF_MEMORY;
data->change.url = reurl;
data->change.url_alloc = TRUE;
conn->protocol &= ~PROT_MISSING;
}
#ifndef CURL_DISABLE_HTTP
if(conn->resume_from) {
if(!conn->bits.use_range) {
conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
if(!conn->range)
return CURLE_OUT_OF_MEMORY;
conn->bits.rangestringalloc = TRUE;
conn->bits.use_range = 1;
}
}
#endif
if (strequal(conn->protostr, "HTTP")) {
#ifndef CURL_DISABLE_HTTP
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_HTTP;
conn->remote_port = PORT_HTTP;
conn->protocol |= PROT_HTTP;
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
#else
failf(data, LIBCURL_NAME
" was built with HTTP disabled, http: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
else if (strequal(conn->protostr, "HTTPS")) {
#if defined(USE_SSLEAY) && !defined(CURL_DISABLE_HTTP)
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_HTTPS;
conn->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
#else
failf(data, LIBCURL_NAME
" was built with SSL disabled, https: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
else if (strequal(conn->protostr, "GOPHER")) {
#ifndef CURL_DISABLE_GOPHER
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_GOPHER;
conn->remote_port = PORT_GOPHER;
if (isdigit((int)conn->path[1])) {
conn->path = strchr(&conn->path[1], '/');
if (conn->path == NULL)
conn->path = conn->pathbuffer;
}
conn->protocol |= PROT_GOPHER;
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
conn->curl_done = Curl_http_done;
#else
failf(data, LIBCURL_NAME
" was built with GOPHER disabled, gopher: not supported!");
#endif
}
else if(strequal(conn->protostr, "FTP") ||
strequal(conn->protostr, "FTPS")) {
#ifndef CURL_DISABLE_FTP
char *type;
int port = PORT_FTP;
if(strequal(conn->protostr, "FTPS")) {
#ifdef USE_SSLEAY
conn->protocol |= PROT_FTPS|PROT_SSL;
conn->ssl[SECONDARYSOCKET].use = TRUE;
port = PORT_FTPS;
#else
failf(data, LIBCURL_NAME
" was built with SSL disabled, ftps: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:port;
conn->remote_port = port;
conn->protocol |= PROT_FTP;
if(data->change.proxy &&
*data->change.proxy &&
!data->set.tunnel_thru_httpproxy) {
if(conn->protocol & PROT_FTPS) {
failf(data, "ftps does not work through http proxy!");
return CURLE_UNSUPPORTED_PROTOCOL;
}
#ifndef CURL_DISABLE_HTTP
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
#else
failf(data, "FTP over http proxy requires HTTP support built-in!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
else {
conn->curl_do = Curl_ftp;
conn->curl_do_more = Curl_ftp_nextconnect;
conn->curl_done = Curl_ftp_done;
conn->curl_connect = Curl_ftp_connect;
conn->curl_connecting = Curl_ftp_multi_statemach;
conn->curl_doing = Curl_ftp_doing;
conn->curl_proto_fdset = Curl_ftp_fdset;
conn->curl_doing_fdset = Curl_ftp_fdset;
conn->curl_disconnect = Curl_ftp_disconnect;
}
conn->path++;
type=strstr(conn->path, ";type=");
if(!type) {
type=strstr(conn->host.rawalloc, ";type=");
}
if(type) {
char command;
*type=0;
command = toupper((int)type[6]);
switch(command) {
case 'A':
data->set.ftp_ascii = 1;
break;
case 'D':
data->set.ftp_list_only = 1;
break;
case 'I':
default:
data->set.ftp_ascii = 0;
break;
}
}
#else
failf(data, LIBCURL_NAME
" was built with FTP disabled, ftp/ftps: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
else if(strequal(conn->protostr, "TELNET")) {
#ifndef CURL_DISABLE_TELNET
conn->protocol |= PROT_TELNET;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port: PORT_TELNET;
conn->remote_port = PORT_TELNET;
conn->curl_do = Curl_telnet;
conn->curl_done = Curl_telnet_done;
#else
failf(data, LIBCURL_NAME
" was built with TELNET disabled!");
#endif
}
else if (strequal(conn->protostr, "DICT")) {
#ifndef CURL_DISABLE_DICT
conn->protocol |= PROT_DICT;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_DICT;
conn->remote_port = PORT_DICT;
conn->curl_do = Curl_dict;
conn->curl_done = NULL;
#else
failf(data, LIBCURL_NAME
" was built with DICT disabled!");
#endif
}
else if (strequal(conn->protostr, "LDAP")) {
#ifndef CURL_DISABLE_LDAP
conn->protocol |= PROT_LDAP;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_LDAP;
conn->remote_port = PORT_LDAP;
conn->curl_do = Curl_ldap;
conn->curl_done = NULL;
#else
failf(data, LIBCURL_NAME
" was built with LDAP disabled!");
#endif
}
else if (strequal(conn->protostr, "FILE")) {
#ifndef CURL_DISABLE_FILE
conn->protocol |= PROT_FILE;
conn->curl_do = Curl_file;
conn->curl_done = Curl_file_done;
result = Curl_file_connect(conn);
if(CURLE_OK == result) {
conn->bits.tcpconnect = TRUE;
result = Curl_Transfer(conn, -1, -1, FALSE, NULL,
-1, NULL);
}
return result;
#else
failf(data, LIBCURL_NAME
" was built with FILE disabled!");
#endif
}
else {
failf(data, "Unsupported protocol: %s", conn->protostr);
return CURLE_UNSUPPORTED_PROTOCOL;
}
if(data->change.proxy && *data->change.proxy) {
char *prox_portno;
char *endofprot;
char *proxydup=strdup(data->change.proxy);
char *proxyptr=proxydup;
if(NULL == proxydup) {
failf(data, "memory shortage");
return CURLE_OUT_OF_MEMORY;
}
endofprot=strstr(proxyptr, "://");
if(endofprot) {
proxyptr = endofprot+3;
}
prox_portno = strchr (proxyptr, ':');
if (prox_portno) {
*prox_portno = 0x0;
prox_portno ++;
conn->port = atoi(prox_portno);
}
else if(data->set.proxyport) {
conn->port = data->set.proxyport;
}
conn->proxy.rawalloc = strdup(proxyptr);
conn->proxy.name = conn->proxy.rawalloc;
free(proxydup);
if(!conn->proxy.rawalloc)
return CURLE_OUT_OF_MEMORY;
}
if((conn->protocol&PROT_SSL) && conn->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE;
user[0] =0;
passwd[0]=0;
if (conn->protocol & (PROT_FTP|PROT_HTTP)) {
char *ptr=strchr(conn->host.name, '@');
char *userpass = conn->host.name;
if(ptr != NULL) {
conn->host.name = ++ptr;
if (data->set.use_netrc != CURL_NETRC_REQUIRED) {
conn->bits.user_passwd = 1;
if(*userpass != ':') {
sscanf(userpass, "%127[^:@]:%127[^@]",
user, passwd);
}
else
sscanf(userpass, ":%127[^@]", passwd);
if(user[0]) {
char *newname=curl_unescape(user, 0);
if(!newname)
return CURLE_OUT_OF_MEMORY;
if(strlen(newname) < sizeof(user))
strcpy(user, newname);
free(newname);
}
if (passwd[0]) {
char *newpasswd=curl_unescape(passwd, 0);
if(!newpasswd)
return CURLE_OUT_OF_MEMORY;
if(strlen(newpasswd) < sizeof(passwd))
strcpy(passwd, newpasswd);
free(newpasswd);
}
}
}
}
if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
(']' == endbracket)) {
conn->bits.ipv6_ip = TRUE;
conn->host.name++;
tmp = strchr(conn->host.name, ']');
*tmp = 0;
tmp++;
if(':' != *tmp)
tmp = NULL;
}
else
tmp = strrchr(conn->host.name, ':');
if (tmp) {
char *rest;
unsigned long port;
port=strtoul(tmp+1, &rest, 10);
if (rest != (tmp+1) && *rest == '\0') {
if (port > 0xffff) {
failf(data, "Port number too large: %lu", port);
return CURLE_URL_MALFORMAT;
}
*tmp = '\0';
conn->remote_port = (unsigned short)port;
}
}
if (data->set.userpwd != NULL) {
sscanf(data->set.userpwd,
"%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
user, passwd);
}
if (data->set.use_netrc != CURL_NETRC_IGNORED) {
if(Curl_parsenetrc(conn->host.name,
user, passwd,
data->set.netrc_file)) {
infof(data, "Couldn't find host %s in the " DOT_CHAR "netrc file, using defaults\n",
conn->host.name);
}
else
conn->bits.user_passwd = 1;
}
if ( (conn->protocol & PROT_FTP) &&
!conn->bits.user_passwd) {
conn->user = strdup(CURL_DEFAULT_USER);
conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
}
else {
conn->user = strdup(user);
conn->passwd = strdup(passwd);
}
if(!conn->user || !conn->passwd)
return CURLE_OUT_OF_MEMORY;
if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
return CURLE_OUT_OF_MEMORY;
if(data->set.reuse_fresh && !data->state.this_is_a_follow)
reuse = FALSE;
else
reuse = ConnectionExists(data, conn, &conn_temp);
if(reuse) {
struct connectdata *old_conn = conn;
if(old_conn->proxy.rawalloc)
free(old_conn->proxy.rawalloc);
Curl_free_ssl_config(&conn->ssl_config);
conn = conn_temp;
conn->bits.user_passwd = old_conn->bits.user_passwd;
if (conn->bits.user_passwd) {
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
conn->user = old_conn->user;
conn->passwd = old_conn->passwd;
old_conn->user = NULL;
old_conn->passwd = NULL;
}
conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
if (conn->bits.proxy_user_passwd) {
Curl_safefree(conn->proxyuser);
Curl_safefree(conn->proxypasswd);
conn->proxyuser = old_conn->proxyuser;
conn->proxypasswd = old_conn->proxypasswd;
old_conn->proxyuser = NULL;
old_conn->proxypasswd = NULL;
}
if (conn->bits.httpproxy) {
free(conn->host.rawalloc);
conn->host=old_conn->host;
}
conn->bits.no_body = old_conn->bits.no_body;
if (!conn->bits.httpproxy)
free(old_conn->host.rawalloc);
free(conn->pathbuffer);
conn->pathbuffer = old_conn->pathbuffer;
conn->path = old_conn->path;
conn->bits.reuse = TRUE;
conn->bits.chunk = FALSE;
conn->maxdownload = -1;
Curl_safefree(old_conn->user);
Curl_safefree(old_conn->passwd);
Curl_safefree(old_conn->proxyuser);
Curl_safefree(old_conn->proxypasswd);
if(old_conn->bits.rangestringalloc)
free(old_conn->range);
free(old_conn);
conn->resume_from = data->set.set_resume_from;
if (conn->resume_from) {
if (conn->bits.rangestringalloc == TRUE)
free(conn->range);
conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
if(!conn->range)
return CURLE_OUT_OF_MEMORY;
conn->bits.use_range = TRUE;
conn->bits.rangestringalloc = TRUE;
}
else if (data->set.set_range) {
conn->range = strdup(data->set.set_range);
if(!conn->range)
return CURLE_OUT_OF_MEMORY;
conn->bits.rangestringalloc = TRUE;
conn->bits.use_range = TRUE;
}
else
conn->bits.use_range = FALSE;
*in_connect = conn;
infof(data, "Re-using existing connection! (#%ld) with host %s\n",
conn->connectindex,
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
}
else {
ConnectionStore(data, conn);
}
conn->fread = data->set.fread;
conn->fread_in = data->set.in;
conn->bits.upload_chunky =
((conn->protocol&PROT_HTTP) &&
data->set.upload &&
(data->set.infilesize == -1) &&
(data->set.httpversion != CURL_HTTP_VERSION_1_0))?
TRUE:
FALSE;
#ifndef USE_ARES
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
#ifdef SIGALRM
#ifdef HAVE_SIGACTION
struct sigaction sigact;
sigaction(SIGALRM, NULL, &sigact);
keep_sigact = sigact;
keep_copysig = TRUE;
sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
sigact.sa_flags &= ~SA_RESTART;
#endif
sigaction(SIGALRM, &sigact, NULL);
#else
#ifdef HAVE_SIGNAL
keep_sigact = signal(SIGALRM, alarmfunc);
#endif
#endif
#ifdef HAVE_ALARM
prev_alarm = alarm(data->set.connecttimeout?
data->set.connecttimeout:
data->set.timeout);
#endif
#endif
}
#endif
if(conn->bits.reuse) {
hostaddr = NULL;
if (conn->bits.httpproxy)
fix_hostname(conn, &conn->host);
}
else {
fix_hostname(conn, &conn->host);
if(!data->change.proxy || !*data->change.proxy) {
conn->port = conn->remote_port;
rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
result = CURLE_COULDNT_RESOLVE_HOST;
}
}
else {
fix_hostname(conn, &conn->proxy);
rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(!hostaddr) {
failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
result = CURLE_COULDNT_RESOLVE_PROXY;
}
}
}
*addr = hostaddr;
#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
#ifdef HAVE_SIGACTION
if(keep_copysig) {
sigaction(SIGALRM, &keep_sigact, NULL);
}
#else
#ifdef HAVE_SIGNAL
signal(SIGALRM, keep_sigact);
#endif
#endif
if(prev_alarm) {
unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
unsigned long alarm_set;
alarm_set = prev_alarm - elapsed_ms/1000;
if(!alarm_set ||
((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
alarm(1);
result = CURLE_OPERATION_TIMEOUTED;
failf(data, "Previous alarm fired off!");
}
else
alarm((unsigned int)alarm_set);
}
else
alarm(0);
}
#endif
return result;
}
static CURLcode SetupConnection(struct connectdata *conn,
struct Curl_dns_entry *hostaddr,
bool *protocol_done)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
if(conn->protocol & PROT_FILE) {
*protocol_done = TRUE;
return result;
}
*protocol_done = FALSE;
if((conn->protocol&PROT_HTTP) ||
(data->change.proxy && *data->change.proxy)) {
if(data->set.useragent) {
Curl_safefree(conn->allocptr.uagent);
conn->allocptr.uagent =
aprintf("User-Agent: %s\015\012", data->set.useragent);
if(!conn->allocptr.uagent)
return CURLE_OUT_OF_MEMORY;
}
}
conn->bytecount = 0;
conn->headerbytecount = 0;
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
bool connected = FALSE;
result = ConnectPlease(conn, hostaddr, &connected);
if(connected) {
result = Curl_protocol_connect(conn, protocol_done);
if(CURLE_OK == result)
conn->bits.tcpconnect = TRUE;
}
else
conn->bits.tcpconnect = FALSE;
if(CURLE_OK != result)
return result;
}
else {
Curl_pgrsTime(data, TIMER_CONNECT);
conn->bits.tcpconnect = TRUE;
*protocol_done = TRUE;
if(data->set.verbose)
verboseconnect(conn);
}
conn->now = Curl_tvnow();
#ifdef __EMX__
if ((data->set.out)->_handle == NULL) {
_fsetmode(stdout, "b");
}
#endif
return CURLE_OK;
}
CURLcode Curl_connect(struct SessionHandle *data,
struct connectdata **in_connect,
bool *asyncp,
bool *protocol_done)
{
CURLcode code;
struct Curl_dns_entry *dns;
*asyncp = FALSE;
code = CreateConnection(data, in_connect, &dns, asyncp);
if(CURLE_OK == code) {
if(dns || !*asyncp)
code = SetupConnection(*in_connect, dns, protocol_done);
}
if(CURLE_OK != code) {
if(*in_connect) {
Curl_disconnect(*in_connect);
*in_connect = NULL;
}
}
return code;
}
CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_done)
{
#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
defined(USE_THREADING_GETADDRINFO)
CURLcode code = SetupConnection(conn, conn->async.dns, protocol_done);
if(code)
Curl_disconnect(conn);
return code;
#else
(void)conn;
(void)protocol_done;
return CURLE_OK;
#endif
}
CURLcode Curl_done(struct connectdata **connp,
CURLcode status)
{
CURLcode result;
struct connectdata *conn = *connp;
struct SessionHandle *data=conn->data;
if(conn->bits.rangestringalloc) {
free(conn->range);
conn->bits.rangestringalloc = FALSE;
}
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry);
conn->dns_entry = NULL;
}
if(conn->newurl) {
free(conn->newurl);
conn->newurl = NULL;
}
if(conn->curl_done)
result = conn->curl_done(conn, status);
else
result = CURLE_OK;
Curl_pgrsDone(conn);
if(data->set.reuse_forbid || conn->bits.close) {
CURLcode res2;
res2 = Curl_disconnect(conn);
*connp = NULL;
if(!result && res2)
result = res2;
}
else
infof(data, "Connection #%ld to host %s left intact\n",
conn->connectindex,
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
return result;
}
CURLcode Curl_do(struct connectdata **connp, bool *done)
{
CURLcode result=CURLE_OK;
struct connectdata *conn = *connp;
struct SessionHandle *data=conn->data;
conn->bits.do_more = FALSE;
if(conn->curl_do) {
result = conn->curl_do(conn, done);
if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
infof(data, "Re-used connection seems dead, get a new one\n");
conn->bits.close = TRUE;
result = Curl_done(&conn, result);
if(CURLE_OK == result) {
bool async;
bool protocol_done = TRUE;
result = Curl_connect(data, connp, &async, &protocol_done);
if(CURLE_OK == result) {
conn = *connp;
if(async) {
result = Curl_wait_for_resolv(conn, NULL);
if(result)
return result;
result = Curl_async_resolved(conn, &protocol_done);
if(result)
return result;
}
result = conn->curl_do(conn, done);
}
}
}
}
return result;
}
CURLcode Curl_do_more(struct connectdata *conn)
{
CURLcode result=CURLE_OK;
if(conn->curl_do_more)
result = conn->curl_do_more(conn);
return result;
}
static bool safe_strequal(char* str1, char* str2)
{
if(str1 && str2)
return strequal(str1, str2);
else
return (!str1 && !str2);
}
bool
Curl_ssl_config_matches(struct ssl_config_data* data,
struct ssl_config_data* needle)
{
if((data->version == needle->version) &&
(data->verifypeer == needle->verifypeer) &&
(data->verifyhost == needle->verifyhost) &&
safe_strequal(data->CApath, needle->CApath) &&
safe_strequal(data->CAfile, needle->CAfile) &&
safe_strequal(data->random_file, needle->random_file) &&
safe_strequal(data->egdsocket, needle->egdsocket) &&
safe_strequal(data->cipher_list, needle->cipher_list))
return TRUE;
return FALSE;
}
bool
Curl_clone_ssl_config(struct ssl_config_data *source,
struct ssl_config_data *dest)
{
dest->verifyhost = source->verifyhost;
dest->verifypeer = source->verifypeer;
dest->version = source->version;
if(source->CAfile) {
dest->CAfile = strdup(source->CAfile);
if(!dest->CAfile)
return FALSE;
}
if(source->CApath) {
dest->CApath = strdup(source->CApath);
if(!dest->CApath)
return FALSE;
}
if(source->cipher_list) {
dest->cipher_list = strdup(source->cipher_list);
if(!dest->cipher_list)
return FALSE;
}
if(source->egdsocket) {
dest->egdsocket = strdup(source->egdsocket);
if(!dest->egdsocket)
return FALSE;
}
if(source->random_file) {
dest->random_file = strdup(source->random_file);
if(!dest->random_file)
return FALSE;
}
return TRUE;
}
void Curl_free_ssl_config(struct ssl_config_data* sslc)
{
if(sslc->CAfile)
free(sslc->CAfile);
if(sslc->CApath)
free(sslc->CApath);
if(sslc->cipher_list)
free(sslc->cipher_list);
if(sslc->egdsocket)
free(sslc->egdsocket);
if(sslc->random_file)
free(sslc->random_file);
}