Newer
Older
Daniel Stenberg
committed
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
/* 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) {
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
*************************************************************/
Daniel Stenberg
committed
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 */
/* it might already be set if reusing a connection */
conn->hostaddr = Curl_resolv(data, conn->name, conn->port,
&conn->hostent_buf);
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 */
/* This is a proxy that hasn't been resolved yet. It may be resolved
if we're reusing an existing connection. */
/* it might already be set if reusing a connection */
conn->hostaddr = Curl_resolv(data, conn->proxyhost, conn->port,
&conn->hostent_buf);
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) {
#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
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
#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);
if(-1 == conn->firstsocket) {
/* Connect only if not already connected! */
if(CURLE_OK != result)
return result;
if(conn->curl_connect) {
/* is there a connect() procedure? */
/* set start time here for timeout purposes in the
* connect procedure, it is later set again for the
* progress meter purpose */
conn->now = Curl_tvnow();
/* Call the protocol-specific connect function */
result = conn->curl_connect(conn);
if(result != CURLE_OK)
return result; /* pass back errors */
}
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected */
conn->now = Curl_tvnow(); /* time this *after* the connect is done */
Daniel Stenberg
committed
conn->headerbytecount = 0;
/* Figure out the ip-number and display the first host name it shows: */
#ifdef ENABLE_IPV6
{
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);
infof(data, "Connected to %s port %d\n", hbuf, conn->port);
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
infof(data, "Connected to %s (%s)\n", conn->hostaddr->h_name,
#if defined(HAVE_INET_NTOA_R)
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf))
#else
inet_ntoa(in)
#endif
);
#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;
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->curl_do(conn);
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
/* This was formerly done in transfer.c, but we better do it here */
if((CURLE_WRITE_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);
}
}
}
/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78