#include "setup.h"
#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
#ifdef HAVE_SETJMP_H
#include <setjmp.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"
#include "transfer.h"
#include "sendf.h"
#include "getpass.h"
#include "progress.h"
#include "cookie.h"
#include "strequal.h"
#include "escape.h"
#include "strtok.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 "ca-bundle.h"
#include <curl/types.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 KRB4
#include "security.h"
#endif
#ifdef MALLOCDEBUG
#include "memdebug.h"
#endif
static int ConnectionKillOne(struct SessionHandle *data);
static bool ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis);
static unsigned int ConnectionStore(struct SessionHandle *data,
struct connectdata *conn);
#if !defined(WIN32)||defined(__CYGWIN32__)
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
#ifdef HAVE_SIGSETJMP
extern sigjmp_buf curl_jmpenv;
#endif
static
RETSIGTYPE alarmfunc(int signal)
{
(void)signal;
#ifdef HAVE_SIGSETJMP
siglongjmp(curl_jmpenv, 1);
#endif
return;
}
#endif
CURLcode Curl_close(struct SessionHandle *data)
{
while(-1 != ConnectionKillOne(data));
#ifdef USE_SSLEAY
Curl_SSL_Close_All(data);
#endif
if (data->share)
data->share->dirty--;
if(data->change.cookielist)
curl_slist_free_all(data->change.cookielist);
if(data->state.auth_host)
free(data->state.auth_host);
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);
if(data->state.headerbuff)
free(data->state.headerbuff);
#ifndef CURL_DISABLE_HTTP
if(data->set.cookiejar)
Curl_cookie_output(data->cookies, data->set.cookiejar);
Curl_cookie_cleanup(data->cookies);
#endif
free(data->state.connects);
if(data->info.contenttype)
free(data->info.contenttype);
free(data);
return CURLE_OK;
}
static
int my_getpass(void *clientp, const char *prompt, char* buffer, int buflen )
{
char *retbuf;
clientp=NULL;
retbuf = getpass_r(prompt, buffer, buflen);
if(NULL == retbuf)
return 1;
else
return 0;
}
CURLcode Curl_open(struct SessionHandle **curl)
{
struct SessionHandle *data;
data = (struct SessionHandle *)malloc(sizeof(struct SessionHandle));
if(!data)
return CURLE_OUT_OF_MEMORY;
memset(data, 0, sizeof(struct SessionHandle));
data->state.headerbuff=(char*)malloc(HEADERSIZE);
if(!data->state.headerbuff) {
free(data);
return CURLE_OUT_OF_MEMORY;
}
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.fpasswd = my_getpass;
data->set.infilesize = -1;
data->state.current_speed = -1;
data->set.httpreq = HTTPREQ_GET;
data->set.ftp_use_epsv = 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->state.numconnects = 5;
data->state.connects = (struct connectdata **)
malloc(sizeof(struct connectdata *) * data->state.numconnects);
if(!data->state.connects) {
free(data);
return CURLE_OUT_OF_MEMORY;
}
data->set.ssl.verifypeer = TRUE;
data->set.ssl.verifyhost = 2;
#ifdef CURL_CA_BUNDLE
data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
#endif
memset(data->state.connects, 0,
sizeof(struct connectdata *)*data->state.numconnects);
*curl = data;
return CURLE_OK;
}
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
{
va_list param;
char *cookiefile;
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;
if(newconnects < data->state.numconnects) {
int i;
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;
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.http_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.no_body = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FAILONERROR:
data->set.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_UPLOAD:
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_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 = va_arg(param, long);
break;
case CURLOPT_FOLLOWLOCATION:
data->set.http_follow_location = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_HTTP_VERSION:
data->set.httpversion = va_arg(param, long);
break;
case CURLOPT_TRANSFERTEXT:
data->set.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_PUT:
if(va_arg(param, long))
data->set.httpreq = HTTPREQ_PUT;
break;
case CURLOPT_TIMECONDITION:
data->set.timecondition = va_arg(param, long);
break;
case CURLOPT_TIMEVALUE:
data->set.timevalue = va_arg(param, long);
break;
case CURLOPT_SSLVERSION:
data->set.ssl.version = va_arg(param, long);
break;
case CURLOPT_COOKIESESSION:
data->set.cookiesession = (bool)va_arg(param, long);
break;
#ifndef CURL_DISABLE_HTTP
case CURLOPT_COOKIEFILE:
cookiefile = (char *)va_arg(param, void *);
if(cookiefile)
data->change.cookielist =
curl_slist_append(data->change.cookielist, cookiefile);
break;
case CURLOPT_COOKIEJAR:
data->set.cookiejar = (char *)va_arg(param, void *);
data->cookies = Curl_cookie_init(NULL, data->cookies,
data->set.cookiesession);
break;
#endif
case CURLOPT_WRITEHEADER:
data->set.writeheader = (void *)va_arg(param, void *);
break;
case CURLOPT_COOKIE:
data->set.cookie = va_arg(param, char *);
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_EPSV:
data->set.ftp_use_epsv = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_HTTPHEADER:
data->set.headers = va_arg(param, struct curl_slist *);
break;
case CURLOPT_CUSTOMREQUEST:
data->set.customrequest = va_arg(param, char *);
break;
case CURLOPT_HTTPPOST:
data->set.httppost = va_arg(param, struct HttpPost *);
if(data->set.httppost)
data->set.httpreq = HTTPREQ_POST_FORM;
break;
case CURLOPT_HTTPGET:
if(va_arg(param, long)) {
data->set.httpreq = HTTPREQ_GET;
data->set.upload = 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_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;
break;
case CURLOPT_PORT:
data->set.use_port = va_arg(param, long);
break;
case CURLOPT_POST:
if(va_arg(param, long))
data->set.httpreq = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDS:
data->set.postfields = va_arg(param, char *);
if(data->set.postfields)
data->set.httpreq = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDSIZE:
data->set.postfieldsize = va_arg(param, long);
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_AUTOREFERER:
data->set.http_auto_referer = va_arg(param, long)?1:0;
break;
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_HTTPPROXYTUNNEL:
data->set.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_PROXYPORT:
data->set.proxyport = 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_MAXREDIRS:
data->set.maxredirs = va_arg(param, long);
break;
case CURLOPT_USERAGENT:
data->set.useragent = va_arg(param, char *);
break;
case CURLOPT_ENCODING:
data->set.encoding = va_arg(param, char *);
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_PASSWDFUNCTION:
data->set.fpasswd = va_arg(param, curl_passwd_callback);
if(!data->set.fpasswd)
{
data->set.fpasswd = my_getpass;
}
break;
case CURLOPT_PASSWDDATA:
data->set.passwd_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_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);
break;
case CURLOPT_READFUNCTION:
data->set.fread = va_arg(param, curl_read_callback);
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:
#ifdef HAVE_OPENSSL_ENGINE_H
{
const char *cpTemp = va_arg(param, char *);
ENGINE *e;
if (cpTemp && cpTemp[0]) {
e = ENGINE_by_id(cpTemp);
if (e) {
if (data->engine) {
ENGINE_free(data->engine);
}
data->engine = e;
}
else {
failf(data, "SSL Engine '%s' not found", cpTemp);
return CURLE_SSL_ENGINE_NOTFOUND;
}
}
}
#else
return CURLE_SSL_ENGINE_NOTFOUND;
#endif
break;
case CURLOPT_SSLENGINE_DEFAULT:
#ifdef HAVE_OPENSSL_ENGINE_H
if (data->engine) {
if (ENGINE_set_default(data->engine, ENGINE_METHOD_ALL) > 0) {
#ifdef DEBUG
fprintf(stderr,"set default crypto engine\n");
#endif
}
else {
#ifdef DEBUG
failf(data, "set default crypto engine failed");
#endif
return CURLE_SSL_ENGINE_SETFAILED;
}
}
#endif
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_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 = 0;
break;
case CURLOPT_NOSIGNAL:
data->set.no_signal = va_arg(param, long) ? TRUE : FALSE;
break;
case CURLOPT_SHARE:
{
curl_share *set;
set = va_arg(param, curl_share *);
if(data->share)
data->share->dirty--;
data->share = set;
data->share->dirty++;
}
break;
case CURLOPT_PROXYTYPE:
data->set.proxytype = va_arg(param, long);
break;
default:
return CURLE_FAILED_INIT;
}
return CURLE_OK;
}
CURLcode Curl_disconnect(struct connectdata *conn)
{
if(!conn)
return CURLE_OK;
if(conn->bits.rangestringalloc) {
free(conn->range);
conn->bits.rangestringalloc = FALSE;
}
if(-1 != conn->connectindex) {
infof(conn->data, "Closing connection #%d\n", conn->connectindex);
conn->data->state.connects[conn->connectindex] = NULL;
}
if(conn->curl_disconnect)
conn->curl_disconnect(conn);
if(conn->proto.generic)
free(conn->proto.generic);
if(conn->newurl)
free(conn->newurl);
if(conn->path)
free(conn->path);
#ifdef USE_SSLEAY
Curl_SSL_Close(conn);
#endif
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.accept_encoding)
free(conn->allocptr.accept_encoding);
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);
return CURLE_OK;
}
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 = 0;
sval = select(sock + 1, &check_set, 0, 0, &to);
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->bits.httpproxy || needle->protocol&PROT_SSL) {
if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
continue;
if(strequal(needle->protostr, check->protostr) &&
strequal(needle->name, check->name) &&
(needle->remote_port == check->remote_port) ) {
if(strequal(needle->protostr, "FTP")) {
if(!strequal(needle->data->state.user, check->proto.ftp->user) ||
!strequal(needle->data->state.passwd, check->proto.ftp->passwd)) {
continue;
}
}
match = TRUE;
}
}
else {
if(check->bits.httpproxy &&
strequal(needle->proxyhost, check->proxyhost) &&
needle->port == check->port) {
match = TRUE;
}
}
if(match) {
bool dead = SocketIsDead(check->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 int
ConnectionKillOne(struct SessionHandle *data)
{
long i;
struct connectdata *conn;
int highscore=-1;
int connindex=-1;
int score;
CURLcode result;
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) {
result = Curl_disconnect(data->state.connects[connindex]);
data->state.connects[connindex] = NULL;
}
return connindex;
}
static unsigned int
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,
int sock)
{
unsigned char socksreq[600];
int actualread;
int written;
CURLcode result;
Curl_nonblock(sock, FALSE);
socksreq[0] = 5;
socksreq[1] = (char)(proxy_name[0] ? 2 : 1);
socksreq[2] = 0;
socksreq[3] = 2;
result = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
&written);
if ((result != 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 = strlen(proxy_name);
pwlen = strlen(proxy_password);
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;
result = Curl_write(conn, sock, (char *)socksreq, len, &written);
if ((result != CURLE_OK) || (len != written)) {
failf(conn->data, "Failed to send SOCKS5 sub-negotiation request.");
return 1;
}
result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
if ((result != CURLE_OK) || (actualread != 2)) {
failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response.");
return 1;
}
if ((socksreq[0] != 5) ||
(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;
{
#ifndef ENABLE_IPV6
struct Curl_dns_entry *dns;
Curl_addrinfo *hp=NULL;
dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port);
if(dns)
hp=dns->addr;
if (hp && hp->h_addr_list[0]) {
socksreq[4] = ((char*)hp->h_addr_list[0])[0];
socksreq[5] = ((char*)hp->h_addr_list[0])[1];
socksreq[6] = ((char*)hp->h_addr_list[0])[2];
socksreq[7] = ((char*)hp->h_addr_list[0])[3];
Curl_resolv_unlock(dns);
}
else {
failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
conn->hostname);
return 1;
}
#else
failf(conn->data,
"%s:%d has an internal error an needs to be fixed to work",
__FILE__, __LINE__);
return 1;
#endif
}
*((unsigned short*)&socksreq[8]) = htons(conn->remote_port);
{
const int packetsize = 10;
result = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
if ((result != 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_ipconnect *addr;
result= Curl_connecthost(conn,
hostaddr,
conn->port,
&conn->firstsocket,
&addr,
connected);
if(CURLE_OK == result) {
conn->connect_addr = hostaddr;
#ifdef ENABLE_IPV6
conn->serv_addr = addr;
#else
memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
memcpy((char *)&(conn->serv_addr.sin_addr),
(struct in_addr *)addr, sizeof(struct in_addr));
conn->serv_addr.sin_family = hostaddr->addr->h_addrtype;
conn->serv_addr.sin_port = htons((unsigned short)conn->port);
#endif
if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
return handleSock5Proxy(conn->data->state.proxyuser,
conn->data->state.proxypasswd,
conn,
conn->firstsocket) ?
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,
struct Curl_dns_entry *dns)
{
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
#endif
struct SessionHandle *data = conn->data;
#ifdef ENABLE_IPV6
(void)dns;
{
char hbuf[NI_MAXHOST];
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
struct addrinfo *ai = conn->serv_addr;
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0,
niflags)) {
snprintf(hbuf, sizeof(hbuf), "?");
}
if (ai->ai_canonname) {
infof(data, "Connected to %s (%s) port %d\n", ai->ai_canonname, hbuf,
conn->port);
} else {
infof(data, "Connected to %s port %d\n", hbuf, conn->port);
}
}
#else
{
Curl_addrinfo *hostaddr=dns->addr;
struct in_addr in;
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
infof(data, "Connected to %s (%s) port %d\n",
hostaddr?hostaddr->h_name:"",
#if defined(HAVE_INET_NTOA_R)
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
#else
inet_ntoa(in),
#endif
conn->port);
}
#endif
}
CURLcode Curl_protocol_connect(struct connectdata *conn,
struct Curl_dns_entry *hostaddr)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
Curl_pgrsTime(data, TIMER_CONNECT);
if(data->set.verbose)
verboseconnect(conn, hostaddr);
if(conn->curl_connect) {
conn->now = Curl_tvnow();
result = conn->curl_connect(conn);
}
return result;
}
static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata **in_connect)
{
char *tmp;
char *buf;
CURLcode result=CURLE_OK;
char resumerange[40]="";
struct connectdata *conn;
struct connectdata *conn_temp;
int urllen;
struct Curl_dns_entry *hostaddr;
#ifdef HAVE_ALARM
unsigned int prev_alarm=0;
#endif
char endbracket;
#ifdef HAVE_SIGACTION
struct sigaction keep_sigact;
bool keep_copysig=FALSE;
#else
#ifdef HAVE_SIGNAL
void *keep_sigact;
#endif
#endif
if(!data->change.url)
return CURLE_URL_MALFORMAT;
conn = (struct connectdata *)malloc(sizeof(struct connectdata));
if(!conn) {
*in_connect = NULL;
return CURLE_OUT_OF_MEMORY;
}
*in_connect = conn;
memset(conn, 0, sizeof(struct connectdata));
conn->data = data;
conn->firstsocket = -1;
conn->secondarysocket = -1;
conn->connectindex = -1;
conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
(data->set.proxytype == CURLPROXY_HTTP))?
TRUE:FALSE;
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.close = TRUE;
conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
conn->maxdownload = -1;
conn->created = Curl_tvnow();
conn->data->progress.start = conn->created;
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;
#define LEAST_PATH_ALLOC 256
urllen=strlen(data->change.url);
if(urllen < LEAST_PATH_ALLOC)
urllen=LEAST_PATH_ALLOC;
conn->path=(char *)malloc(urllen);
if(NULL == conn->path)
return CURLE_OUT_OF_MEMORY;
if((2 == sscanf(data->change.url, "%64[^:]://%[^\n]",
conn->protostr,
conn->path)) && strequal(conn->protostr, "file")) {
if(conn->path[0] != '/') {
char *ptr=strchr(conn->path, '/');
if(ptr) {
if(ptr[1] && ('/' == ptr[1]))
ptr++;
strcpy(conn->path, ptr);
}
}
strcpy(conn->protostr, "file");
}
else {
strcpy(conn->gname, "curl.haxx.se");
strcpy(conn->path, "/");
if (2 > sscanf(data->change.url,
"%64[^\n:]://%512[^\n/]%[^\n]",
conn->protostr, conn->gname, conn->path)) {
if((1 > sscanf(data->change.url, "%512[^\n/]%[^\n]",
conn->gname, conn->path)) ) {
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
if(checkprefix("FTP", conn->gname)) {
strcpy(conn->protostr, "ftp");
}
else if(checkprefix("GOPHER", conn->gname))
strcpy(conn->protostr, "gopher");
#ifdef USE_SSLEAY
else if(checkprefix("HTTPS", conn->gname))
strcpy(conn->protostr, "https");
else if(checkprefix("FTPS", conn->gname))
strcpy(conn->protostr, "ftps");
#endif
else if(checkprefix("TELNET", conn->gname))
strcpy(conn->protostr, "telnet");
else if (checkprefix("DICT", conn->gname))
strcpy(conn->protostr, "DICT");
else if (checkprefix("LDAP", conn->gname))
strcpy(conn->protostr, "LDAP");
else {
strcpy(conn->protostr, "http");
}
conn->protocol |= PROT_MISSING;
}
}
buf = data->state.buffer;
if(conn->bits.proxy_user_passwd) {
data->state.proxyuser[0] =0;
data->state.proxypasswd[0]=0;
if(*data->set.proxyuserpwd != ':') {
sscanf(data->set.proxyuserpwd, "%127[^:]:%127[^\n]",
data->state.proxyuser, data->state.proxypasswd);
}
else
sscanf(data->set.proxyuserpwd+1, "%127[^\n]", data->state.proxypasswd);
if( !data->state.proxypasswd[0] ) {
if(data->set.fpasswd( data->set.passwd_client,
"proxy password:",
data->state.proxypasswd,
sizeof(data->state.proxypasswd))) {
failf(data, "Bad password from password callback");
return CURLE_BAD_PASSWORD_ENTERED;
}
}
}
conn->name = conn->gname;
conn->ppath = conn->path;
conn->hostname = conn->name;
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) {
unsigned int namelen;
char *endptr = strchr(conn->name, ':');
if(endptr)
namelen=endptr-conn->name;
else
namelen=strlen(conn->name);
if(strlen(nope) <= namelen) {
char *checkn=
conn->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(*protop++);
strcpy(envp, "_proxy");
prox=curl_getenv(proxy_env);
if(!prox && !strequal("http_proxy", proxy_env)) {
for(envp = proxy_env; *envp; envp++)
*envp = toupper(*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) {
data->change.proxy = proxy;
data->change.proxy_alloc=TRUE;
conn->bits.httpproxy = TRUE;
}
}
}
if(no_proxy)
free(no_proxy);
}
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) {
snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
conn->range=strdup(resumerange);
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->ppath = strchr(&conn->path[1], '/');
if (conn->ppath == NULL)
conn->ppath = conn->path;
}
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;
if(strequal(conn->protostr, "FTPS")) {
#ifdef USE_SSLEAY
conn->protocol |= PROT_FTPS|PROT_SSL;
#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_FTP;
conn->remote_port = PORT_FTP;
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_disconnect = Curl_ftp_disconnect;
}
conn->ppath++;
type=strstr(conn->ppath, ";type=");
if(!type) {
type=strstr(conn->gname, ";type=");
}
if(type) {
char command;
*type=0;
command = toupper(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;
result = Curl_file_connect(conn);
if(CURLE_OK == result) {
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((1 == sscanf(conn->name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
(']' == endbracket)) {
conn->bits.ipv6_ip = TRUE;
conn->name++;
conn->hostname++;
tmp = strchr(conn->name, ']');
*tmp = 0;
tmp++;
if(':' != *tmp)
tmp = NULL;
}
else
tmp = strrchr(conn->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->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->proxyhost = strdup(proxyptr);
free(proxydup);
}
data->state.user[0] =0;
data->state.passwd[0]=0;
if (conn->protocol & (PROT_FTP|PROT_HTTP)) {
char *ptr=strchr(conn->name, '@');
char *userpass = conn->name;
if(ptr != NULL) {
conn->name = conn->hostname = ++ptr;
if (data->set.use_netrc != CURL_NETRC_REQUIRED) {
conn->bits.user_passwd = 1;
if(*userpass != ':') {
sscanf(userpass, "%127[^:@]:%127[^@]",
data->state.user, data->state.passwd);
}
else
sscanf(userpass, ":%127[^@]", data->state.passwd);
if(data->state.user[0]) {
char *newname=curl_unescape(data->state.user, 0);
if(strlen(newname) < sizeof(data->state.user)) {
strcpy(data->state.user, newname);
}
free(newname);
}
if (data->state.passwd[0]) {
char *newpasswd=curl_unescape(data->state.passwd, 0);
if(strlen(newpasswd) < sizeof(data->state.passwd)) {
strcpy(data->state.passwd, newpasswd);
}
free(newpasswd);
}
}
}
}
if (data->set.userpwd != NULL) {
if(*data->set.userpwd != ':') {
sscanf(data->set.userpwd, "%127[^:]:%127[^\n]",
data->state.user, data->state.passwd);
}
else
sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd);
}
if (data->set.use_netrc != CURL_NETRC_IGNORED &&
data->state.passwd[0] == '\0' ) {
if(Curl_parsenetrc(conn->hostname,
data->state.user,
data->state.passwd)) {
infof(data, "Couldn't find host %s in the .netrc file, using defaults",
conn->hostname);
} else
conn->bits.user_passwd = 1;
}
if(conn->bits.user_passwd &&
!data->state.passwd[0] ) {
if(data->set.fpasswd(data->set.passwd_client,
"password:", data->state.passwd,
sizeof(data->state.passwd)))
return CURLE_BAD_PASSWORD_ENTERED;
}
if ( (conn->protocol & (PROT_FTP|PROT_HTTP)) &&
!conn->bits.user_passwd) {
strcpy(data->state.user, CURL_DEFAULT_USER);
strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD);
}
if(!data->set.reuse_fresh &&
ConnectionExists(data, conn, &conn_temp)) {
struct connectdata *old_conn = conn;
char *path = old_conn->path;
char *ppath = old_conn->ppath;
if(old_conn->proxyhost)
free(old_conn->proxyhost);
conn = conn_temp;
strcpy(conn->gname, old_conn->gname);
conn->hostname = conn->gname;
conn->name = &conn->gname[old_conn->name - old_conn->gname];
free(conn->path);
conn->path = path;
conn->ppath = ppath;
conn->bits.reuse = TRUE;
conn->bits.chunk = FALSE;
conn->maxdownload = -1;
free(old_conn);
conn->resume_from = data->set.set_resume_from;
if (conn->resume_from) {
snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
if (conn->bits.rangestringalloc == TRUE)
free(conn->range);
conn->range = strdup(resumerange);
conn->bits.use_range = TRUE;
conn->bits.rangestringalloc = TRUE;
}
else if (data->set.set_range) {
conn->range = strdup(data->set.set_range);
conn->bits.rangestringalloc = TRUE;
conn->bits.use_range = TRUE;
}
*in_connect = conn;
infof(data, "Re-using existing connection! (#%d)\n", conn->connectindex);
}
else {
ConnectionStore(data, conn);
}
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
#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
}
if(conn->bits.reuse) {
hostaddr = NULL;
}
else if(!data->change.proxy || !*data->change.proxy) {
conn->port = conn->remote_port;
hostaddr = Curl_resolv(data, conn->name, conn->port);
if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", conn->name);
result = CURLE_COULDNT_RESOLVE_HOST;
}
}
else {
hostaddr = Curl_resolv(data, conn->proxyhost, conn->port);
if(!hostaddr) {
failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
result = CURLE_COULDNT_RESOLVE_PROXY;
}
}
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
#ifdef HAVE_ALARM
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) {
long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
long alarm_set;
alarm_set = prev_alarm - elapsed_ms/1000;
if(alarm_set<=0) {
alarm(1);
result = CURLE_OPERATION_TIMEOUTED;
failf(data, "Previous alarm fired off!");
}
else
alarm(alarm_set);
}
else
alarm(0);
}
#endif
if(result)
return result;
if(conn->bits.proxy_user_passwd) {
char *authorization;
snprintf(data->state.buffer, BUFSIZE, "%s:%s",
data->state.proxyuser, data->state.proxypasswd);
if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
&authorization) >= 0) {
if(conn->allocptr.proxyuserpwd)
free(conn->allocptr.proxyuserpwd);
conn->allocptr.proxyuserpwd =
aprintf("Proxy-authorization: Basic %s\015\012", authorization);
free(authorization);
}
}
if((conn->protocol&PROT_HTTP) ||
(data->change.proxy && *data->change.proxy)) {
if(data->set.useragent) {
if(conn->allocptr.uagent)
free(conn->allocptr.uagent);
conn->allocptr.uagent =
aprintf("User-Agent: %s\015\012", data->set.useragent);
}
}
if(data->set.encoding) {
if(conn->allocptr.accept_encoding)
free(conn->allocptr.accept_encoding);
conn->allocptr.accept_encoding =
aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
}
conn->bytecount = 0;
conn->headerbytecount = 0;
if(-1 == conn->firstsocket) {
bool connected;
result = ConnectPlease(conn, hostaddr, &connected);
if(connected)
result = Curl_protocol_connect(conn, hostaddr);
if(CURLE_OK != result)
return result;
}
else {
Curl_pgrsTime(data, TIMER_CONNECT);
if(data->set.verbose)
verboseconnect(conn, hostaddr);
}
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)
{
CURLcode code;
struct connectdata *conn;
code = CreateConnection(data, in_connect);
if(CURLE_OK != code) {
conn = (struct connectdata *)*in_connect;
if(conn) {
Curl_disconnect(conn);
*in_connect = NULL;
}
}
return code;
}
CURLcode Curl_done(struct connectdata *conn)
{
struct SessionHandle *data=conn->data;
CURLcode result;
if(conn->bits.rangestringalloc) {
free(conn->range);
conn->bits.rangestringalloc = FALSE;
}
if(conn->newurl) {
free(conn->newurl);
conn->newurl = NULL;
}
if(conn->connect_addr)
Curl_resolv_unlock(conn->connect_addr);
#if defined(MALLOCDEBUG) && defined(AGGRESIVE_TEST)
Curl_hash_apply(data->hostcache,
NULL, Curl_scan_cache_used);
#endif
if(conn->curl_done)
result = conn->curl_done(conn);
else
result = CURLE_OK;
Curl_pgrsDone(conn);
if(data->set.reuse_forbid ||
((CURLE_OK == result) && conn->bits.close))
result = Curl_disconnect(conn);
else
infof(data, "Connection #%d left intact\n", conn->connectindex);
return result;
}
CURLcode Curl_do(struct connectdata **connp)
{
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);
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);
if(CURLE_OK == result) {
result = Curl_connect(data, connp);
if(CURLE_OK == result)
result = conn->curl_do(*connp);
}
}
}
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;
}