Newer
Older
conn->curl_do = Curl_ldap;
conn->curl_done = NULL; /* no LDAP-specific done */
#else
failf(data, LIBCURL_NAME
" was built with LDAP disabled!");
#endif
else if (strequal(conn->protostr, "FILE")) {
#ifndef CURL_DISABLE_FILE
conn->curl_do = Curl_file;
/* anyway, this is supposed to be the connect function so we better
at least check that the file is present here! */
result = Curl_file_connect(conn);
/* Setup a "faked" transfer that'll do nothing */
if(CURLE_OK == result) {
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */
}
return result;
#else
failf(data, LIBCURL_NAME
" was built with FILE disabled!");
#endif
/* We fell through all checks and thus we don't support the specified
protocol */
failf(data, "Unsupported protocol: %s", conn->protostr);
/*************************************************************
* Figure out the remote port number
*
* No matter if we use a proxy or not, we have to figure out the remote
* port number of various reasons.
*
* To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style. (RFC2732)
*
* The conn->name is currently [user:passwd@]host[:port] where host could
* be a hostname, IPv4 address or IPv6 address.
*************************************************************/
if((1 == sscanf(conn->name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
(']' == endbracket)) {
/* this is a RFC2732-style specified IP-address */
conn->name++; /* pass the starting bracket */
tmp = strchr(conn->name, ']');
*tmp = 0; /* zero terminate */
tmp++; /* pass the ending bracket */
if(':' != *tmp)
tmp = NULL; /* no port number available */
}
else
tmp = strrchr(conn->name, ':');
if (tmp) {
char *rest;
unsigned long port;
Daniel Stenberg
committed
port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
Daniel Stenberg
committed
if (rest != (tmp+1) && *rest == '\0') {
/* The colon really did have only digits after it,
* so it is either a port number or a mistake */
if (port > 0xffff) { /* Single unix standard says port numbers are
* 16 bits long */
failf(data, "Port number too large: %lu", port);
return CURLE_URL_MALFORMAT;
}
*tmp = '\0'; /* cut off the name there */
conn->remote_port = port;
}
Daniel Stenberg
committed
}
Daniel Stenberg
committed
if(data->change.proxy) {
/* If this is supposed to use a proxy, we need to figure out the proxy
host name name, so that we can re-use an existing connection
that may exist registered to the same proxy host. */
char *prox_portno;
char *endofprot;
/* We need to make a duplicate of the proxy so that we can modify the
string safely. */
Daniel Stenberg
committed
char *proxydup=strdup(data->change.proxy);
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
/* We use 'proxyptr' to point to the proxy name from now on... */
char *proxyptr=proxydup;
if(NULL == proxydup) {
failf(data, "memory shortage");
return CURLE_OUT_OF_MEMORY;
}
/* Daniel Dec 10, 1998:
We do the proxy host string parsing here. We want the host name and the
port name. Accept a protocol:// prefix, even though it should just be
ignored. */
/* 1. skip the protocol part if present */
endofprot=strstr(proxyptr, "://");
if(endofprot) {
proxyptr = endofprot+3;
}
/* allow user to specify proxy.server.com:1080 if desired */
prox_portno = strchr (proxyptr, ':');
if (prox_portno) {
*prox_portno = 0x0; /* cut off number from host name */
prox_portno ++;
/* now set the local port number */
conn->port = atoi(prox_portno);
}
Daniel Stenberg
committed
else if(data->set.proxyport) {
/* None given in the proxy string, then get the default one if it is
given */
Daniel Stenberg
committed
conn->port = data->set.proxyport;
}
/* now, clone the cleaned proxy host name */
conn->proxyhost = strdup(proxyptr);
free(proxydup); /* free the duplicate pointer and not the modified */
}
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
/*************************************************************
* Take care of user and password authentication stuff
*************************************************************/
/*
* Inputs: data->set.userpwd (CURLOPT_USERPWD)
* data->set.fpasswd (CURLOPT_PASSWDFUNCTION)
* data->set.use_netrc (CURLOPT_NETRC)
* conn->hostname
* netrc file
* hard-coded defaults
*
* Outputs: (almost :- all currently undefined)
* conn->bits.user_passwd - non-zero if non-default passwords exist
* conn->state.user - non-zero length if defined
* conn->state.passwd - ditto
* conn->hostname - remove user name and password
*/
/* At this point, we're hoping all the other special cases have
* been taken care of, so conn->hostname is at most
* [user[:password]]@]hostname
*
* We need somewhere to put the embedded details, so do that first.
*/
data->state.user[0] =0; /* to make everything well-defined */
data->state.passwd[0]=0;
if (conn->protocol & (PROT_FTP|PROT_HTTP)) {
/* This is a FTP or HTTP URL, we will now try to extract the possible
* user+password pair in a string like:
* ftp://user:password@ftp.my.site:8021/README */
char *ptr=strchr(conn->name, '@');
char *userpass = conn->name;
if(ptr != NULL) {
/* there's a user+password given here, to the left of the @ */
conn->name = conn->hostname = ++ptr;
/* So the hostname is sane. Only bother interpreting the
* results if we could care. It could still be wasted
* work because it might be overtaken by the programmatically
* set user/passwd, but doing that first adds more cases here :-(
*/
if (data->set.use_netrc != CURL_NETRC_REQUIRED) {
/* We could use the one in the URL */
conn->bits.user_passwd = 1; /* enable user+password */
if(*userpass != ':') {
/* the name is given, get user+password */
sscanf(userpass, "%127[^:@]:%127[^@]",
data->state.user, data->state.passwd);
}
else
/* no name given, get the password only */
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);
}
/* if the new name is longer than accepted, then just use
the unconverted name, it'll be wrong but what the heck */
free(newname);
}
if (data->state.passwd[0]) {
/* we have a password found in the URL, decode it! */
char *newpasswd=curl_unescape(data->state.passwd, 0);
if(strlen(newpasswd) < sizeof(data->state.passwd)) {
strcpy(data->state.passwd, newpasswd);
}
free(newpasswd);
}
}
}
}
/* Programmatically set password:
* - always applies, if available
* - takes precedence over the values we just set above
* so scribble it over the top.
* User-supplied passwords are assumed not to need unescaping.
*
* user_password is set in "inherite initial knowledge' above,
* so it doesn't have to be set in this block
*/
if (data->set.userpwd != NULL) {
if(*data->set.userpwd != ':') {
/* the name is given, get user+password */
sscanf(data->set.userpwd, "%127[^:]:%127[^\n]",
data->state.user, data->state.passwd);
}
else
/* no name given, get the password only */
sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd);
}
if (data->set.use_netrc != CURL_NETRC_IGNORED &&
data->state.passwd[0] == '\0' ) { /* need passwd */
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; /* enable user+password */
}
/* if we have a user but no password, ask for one */
if(conn->bits.user_passwd &&
!data->state.passwd[0] ) {
Daniel Stenberg
committed
if(data->set.fpasswd(data->set.passwd_client,
"password:", data->state.passwd,
sizeof(data->state.passwd)))
return CURLE_BAD_PASSWORD_ENTERED;
}
/* So we could have a password but no user; that's just too bad. */
/* If our protocol needs a password and we have none, use the defaults */
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);
/* This is the default password, so DON'T set conn->bits.user_passwd */
}
/*************************************************************
* Check the current list of connections to see if we can
* re-use an already existing one or if we have to create a
* new one.
*************************************************************/
/* reuse_fresh is set TRUE if we are told to use a fresh connection
by force */
Daniel Stenberg
committed
if(!data->set.reuse_fresh &&
ConnectionExists(data, conn, &conn_temp)) {
/*
* We already have a connection for this, we got the former connection
* in the conn_temp variable and thus we need to cleanup the one we
* just allocated before we can move along and use the previously
* existing one.
*/
Daniel Stenberg
committed
struct connectdata *old_conn = conn;
char *path = old_conn->path; /* setup the current path pointer properly */
char *ppath = old_conn->ppath; /* this is the modified path pointer */
Daniel Stenberg
committed
if(old_conn->proxyhost)
free(old_conn->proxyhost);
conn = conn_temp; /* use this connection from now on */
Daniel Stenberg
committed
Daniel Stenberg
committed
/* If we speak over a proxy, we need to copy the host name too, as it
might be another remote host even when re-using a connection */
strcpy(conn->gname, old_conn->gname); /* safe strcpy() */
Daniel Stenberg
committed
/* we need these pointers if we speak over a proxy */
conn->hostname = conn->gname;
conn->name = &conn->gname[old_conn->name - old_conn->gname];
Daniel Stenberg
committed
free(conn->path); /* free the previously allocated path pointer */
/* 'path' points to the allocated data, 'ppath' may have been advanced
to point somewhere within the 'path' area. */
conn->path = path;
conn->ppath = ppath;
/* re-use init */
conn->bits.reuse = TRUE; /* yes, we're re-using here */
conn->bits.chunk = FALSE; /* always assume not chunked unless told
otherwise */
conn->maxdownload = -1; /* might have been used previously! */
Daniel Stenberg
committed
free(old_conn); /* we don't need this anymore */
/*
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
*/
Daniel Stenberg
committed
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);
/* tell ourselves to fetch this range */
conn->range = strdup(resumerange);
conn->bits.use_range = TRUE; /* enable range download */
conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
}
Daniel Stenberg
committed
else if (data->set.set_range) {
/* There is a range, but is not a resume, useful for random ftp access */
Daniel Stenberg
committed
conn->range = strdup(data->set.set_range);
conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
conn->bits.use_range = TRUE; /* enable range download */
}
*in_connect = conn; /* return this instead! */
infof(data, "Re-using existing connection! (#%d)\n", conn->connectindex);
}
else {
/*
* This is a brand new connection, so let's store it in the connection
* cache of ours!
*/
ConnectionStore(data, conn);
}
/*************************************************************
* Set timeout if that is being used
*************************************************************/
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
Daniel Stenberg
committed
/*************************************************************
* Set signal handler to catch SIGALRM
* Store the old value to be able to set it back later!
*************************************************************/
#ifdef HAVE_SIGACTION
struct sigaction sigact;
sigaction(SIGALRM, NULL, &sigact);
keep_copysig = TRUE; /* yes, we have a copy */
Daniel Stenberg
committed
sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
/* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
sigact.sa_flags &= ~SA_RESTART;
#endif
/* now set the new struct */
sigaction(SIGALRM, &sigact, NULL);
#else
/* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL
keep_sigact = signal(SIGALRM, alarmfunc);
Daniel Stenberg
committed
#endif
#endif
/* We set the timeout on the name resolving phase first, separately from
* the download/upload part to allow a maximum time on everything. This is
* a signal-based timeout, why it won't work and shouldn't be used in
* multi-threaded environments. */
Daniel Stenberg
committed
#ifdef HAVE_ALARM
/* alarm() makes a signal get sent when the timeout fires off, and that
will abort system calls */
Daniel Stenberg
committed
prev_alarm = alarm(data->set.connecttimeout?
data->set.connecttimeout:
data->set.timeout);
/* We can expect the conn->created time to be "now", as that was just
recently set in the beginning of this function and nothing slow
has been done since then until now. */
#endif
}
/*************************************************************
* Resolve the name of the server or proxy
*************************************************************/
if(conn->bits.reuse) {
/* re-used connection, no resolving is necessary */
hostaddr = NULL;
}
else if(!data->change.proxy) {
/* If not connecting via a proxy, extract the port from the URL, if it is
* there, thus overriding any defaults that might have been set above. */
conn->port = conn->remote_port; /* it is the same port */
/* Resolve target host right on */
hostaddr = Curl_resolv(data, conn->name, conn->port);
if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", conn->name);
Daniel Stenberg
committed
result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
else {
/* This is a proxy that hasn't been resolved yet. */
hostaddr = Curl_resolv(data, conn->proxyhost, conn->port);
if(!hostaddr) {
failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
Daniel Stenberg
committed
result = CURLE_COULDNT_RESOLVE_PROXY;
/* don't return yet, we need to clean up the timeout first */
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
Daniel Stenberg
committed
#ifdef HAVE_ALARM
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
Daniel Stenberg
committed
#ifdef HAVE_SIGACTION
if(keep_copysig) {
/* we got a struct as it looked before, now put that one back nice
and clean */
sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
}
#else
#ifdef HAVE_SIGNAL
/* restore the previous SIGALRM handler */
signal(SIGALRM, keep_sigact);
#endif
Daniel Stenberg
committed
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
#endif
/* switch back the alarm() to either zero or to what it was before minus
the time we spent until now! */
if(prev_alarm) {
/* there was an alarm() set before us, now put it back */
long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
long alarm_set;
/* the alarm period is counted in even number of seconds */
alarm_set = prev_alarm - elapsed_ms/1000;
if(alarm_set<=0) {
/* if it turned negative, we should fire off a SIGALRM here, but we
won't, and zero would be to switch it off so we never set it to
less than 1! */
alarm(1);
result = CURLE_OPERATION_TIMEOUTED;
failf(data, "Previous alarm fired off!");
}
else
alarm(alarm_set);
}
else
alarm(0); /* just shut it off */
}
#endif
if(result)
return result;
/*************************************************************
* Proxy authentication
*************************************************************/
Daniel Stenberg
committed
if(conn->bits.proxy_user_passwd) {
Daniel Stenberg
committed
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);
/*************************************************************
* Send user-agent to HTTP proxies even if the target protocol
* isn't HTTP.
*************************************************************/
Daniel Stenberg
committed
if((conn->protocol&PROT_HTTP) || data->change.proxy) {
if(data->set.useragent) {
if(conn->allocptr.uagent)
free(conn->allocptr.uagent);
conn->allocptr.uagent =
Daniel Stenberg
committed
aprintf("User-Agent: %s\015\012", data->set.useragent);
Daniel Stenberg
committed
conn->bytecount = 0;
conn->headerbytecount = 0;
bool connected;
result = ConnectPlease(conn, hostaddr, &connected);
if(connected)
result = Curl_protocol_connect(conn, hostaddr);
Daniel Stenberg
committed
else {
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
if(data->set.verbose)
verboseconnect(conn, hostaddr);
Daniel Stenberg
committed
conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
set this here perhaps a second time */
#ifdef __EMX__
/* 20000330 mgs
* the check is quite a hack...
* we're calling _fsetmode to fix the problem with fwrite converting newline
* characters (you get mangled text files, and corrupted binary files when
* you download to stdout and redirect it to a file). */
Daniel Stenberg
committed
if ((data->set.out)->_handle == NULL) {
_fsetmode(stdout, "b");
}
#endif
Daniel Stenberg
committed
CURLcode Curl_connect(struct SessionHandle *data,
struct connectdata **in_connect)
{
CURLcode code;
struct connectdata *conn;
/* call the stuff that needs to be called */
code = CreateConnection(data, in_connect);
if(CURLE_OK != code) {
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
conn = (struct connectdata *)*in_connect;
Daniel Stenberg
committed
if(conn) {
Curl_disconnect(conn); /* close the connection */
Daniel Stenberg
committed
*in_connect = NULL; /* return a NULL */
}
CURLcode Curl_done(struct connectdata *conn)
Daniel Stenberg
committed
struct SessionHandle *data=conn->data;
/* cleanups done even if the connection is re-used */
if(conn->bits.rangestringalloc) {
free(conn->range);
conn->bits.rangestringalloc = FALSE;
}
/* Cleanup possible redirect junk */
if(conn->newurl) {
free(conn->newurl);
conn->newurl = NULL;
}
/* this calls the protocol-specific function pointer previously set */
if(conn->curl_done)
result = conn->curl_done(conn);
else
result = CURLE_OK;
Curl_pgrsDone(conn); /* done with the operation */
Daniel Stenberg
committed
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
forced us to close this no matter what we think.
if conn->bits.close is TRUE, it means that the connection should be
closed in spite of all our efforts to be nice, due to protocol
restrictions in our or the server's end */
Daniel Stenberg
committed
if(data->set.reuse_forbid ||
((CURLE_OK == result) && conn->bits.close))
result = Curl_disconnect(conn); /* close the connection */
else
Daniel Stenberg
committed
infof(data, "Connection #%d left intact\n", conn->connectindex);
CURLcode Curl_do(struct connectdata **connp)
CURLcode result=CURLE_OK;
struct connectdata *conn = *connp;
struct SessionHandle *data=conn->data;
conn->do_more = FALSE; /* by default there's no curl_do_more() to use */
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->curl_do(conn);
/* This was formerly done in transfer.c, but we better do it here */
if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
/* This was a re-use of a connection and we got a write error in the
* DO-phase. Then we DISCONNECT this connection and have another attempt
* to CONNECT and then DO again! The retry cannot possibly find another
* connection to re-use, since we only keep one possible connection for
* each. */
infof(data, "Re-used connection seems dead, get a new one\n");
conn->bits.close = TRUE; /* enforce close of this connetion */
result = Curl_done(conn); /* we are so done with this */
if(CURLE_OK == result) {
/* Now, redo the connect and get a new connection */
result = Curl_connect(data, connp);
if(CURLE_OK == result)
/* ... finally back to actually retry the DO phase */
result = conn->curl_do(*connp);
}
}
}
CURLcode Curl_do_more(struct connectdata *conn)
{
CURLcode result=CURLE_OK;
if(conn->curl_do_more)
result = conn->curl_do_more(conn);
return result;
}
/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78