Newer
Older
Daniel Stenberg
committed
data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
Daniel Stenberg
committed
data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
Daniel Stenberg
committed
data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
Daniel Stenberg
committed
data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
Daniel Stenberg
committed
if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
we only acknowledge this option if this is not a re-used connection
already (which happens due to follow-location or during a HTTP
authentication phase). */
if(data->set.reuse_fresh && !data->state.this_is_a_follow)
Daniel Stenberg
committed
reuse = FALSE;
Daniel Stenberg
committed
reuse = ConnectionExists(data, conn, &conn_temp);
if(reuse) {
/*
* 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;
Daniel Stenberg
committed
if(old_conn->proxy.rawalloc)
free(old_conn->proxy.rawalloc);
Daniel Stenberg
committed
/* free the SSL config struct from this connection struct as this was
allocated in vain and is targeted for destruction */
Curl_free_ssl_config(&conn->ssl_config);
conn = conn_temp; /* use this connection from now on */
Daniel Stenberg
committed
conn->data = old_conn->data;
/* get the user+password information from the old_conn struct since it may
* be new for this request even when we re-use an existing connection */
conn->bits.user_passwd = old_conn->bits.user_passwd;
Daniel Stenberg
committed
if(conn->bits.user_passwd) {
/* use the new user namd and password though */
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
conn->user = old_conn->user;
conn->passwd = old_conn->passwd;
old_conn->user = NULL;
old_conn->passwd = NULL;
}
conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
Daniel Stenberg
committed
if(conn->bits.proxy_user_passwd) {
/* use the new proxy user name and proxy password though */
Curl_safefree(conn->proxyuser);
Curl_safefree(conn->proxypasswd);
conn->proxyuser = old_conn->proxyuser;
conn->proxypasswd = old_conn->proxypasswd;
old_conn->proxyuser = NULL;
old_conn->proxypasswd = NULL;
}
/* host can change, when doing keepalive with a proxy ! */
Daniel Stenberg
committed
if(conn->bits.proxy) {
free(conn->host.rawalloc);
conn->host=old_conn->host;
}
Daniel Stenberg
committed
else
free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
/* re-use init */
conn->bits.reuse = TRUE; /* yes, we're re-using here */
Daniel Stenberg
committed
Curl_safefree(old_conn->user);
Curl_safefree(old_conn->passwd);
Curl_safefree(old_conn->proxyuser);
Curl_safefree(old_conn->proxypasswd);
Curl_llist_destroy(old_conn->send_pipe, NULL);
Curl_llist_destroy(old_conn->recv_pipe, NULL);
Daniel Stenberg
committed
Curl_llist_destroy(old_conn->pend_pipe, NULL);
Daniel Stenberg
committed
Curl_safefree(old_conn->master_buffer);
Daniel Stenberg
committed
free(old_conn); /* we don't need this anymore */
*in_connect = conn; /* return this instead! */
infof(data, "Re-using existing connection! (#%ld) with host %s\n",
conn->connectindex,
conn->proxy.name?conn->proxy.dispname:conn->host.dispname);
}
else {
/*
* This is a brand new connection, so let's store it in the connection
* cache of ours!
*/
ConnectionStore(data, conn);
}
Daniel Stenberg
committed
result = setup_range(data);
if(result)
return result;
/* Continue connectdata initialization here. */
/*
* Inherit the proper values from the urldata struct AFTER we have arranged
* the persistent connection stuff */
conn->fread_func = data->set.fread_func;
conn->fread_in = data->set.in;
Daniel Stenberg
committed
conn->seek_func = data->set.seek_func;
conn->seek_client = data->set.seek_client;
Daniel Stenberg
committed
#ifndef USE_ARES
/*************************************************************
Daniel Stenberg
committed
* Set timeout if that is being used, and we're not using an asynchronous
* name resolve.
*************************************************************/
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_ALARM
long shortest;
#endif
Daniel Stenberg
committed
#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 /* HAVE_SIGACTION */
Daniel Stenberg
committed
/* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL
keep_sigact = signal(SIGALRM, alarmfunc);
Daniel Stenberg
committed
#endif
#endif /* HAVE_SIGACTION */
Daniel Stenberg
committed
/* 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
shortest = data->set.timeout; /* default to this timeout value */
if(shortest && data->set.connecttimeout &&
(data->set.connecttimeout < shortest))
/* if both are set, pick the shortest */
shortest = data->set.connecttimeout;
else if(!shortest)
/* if timeout is not set, use the connect timeout */
shortest = data->set.connecttimeout;
Daniel Stenberg
committed
if(shortest < 1000)
/* the alarm() function only provide integer second resolution, so if
we want to wait less than one second we must bail out already now. */
return CURLE_OPERATION_TIMEDOUT;
Daniel Stenberg
committed
/* alarm() makes a signal get sent when the timeout fires off, and that
will abort system calls */
Daniel Stenberg
committed
prev_alarm = alarm((unsigned int) (shortest ? shortest/1000L : shortest));
Daniel Stenberg
committed
/* 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
#endif /* SIGALRM */
}
#endif /* USE_ARES */
/*************************************************************
* Resolve the name of the server or proxy
*************************************************************/
if(conn->bits.reuse) {
/* re-used connection, no resolving is necessary */
hostaddr = NULL;
Daniel Stenberg
committed
/* we'll need to clear conn->dns_entry later in Curl_disconnect() */
Daniel Stenberg
committed
if(conn->bits.proxy)
fix_hostname(data, conn, &conn->host);
else {
/* this is a fresh connect */
/* set a pointer to the hostname we display */
fix_hostname(data, conn, &conn->host);
if(!conn->proxy.name || !*conn->proxy.name) {
/* 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 */
rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
else {
/* This is a proxy that hasn't been resolved yet. */
fix_hostname(data, conn, &conn->proxy);
Daniel Stenberg
committed
/* resolve proxy */
rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(!hostaddr) {
failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
result = CURLE_COULDNT_RESOLVE_PROXY;
/* don't return yet, we need to clean up the timeout first */
}
Daniel Stenberg
committed
*addr = hostaddr;
#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
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
#endif /* HAVE_SIGACTION */
Daniel Stenberg
committed
/* 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 */
Daniel Stenberg
committed
unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
unsigned long alarm_set;
Daniel Stenberg
committed
/* the alarm period is counted in even number of seconds */
alarm_set = prev_alarm - elapsed_ms/1000;
Daniel Stenberg
committed
if(!alarm_set ||
((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
/* if the alarm time-left reached zero or turned "negative" (counted
with unsigned values), we should fire off a SIGALRM here, but we
Daniel Stenberg
committed
won't, and zero would be to switch it off so we never set it to
less than 1! */
alarm(1);
result = CURLE_OPERATION_TIMEDOUT;
Daniel Stenberg
committed
failf(data, "Previous alarm fired off!");
}
else
alarm((unsigned int)alarm_set);
Daniel Stenberg
committed
}
else
alarm(0); /* just shut it off */
}
#endif
Daniel Stenberg
committed
return result;
}
Daniel Stenberg
committed
/* setup_conn() is called after the name resolve initiated in
* create_conn() is all done.
*
* NOTE: the argument 'hostaddr' is NULL when this function is called for a
* re-used connection.
*
Daniel Stenberg
committed
* conn->data MUST already have been setup fine (in create_conn)
Daniel Stenberg
committed
*/
Daniel Stenberg
committed
static CURLcode setup_conn(struct connectdata *conn,
struct Curl_dns_entry *hostaddr,
bool *protocol_done)
Daniel Stenberg
committed
{
CURLcode result=CURLE_OK;
struct SessionHandle *data = conn->data;
Daniel Stenberg
committed
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
if(conn->protocol & PROT_FILE) {
Daniel Stenberg
committed
/* There's nothing in this function to setup if we're only doing
a file:// transfer */
*protocol_done = TRUE;
Daniel Stenberg
committed
return result;
}
*protocol_done = FALSE; /* default to not done */
Daniel Stenberg
committed
/* set proxy_connect_closed to false unconditionally already here since it
is used strictly to provide extra information to a parent function in the
case of proxy CONNECT failures and we must make sure we don't have it
lingering set from a previous invoke */
conn->bits.proxy_connect_closed = FALSE;
Daniel Stenberg
committed
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
* basically anything through a http proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
Daniel Stenberg
committed
Curl_safefree(conn->allocptr.uagent);
conn->allocptr.uagent =
Daniel Stenberg
committed
aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
Daniel Stenberg
committed
if(!conn->allocptr.uagent)
return CURLE_OUT_OF_MEMORY;
Daniel Stenberg
committed
data->req.headerbytecount = 0;
Daniel Stenberg
committed
#ifdef CURL_DO_LINEEND_CONV
data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */
Daniel Stenberg
committed
for(;;) {
/* loop for CURL_SERVER_CLOSED_CONNECTION */
Daniel Stenberg
committed
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
bool connected = FALSE;
Daniel Stenberg
committed
/* Connect only if not already connected! */
result = ConnectPlease(data, conn, hostaddr, &connected);
Daniel Stenberg
committed
if(connected) {
result = Curl_protocol_connect(conn, protocol_done);
if(CURLE_OK == result)
conn->bits.tcpconnect = TRUE;
}
else
conn->bits.tcpconnect = FALSE;
Daniel Stenberg
committed
/* if the connection was closed by the server while exchanging
authentication informations, retry with the new set
authentication information */
Daniel Stenberg
committed
if(conn->bits.proxy_connect_closed) {
/* reset the error buffer */
Daniel Stenberg
committed
if(data->set.errorbuffer)
Daniel Stenberg
committed
data->set.errorbuffer[0] = '\0';
data->state.errorbuf = FALSE;
Daniel Stenberg
committed
continue;
Daniel Stenberg
committed
}
Daniel Stenberg
committed
if(CURLE_OK != result)
return result;
}
else {
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
Daniel Stenberg
committed
conn->bits.tcpconnect = TRUE;
*protocol_done = TRUE;
if(data->set.verbose)
verboseconnect(conn);
}
/* Stop the loop now */
break;
Daniel Stenberg
committed
conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
set this here perhaps a second time */
/*
* This 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,
Daniel Stenberg
committed
struct connectdata **in_connect,
bool *asyncp,
bool *protocol_done)
Daniel Stenberg
committed
struct Curl_dns_entry *dns;
Daniel Stenberg
committed
*asyncp = FALSE; /* assume synchronous resolves by default */
/* call the stuff that needs to be called */
Daniel Stenberg
committed
code = create_conn(data, in_connect, &dns, asyncp);
Daniel Stenberg
committed
if(CURLE_OK == code) {
/* no error */
Daniel Stenberg
committed
if((*in_connect)->send_pipe->size +
(*in_connect)->recv_pipe->size != 0)
/* pipelining */
*protocol_done = TRUE;
Daniel Stenberg
committed
else {
if(dns || !*asyncp)
/* If an address is available it means that we already have the name
resolved, OR it isn't async. if this is a re-used connection 'dns'
will be NULL here. Continue connecting from here */
Daniel Stenberg
committed
code = setup_conn(*in_connect, dns, protocol_done);
Daniel Stenberg
committed
/* else
response will be received and treated async wise */
}
Daniel Stenberg
committed
}
Daniel Stenberg
committed
if(CURLE_OK != code && *in_connect) {
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
Daniel Stenberg
committed
Curl_disconnect(*in_connect); /* close the connection */
*in_connect = NULL; /* return a NULL */
Daniel Stenberg
committed
Daniel Stenberg
committed
/* Call this function after Curl_connect() has returned async=TRUE and
then a successful name resolve has been received.
Note: this function disconnects and frees the conn data in case of
resolve failure */
CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_done)
Daniel Stenberg
committed
{
#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
defined(USE_THREADING_GETADDRINFO)
Daniel Stenberg
committed
CURLcode code = setup_conn(conn, conn->async.dns, protocol_done);
Daniel Stenberg
committed
if(code)
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
Curl_disconnect(conn); /* close the connection */
return code;
#else
(void)conn;
Daniel Stenberg
committed
return CURLE_OK;
#endif
}
Daniel Stenberg
committed
CURLcode Curl_done(struct connectdata **connp,
Daniel Stenberg
committed
CURLcode status, /* an error if this is called after an
error was detected */
bool premature)
struct connectdata *conn;
struct SessionHandle *data;
DEBUGASSERT(*connp);
conn = *connp;
data = conn->data;
Daniel Stenberg
committed
Curl_expire(data, 0); /* stop timer */
Daniel Stenberg
committed
if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
conn->readchannel_inuse)
Daniel Stenberg
committed
conn->readchannel_inuse = FALSE;
Daniel Stenberg
committed
if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
conn->writechannel_inuse)
Daniel Stenberg
committed
conn->writechannel_inuse = FALSE;
Daniel Stenberg
committed
Curl_removeHandleFromPipeline(data, conn->pend_pipe);
Daniel Stenberg
committed
if(conn->bits.done ||
(conn->send_pipe->size + conn->recv_pipe->size != 0 &&
!data->set.reuse_forbid &&
!conn->bits.close))
/* Stop if Curl_done() has already been called or pipeline
is not empty and we do not have to close connection. */
return CURLE_OK;
conn->bits.done = TRUE; /* called just now! */
/* Cleanup possible redirect junk */
Daniel Stenberg
committed
if(data->req.newurl) {
free(data->req.newurl);
data->req.newurl = NULL;
}
Daniel Stenberg
committed
if(data->req.location) {
free(data->req.location);
data->req.location = NULL;
}
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
conn->dns_entry = NULL;
}
/* this calls the protocol-specific function pointer previously set */
Patrick Monnerat
committed
if(conn->handler->done)
result = conn->handler->done(conn, status, premature);
Curl_pgrsDone(conn); /* done with the operation */
Daniel Stenberg
committed
/* if the transfer was completed in a paused state there can be buffered
data left to write and then kill */
if(data->state.tempwrite) {
free(data->state.tempwrite);
data->state.tempwrite = NULL;
}
/* for ares-using, make sure all possible outstanding requests are properly
cancelled before we proceed */
ares_cancel(data->state.areschannel);
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
Daniel Stenberg
committed
restrictions in our or the server's end
if premature is TRUE, it means this connection was said to be DONE before
the entire request operation is complete and thus we can't know in what
state it is for re-using, so we're forced to close it. In a perfect world
we can add code that keep track of if we really must close it here or not,
but currently we have no such detail knowledge.
*/
if(data->set.reuse_forbid || conn->bits.close || premature) {
Daniel Stenberg
committed
CURLcode res2 = Curl_disconnect(conn); /* close the connection */
Daniel Stenberg
committed
/* If we had an error already, make sure we return that one. But
if we got a new error, return that. */
if(!result && res2)
result = res2;
}
Daniel Stenberg
committed
else {
Daniel Stenberg
committed
ConnectionDone(conn); /* the connection is no longer in use */
Daniel Stenberg
committed
/* remember the most recently used connection */
data->state.lastconnect = conn->connectindex;
infof(data, "Connection #%ld to host %s left intact\n",
conn->connectindex,
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
Daniel Stenberg
committed
}
*connp = NULL; /* to make the caller of this function better detect that
this was either closed or handed over to the connection
cache here, and therefore cannot be used from this point on
*/
Daniel Stenberg
committed
/*
* do_init() inits the readwrite session. This is inited each time (in the DO
* function before the protocol-specific DO functions are invoked) for a
* transfer, sometimes multiple times on the same SessionHandle. Make sure
* nothing in here depends on stuff that are setup dynamicly for the transfer.
*/
static CURLcode do_init(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
Daniel Stenberg
committed
struct SingleRequest *k = &data->req;
Daniel Stenberg
committed
conn->bits.done = FALSE; /* Curl_done() is not called yet */
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
Daniel Stenberg
committed
/* NB: the content encoding software depends on this initialization */
Curl_easy_initHandleData(data);
Daniel Stenberg
committed
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
k->start = Curl_tvnow(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
k->httpversion = -1; /* unknown at this point */
k->bytecount = 0;
k->buf = data->state.buffer;
k->uploadbuf = data->state.uploadbuffer;
k->hbufp = data->state.headerbuff;
k->ignorebody=FALSE;
Curl_pgrsTime(data, TIMER_PRETRANSFER);
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
return CURLE_OK;
}
/*
* do_complete is called when the DO actions are complete.
*
* We init chunking and trailer bits to their default values here immediately
* before receiving any header data for the current request in the pipeline.
*/
static void do_complete(struct connectdata *conn)
{
Daniel Stenberg
committed
conn->data->req.chunk=FALSE;
conn->data->req.trailerhdrpresent=FALSE;
Daniel Stenberg
committed
Daniel Stenberg
committed
conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
conn->sockfd:conn->writesockfd)+1;
Daniel Stenberg
committed
}
CURLcode Curl_do(struct connectdata **connp, bool *done)
CURLcode result=CURLE_OK;
struct connectdata *conn = *connp;
struct SessionHandle *data = conn->data;
Daniel Stenberg
committed
/* setup and init stuff before DO starts, in preparing for the transfer */
do_init(conn);
Patrick Monnerat
committed
if(conn->handler->do_it) {
/* generic protocol-specific function pointer set in curl_connect() */
Patrick Monnerat
committed
result = conn->handler->do_it(conn, done);
/* 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 connection */
Daniel Stenberg
committed
result = Curl_done(&conn, result, FALSE); /* we are so done with this */
Daniel Stenberg
committed
/* conn may no longer be a good pointer */
Daniel Stenberg
committed
/*
* According to bug report #1330310. We need to check for
* CURLE_SEND_ERROR here as well. I figure this could happen when the
* request failed on a FTP connection and thus Curl_done() itself tried
* to use the connection (again). Slight Lack of feedback in the report,
* but I don't think this extra check can do much harm.
*/
if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
Daniel Stenberg
committed
bool async;
bool protocol_done = TRUE;
/* Now, redo the connect and get a new connection */
result = Curl_connect(data, connp, &async, &protocol_done);
Daniel Stenberg
committed
if(CURLE_OK == result) {
/* We have connected or sent away a name resolve query fine */
conn = *connp; /* setup conn to again point to something nice */
Daniel Stenberg
committed
if(async) {
/* Now, if async is TRUE here, we need to wait for the name
to resolve */
result = Curl_wait_for_resolv(conn, NULL);
if(result)
return result;
Daniel Stenberg
committed
/* Resolved, continue with the connection */
result = Curl_async_resolved(conn, &protocol_done);
Daniel Stenberg
committed
if(result)
return result;
}
/* ... finally back to actually retry the DO phase */
Patrick Monnerat
committed
result = conn->handler->do_it(conn, done);
Daniel Stenberg
committed
}
Daniel Stenberg
committed
if((result == CURLE_OK) && *done)
/* do_complete must be called after the protocol-specific DO function */
Daniel Stenberg
committed
do_complete(conn);
CURLcode Curl_do_more(struct connectdata *conn)
{
CURLcode result=CURLE_OK;
Patrick Monnerat
committed
if(conn->handler->do_more)
result = conn->handler->do_more(conn);
if(result == CURLE_OK)
/* do_complete must be called after the protocol-specific DO function */
do_complete(conn);
return result;
}
/* Called on connect, and if there's already a protocol-specific struct
allocated for a different connection, this frees it that it can be setup
properly later on. */
void Curl_reset_reqproto(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
Daniel Stenberg
committed
if(data->state.proto.generic && data->state.current_conn != conn) {
free(data->state.proto.generic);
data->state.proto.generic = NULL;
Daniel Stenberg
committed
data->state.current_conn = conn;