Newer
Older
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
* $Id$
*****************************************************************************/
#include "setup.h"
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
#include <winsock.h>
#include <time.h>
#include <io.h>
#else
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <netdb.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifndef HAVE_SELECT
#error "We can't compile without select() support!"
#endif
#ifndef HAVE_SOCKET
#error "We can't compile without socket() support!"
#endif
#endif
#include "urldata.h"
#include "netrc.h"
#include "formdata.h"
#include "base64.h"
#include "ssluse.h"
#include "hostip.h"
#include "if2ip.h"
Daniel Stenberg
committed
#include "transfer.h"
#include "sendf.h"
#include "getpass.h"
#include "progress.h"
#include "cookie.h"
#include "escape.h"
/* And now for the protocols */
#include "ftp.h"
#include "dict.h"
#include "telnet.h"
#include "http.h"
#include "file.h"
#include "ldap.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
#ifdef MALLOCDEBUG
#include "memdebug.h"
#endif
/* Local static prototypes */
static int ConnectionKillOne(struct UrlData *data);
static bool ConnectionExists(struct UrlData *data,
struct connectdata *needle,
struct connectdata **usethis);
static unsigned int ConnectionStore(struct UrlData *data,
struct connectdata *conn);
CURLcode Curl_close(CURL *curl)
struct UrlData *data=(struct UrlData *)curl;
/* Loop through all open connections and kill them one by one */
while(-1 != ConnectionKillOne(data));
if(data->bits.proxystringalloc) {
data->bits.proxystringalloc=FALSE;;
free(data->proxy);
data->proxy=NULL;
/* Since we allocated the string the previous round, it means that we
"discovered" the proxy in the environment variables and thus we must
switch off that knowledge again... */
data->bits.httpproxy=FALSE;
if(data->bits.rangestringalloc) {
free(data->range);
data->range=NULL;
data->bits.rangestringalloc=0; /* free now */
/* check for allocated [URL] memory to free: */
if(data->freethis)
free(data->freethis);
if(data->headerbuff)
free(data->headerbuff);
if(data->free_referer)
free(data->referer);
if(data->bits.urlstringalloc)
/* the URL is allocated, free it! */
free(data->url);
Curl_cookie_cleanup(data->cookies);
/* free the connection cache */
free(data->connects);
static
int my_getpass(void *clientp, char *prompt, char* buffer, int buflen )
{
char *retbuf;
retbuf = getpass_r(prompt, buffer, buflen);
if(NULL == retbuf)
return 1;
else
return 0; /* success */
}
CURLcode Curl_open(CURL **curl, char *url)
{
/* We don't yet support specifying the URL at this point */
/* Very simple start-up: alloc the struct, init it with zeroes and return */
data = (struct UrlData *)malloc(sizeof(struct UrlData));
memset(data, 0, sizeof(struct UrlData));
/* We do some initial setup here, all those fields that can't be just 0 */
data-> headerbuff=(char*)malloc(HEADERSIZE);
if(!data->headerbuff) {
free(data); /* free the memory again */
return CURLE_OUT_OF_MEMORY;
}
Daniel Stenberg
committed
data->headersize=HEADERSIZE;
data->out = stdout; /* default output to stdout */
data->in = stdin; /* default input from stdin */
data->err = stderr; /* default stderr to stderr */
/* use fwrite as default function to store output */
data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite;
/* use fread as default function to read input */
data->fread = (size_t (*)(char *, size_t, size_t, FILE *))fread;
/* set the default passwd function */
data->fpasswd = my_getpass;
data->infilesize = -1; /* we don't know any size */
data->current_speed = -1; /* init to negative == impossible */
Daniel Stenberg
committed
data->httpreq = HTTPREQ_GET; /* Default HTTP request */
/* create an array with connection data struct pointers */
data->numconnects = 5; /* hard-coded right now */
data->connects = (struct connectdata **)
malloc(sizeof(struct connectdata *) * data->numconnects);
if(!data->connects) {
free(data);
return CURLE_OUT_OF_MEMORY;
}
memset(data->connects, 0, sizeof(struct connectdata *)*data->numconnects);
}
/* this is a very serious error */
CURLcode Curl_setopt(CURL *curl, CURLoption option, ...)
{
struct UrlData *data = curl;
va_list param;
char *cookiefile;
va_start(param, option);
switch(option) {
data->bits.verbose = va_arg(param, long)?TRUE:FALSE;
data->bits.http_include_header = va_arg(param, long)?TRUE:FALSE;
data->bits.hide_progress = va_arg(param, long)?TRUE:FALSE;
if(data->bits.hide_progress)
data->progress.flags |= PGRS_HIDE;
break;
case CURLOPT_NOBODY:
data->bits.no_body = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FAILONERROR:
data->bits.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
data->bits.upload = va_arg(param, long)?TRUE:FALSE;
if(data->bits.upload)
/* If this is HTTP, PUT is what's needed to "upload" */
data->httpreq = HTTPREQ_PUT;
case CURLOPT_FILETIME:
data->bits.get_filetime = va_arg(param, long)?TRUE:FALSE;
break;
data->bits.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
data->bits.ftp_append = va_arg(param, long)?TRUE:FALSE;
data->bits.use_netrc = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FOLLOWLOCATION:
data->bits.http_follow_location = va_arg(param, long)?TRUE:FALSE;
data->bits.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
data->bits.http_put = va_arg(param, long)?TRUE:FALSE;
if(data->bits.http_put)
data->httpreq = HTTPREQ_PUT;
data->bits.mute = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_TIMECONDITION:
data->timecondition = va_arg(param, long);
break;
data->timevalue = va_arg(param, long);
break;
Daniel Stenberg
committed
data->ssl.version = va_arg(param, long);
cookiefile = (char *)va_arg(param, void *);
if(cookiefile) {
data->cookies = Curl_cookie_init(cookiefile);
data->writeheader = (FILE *)va_arg(param, FILE *);
break;
data->cookie = va_arg(param, char *);
break;
data->errorbuffer = va_arg(param, char *);
break;
data->out = va_arg(param, FILE *);
break;
data->ftpport = va_arg(param, char *);
data->bits.ftp_use_port = data->ftpport?1:0;
data->headers = va_arg(param, struct curl_slist *);
data->customrequest = va_arg(param, char *);
if(data->customrequest)
data->httpreq = HTTPREQ_CUSTOM;
data->httppost = va_arg(param, struct HttpPost *);
data->bits.http_formpost = data->httppost?1:0;
if(data->bits.http_formpost)
data->httpreq = HTTPREQ_POST_FORM;
data->in = va_arg(param, FILE *);
break;
data->infilesize = va_arg(param, long);
break;
data->low_speed_limit=va_arg(param, long);
break;
data->low_speed_time=va_arg(param, long);
break;
data->url = va_arg(param, char *);
break;
data->use_port = va_arg(param, long);
case CURLOPT_POST:
/* Does this option serve a purpose anymore? */
data->bits.http_post = va_arg(param, long)?TRUE:FALSE;
if(data->bits.http_post)
data->httpreq = HTTPREQ_POST;
break;
data->postfields = va_arg(param, char *);
data->bits.http_post = data->postfields?TRUE:FALSE;
if(data->bits.http_post)
data->httpreq = HTTPREQ_POST;
case CURLOPT_POSTFIELDSIZE:
data->postfieldsize = va_arg(param, long);
break;
data->referer = va_arg(param, char *);
data->bits.http_set_referer = (data->referer && *data->referer)?1:0;
case CURLOPT_AUTOREFERER:
data->bits.http_auto_referer = va_arg(param, long)?1:0;
break;
data->proxy = va_arg(param, char *);
data->bits.httpproxy = data->proxy?1:0;
case CURLOPT_HTTPPROXYTUNNEL:
data->bits.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_PROXYPORT:
data->proxyport = va_arg(param, long);
data->timeout = va_arg(param, long);
break;
case CURLOPT_MAXREDIRS:
data->maxredirs = va_arg(param, long);
break;
data->useragent = va_arg(param, char *);
break;
data->userpwd = va_arg(param, char *);
data->bits.user_passwd = data->userpwd?1:0;
data->postquote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_PROGRESSFUNCTION:
data->fprogress = va_arg(param, curl_progress_callback);
data->progress.callback = TRUE; /* no longer internal */
break;
case CURLOPT_PROGRESSDATA:
data->progress_client = va_arg(param, void *);
break;
case CURLOPT_PASSWDFUNCTION:
data->fpasswd = va_arg(param, curl_passwd_callback);
break;
case CURLOPT_PASSWDDATA:
data->passwd_client = va_arg(param, void *);
break;
data->proxyuserpwd = va_arg(param, char *);
data->bits.proxy_user_passwd = data->proxyuserpwd?1:0;
data->range = va_arg(param, char *);
data->bits.set_range = data->range?1:0;
data->resume_from = va_arg(param, long);
break;
data->err = va_arg(param, FILE *);
break;
data->fwrite = va_arg(param, curl_write_callback);
data->fread = va_arg(param, curl_read_callback);
data->cert = va_arg(param, char *);
break;
data->cert_passwd = va_arg(param, char *);
break;
data->crlf = va_arg(param, long);
break;
data->quote = va_arg(param, struct curl_slist *);
break;
case CURLOPT_INTERFACE:
data->device = va_arg(param, char *);
break;
case CURLOPT_KRB4LEVEL:
data->krb4_level = va_arg(param, char *);
data->bits.krb4=data->krb4_level?TRUE:FALSE;
break;
Daniel Stenberg
committed
case CURLOPT_SSL_VERIFYPEER:
data->ssl.verifypeer = va_arg(param, long);
break;
case CURLOPT_CAINFO:
data->ssl.CAfile = va_arg(param, char *);
data->ssl.CApath = NULL; /*This does not work on windows.*/
break;
case CURLOPT_TELNETOPTIONS:
data->telnet_options = va_arg(param, struct curl_slist *);
break;
default:
/* unknown tag and its companion, just ignore: */
return CURLE_READ_ERROR; /* correct this */
#if !defined(WIN32)||defined(__CYGWIN32__)
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
static
RETSIGTYPE alarmfunc(int signal)
{
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void)signal;
return;
}
#endif
CURLcode Curl_disconnect(struct connectdata *conn)
if(conn->curl_disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->curl_disconnect(conn);
if(conn->proto.generic)
free(conn->proto.generic);
if(conn->hp) /* host name info */
freeaddrinfo(conn->hp);
if(conn->hostent_buf) /* host name info */
free(conn->hostent_buf);
if(conn->path) /* the URL path part */
free(conn->path);
#ifdef USE_SSLEAY
if (conn->ssl.use) {
if(conn->ssl.handle) {
(void)SSL_shutdown(conn->ssl.handle);
SSL_set_connect_state(conn->ssl.handle);
SSL_free (conn->ssl.handle);
conn->ssl.handle = NULL;
}
if(conn->ssl.ctx) {
SSL_CTX_free (conn->ssl.ctx);
conn->ssl.ctx = NULL;
}
conn->ssl.use = FALSE; /* get back to ordinary socket usage */
}
#endif /* USE_SSLEAY */
/* close possibly still open sockets */
if(-1 != conn->secondarysocket)
sclose(conn->secondarysocket);
if(-1 != conn->firstsocket)
sclose(conn->firstsocket);
if(conn->allocptr.proxyuserpwd)
free(conn->allocptr.proxyuserpwd);
if(conn->allocptr.uagent)
free(conn->allocptr.uagent);
if(conn->allocptr.userpwd)
free(conn->allocptr.userpwd);
if(conn->allocptr.rangeline)
free(conn->allocptr.rangeline);
if(conn->allocptr.ref)
free(conn->allocptr.ref);
if(conn->allocptr.cookie)
free(conn->allocptr.cookie);
if(conn->allocptr.host)
free(conn->allocptr.host);
if(conn->proxyhost)
free(conn->proxyhost);
free(conn); /* free all the connection oriented data */
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
/*
* This function should return TRUE if the socket is to be assumed to
* be dead. Most commonly this happens when the server has closed the
* connection due to inactivity.
*/
static bool SocketIsDead(int sock)
{
int sval;
bool ret_val = TRUE;
fd_set check_set;
struct timeval to;
FD_ZERO(&check_set);
FD_SET(sock,&check_set);
to.tv_sec = 0;
to.tv_usec = 1;
sval = select(sock + 1, &check_set, 0, 0, &to);
if(sval == 0)
/* timeout */
ret_val = FALSE;
return ret_val;
}
/*
* Given one filled in connection struct, this function should detect if there
* already is one that have all the significant details exactly the same and
* thus should be used instead.
*/
static bool
ConnectionExists(struct UrlData *data,
struct connectdata *needle,
struct connectdata **usethis)
size_t i;
struct connectdata *check;
for(i=0; i< data->numconnects; i++) {
/*
* Note that if we use a HTTP proxy, we check connections to that
* proxy and not to the actual remote server.
*/
check = data->connects[i];
if(!check)
/* NULL pointer means not filled-in entry */
continue;
if(!needle->bits.httpproxy) {
/* The requested connection does not use a HTTP proxy */
if(strequal(needle->protostr, check->protostr) &&
strequal(needle->name, check->name) &&
(needle->port == check->port) ) {
if(strequal(needle->protostr, "FTP")) {
/* This is FTP, verify that we're using the same name and
password as well */
if(!strequal(needle->data->user, check->proto.ftp->user) ||
!strequal(needle->data->passwd, check->proto.ftp->passwd)) {
/* one of them was different */
continue;
}
}
dead = SocketIsDead(check->firstsocket);
if(dead) {
infof(data, "Connection %d seems to be dead!\n", i);
Curl_disconnect(check); /* disconnect resources */
data->connects[i]=NULL; /* nothing here */
continue; /* try another one now */
}
}
*usethis = check;
return TRUE; /* yes, we found one to use! */
}
else { /* The requested needle connection is using a proxy,
is the checked one using the same? */
if(check->bits.httpproxy &&
strequal(needle->proxyhost, check->proxyhost) &&
needle->port == check->port) {
/* This is the same proxy connection, use it! */
*usethis = check;
return TRUE;
}
}
}
return FALSE; /* no matching connecting exists */
}
/*
* This function frees/closes a connection in the connection cache. This
* should take the previously set policy into account when deciding which
* of the connections to kill.
*/
static int
ConnectionKillOne(struct UrlData *data)
{
size_t i;
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
int highscore=-1;
int connindex=-1;
int score;
CURLcode result;
for(i=0; i< data->numconnects; i++) {
conn = data->connects[i];
if(!conn)
continue;
/*
* By using the set policy, we score each connection.
*/
switch(data->closepolicy) {
default:
score = 1; /* not implemented yet */
break;
}
if(score > highscore) {
highscore = score;
connindex = i;
}
}
if(connindex >= 0) {
/* the winner gets the honour of being disconnected */
result = Curl_disconnect(data->connects[connindex]);
/* clean the array entry */
data->connects[connindex] = NULL;
}
return connindex; /* return the available index or -1 */
}
/*
* The given input connection struct pointer is to be stored. If the "cache"
* is already full, we must clean out the most suitable using the previously
* set policy.
*
* The given connection should be unique. That must've been checked prior to
* this call.
*/
static unsigned int
ConnectionStore(struct UrlData *data,
struct connectdata *conn)
{
size_t i;
for(i=0; i< data->numconnects; i++) {
if(!data->connects[i])
break;
}
if(i == data->numconnects) {
/* there was no room available, kill one */
i = ConnectionKillOne(data);
infof(data, "Connection (#%d) was killed to make room\n", i);
}
data->connects[i] = conn; /* fill in this */
conn->connectindex = i; /* make the child know where the pointer to this
particular data is stored */
return i;
}
static CURLcode ConnectPlease(struct UrlData *data,
struct connectdata *conn)
{
#ifndef ENABLE_IPV6
conn->firstsocket = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
memcpy((char *)&(conn->serv_addr.sin_addr),
conn->hp->h_addr, conn->hp->h_length);
conn->serv_addr.sin_family = conn->hp->h_addrtype;
conn->serv_addr.sin_port = htons(conn->port);
Daniel Stenberg
committed
#endif
#if !defined(WIN32)||defined(__CYGWIN32__)
/* We don't generally like checking for OS-versions, we should make this
HAVE_XXXX based, although at the moment I don't have a decent test for
this! */
#ifdef HAVE_INET_NTOA
#ifndef INADDR_NONE
#define INADDR_NONE (unsigned long) ~0
/*************************************************************
* Select device to bind socket to
*************************************************************/
if (data->device && (strlen(data->device)<255)) {
struct sockaddr_in sa;
struct hostent *h=NULL;
char *hostdataptr=NULL;
size_t size;
char myhost[256] = "";
unsigned long in;
if(Curl_if2ip(data->device, myhost, sizeof(myhost))) {
h = Curl_gethost(data, myhost, &hostdataptr);
}
else {
if(strlen(data->device)>1) {
h = Curl_gethost(data, data->device, &hostdataptr);
}
if(h) {
/* we know data->device is shorter than the myhost array */
strcpy(myhost, data->device);
}
}
if(! *myhost) {
/* need to fix this
h=Curl_gethost(data,
getmyhost(*myhost,sizeof(myhost)),
hostent_buf,
sizeof(hostent_buf));
*/
printf("in here\n");
}
infof(data, "We connect from %s\n", myhost);
if ( (in=inet_addr(myhost)) != INADDR_NONE ) {
if ( h ) {
memset((char *)&sa, 0, sizeof(sa));
memcpy((char *)&sa.sin_addr,
h->h_addr,
h->h_length);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = in;
sa.sin_port = 0; /* get any port */
if( bind(conn->firstsocket, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
/* we succeeded to bind */
struct sockaddr_in add;
size = sizeof(add);
if(getsockname(conn->firstsocket, (struct sockaddr *) &add,
(socklen_t *)&size)<0) {
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
failf(data, "getsockname() failed");
return CURLE_HTTP_PORT_FAILED;
}
}
else {
switch(errno) {
case EBADF:
failf(data, "Invalid descriptor: %d", errno);
break;
case EINVAL:
failf(data, "Invalid request: %d", errno);
break;
case EACCES:
failf(data, "Address is protected, user not superuser: %d", errno);
break;
case ENOTSOCK:
failf(data,
"Argument is a descriptor for a file, not a socket: %d",
errno);
break;
case EFAULT:
failf(data, "Inaccessable memory error: %d", errno);
break;
case ENAMETOOLONG:
failf(data, "Address too long: %d", errno);
break;
case ENOMEM:
failf(data, "Insufficient kernel memory was available: %d", errno);
break;
default:
failf(data,"errno %d\n");
} /* end of switch */
return CURLE_HTTP_PORT_FAILED;
} /* end of else */
} /* end of if h */
else {
failf(data,"could't find my own IP address (%s)", myhost);
return CURLE_HTTP_PORT_FAILED;
}
} /* end of inet_addr */
else {
failf(data, "could't find my own IP address (%s)", myhost);
return CURLE_HTTP_PORT_FAILED;
}
if(hostdataptr)
free(hostdataptr); /* allocated by Curl_gethost() */
} /* end of device selection support */
#endif /* end of HAVE_INET_NTOA */
#endif /* end of not WIN32 */
#endif /*ENABLE_IPV6*/
/*************************************************************
*************************************************************/
conn->firstsocket = -1;
for (ai = conn->hp; ai; ai = ai->ai_next) {
conn->firstsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (conn->firstsocket < 0)
if (connect(conn->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
close(conn->firstsocket);
conn->firstsocket = -1;
continue;
}
break;
}
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
failf(data, strerror(errno));
return CURLE_COULDNT_CONNECT;
}
#else
if (connect(conn->firstsocket,
(struct sockaddr *) &(conn->serv_addr),
sizeof(conn->serv_addr)
) < 0) {
switch(errno) {
#ifdef ECONNREFUSED
/* this should be made nicer */
case ECONNREFUSED:
failf(data, "Connection refused");
break;
case EFAULT:
failf(data, "Invalid socket address: %d",errno);
break;
case EISCONN:
failf(data, "Socket already connected: %d",errno);
break;
case ETIMEDOUT:
failf(data, "Timeout while accepting connection, server busy: %d",errno);
break;
case ENETUNREACH:
failf(data, "Network is unreachable: %d",errno);
break;
case EADDRINUSE:
failf(data, "Local address already in use: %d",errno);
break;
case EINPROGRESS:
failf(data, "Socket is nonblocking and connection can not be completed immediately: %d",errno);
break;
case EALREADY:
failf(data, "Socket is nonblocking and a previous connection attempt not completed: %d",errno);
break;
case EAGAIN:
failf(data, "No more free local ports: %d",errno);
break;
case EACCES:
case EPERM:
failf(data, "Attempt to connect to broadcast address without socket broadcast flag or local firewall rule violated: %d",errno);
break;
#endif
case EINTR:
failf(data, "Connection timed out");
break;
default:
failf(data, "Can't connect to server: %d", errno);
break;
}
return CURLE_COULDNT_CONNECT;
}
#endif
return CURLE_OK;
}
static CURLcode Connect(struct UrlData *data,
struct connectdata **in_connect,
bool allow_port) /* allow data->use_port ? */
{
char *tmp;
char *buf;
CURLcode result;
char resumerange[40]="";
struct connectdata *conn;
struct connectdata *conn_temp;
char endbracket;
Daniel Stenberg
committed
#ifdef HAVE_SIGACTION
Daniel Stenberg
committed
#endif
/*************************************************************
* Check input data
*************************************************************/
if(!data->url)
return CURLE_URL_MALFORMAT;
/* First, split up the current URL in parts so that we can use the
parts for checking against the already present connections. In order
to not have to modify everything at once, we allocate a temporary
connection data struct and fill in for comparison purposes. */
conn = (struct connectdata *)malloc(sizeof(struct connectdata));
if(!conn) {
*in_connect = NULL; /* clear the pointer */
return CURLE_OUT_OF_MEMORY;
}
/* We must set the return variable as soon as possible, so that our
parent can cleanup any possible allocs we may have done before
any failure */
*in_connect = conn;
/* we have to init the struct */
memset(conn, 0, sizeof(struct connectdata));
/* and we setup a few fields in case we end up actually using this struct */
conn->data = data; /* remember our daddy */
conn->upload_bufsize = UPLOAD_BUFSIZE; /* default upload buffer size */
conn->firstsocket = -1; /* no file descriptor */
conn->secondarysocket = -1; /* no file descriptor */
conn->connectindex = -1; /* no index */
conn->bits.httpproxy = data->bits.httpproxy; /* proxy-or-not status */
/* Default protocol-indepent behaveiour doesn't support persistant
connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */
conn->bits.close = TRUE;
/***********************************************************
* We need to allocate memory to store the path in. We get the size of the