Newer
Older
/*
* It is important that there is NO 'return' from this function at any other
* place than falling down to the end of the function! This is because we
* have cleanup stuff that must be done before we get back, and that is only
* performed after this do-while loop.
*/
res = Curl_connect_host(data, &conn); /* primary connection */
if(res == CURLE_OK) {
if (data->set.source_host) /* 3rd party transfer */
res = Curl_pretransfersec(conn);
else
conn->sec_conn = NULL;
}
if(res == CURLE_OK) {
res = Curl_do(&conn);
/* for non 3rd party transfer only */
if(res == CURLE_OK && !data->set.source_host) {
res = Transfer(conn); /* now fetch that URL please */
if(res == CURLE_OK) {
Daniel Stenberg
committed
if((conn->keep.bytecount+conn->headerbytecount == 0) &&
conn->bits.reuse) {
Daniel Stenberg
committed
/* We got no data and we attempted to re-use a connection. This
might happen if the connection was left alive when we were done
using it before, but that was closed when we wanted to read
from it again. Bad luck. Retry the same request on a fresh
connect! */
infof(data, "Connection died, retrying a fresh connect\n");
newurl = strdup(conn->data->change.url);
conn->bits.close = TRUE; /* close this connection */
conn->bits.retry = TRUE; /* mark this as a connection we're about
to retry. Marking it this way should
prevent i.e HTTP transfers to return
error just because nothing has been
transfered! */
}
else
/*
* We must duplicate the new URL here as the connection data
* may be free()ed in the Curl_done() function.
*/
newurl = conn->newurl?strdup(conn->newurl):NULL;
}
Daniel Stenberg
committed
else {
/* The transfer phase returned error, we mark the connection to get
* closed to prevent being re-used. This is becasue we can't
* possibly know if the connection is in a good shape or not now. */
conn->bits.close = TRUE;
Daniel Stenberg
committed
Daniel Stenberg
committed
if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
Daniel Stenberg
committed
/* if we failed anywhere, we must clean up the secondary socket if
it was used */
Daniel Stenberg
committed
sclose(conn->sock[SECONDARYSOCKET]);
Daniel Stenberg
committed
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
Daniel Stenberg
committed
}
}
Daniel Stenberg
committed
/* Always run Curl_done(), even if some of the previous calls
failed, but return the previous (original) error code */
Daniel Stenberg
committed
res2 = Curl_done(&conn, res);
Daniel Stenberg
committed
if(CURLE_OK == res)
res = res2;
Daniel Stenberg
committed
else
/* Curl_do() failed, clean up left-overs in the done-call */
Daniel Stenberg
committed
res2 = Curl_done(&conn, res);
Daniel Stenberg
committed
/*
* Important: 'conn' cannot be used here, since it may have been closed
* in 'Curl_done' or other functions.
*/
if((res == CURLE_OK) && newurl) {
res = Curl_follow(data, newurl);
if(CURLE_OK == res) {
newurl = NULL;
continue;
}
}
break; /* it only reaches here when this shouldn't loop */
} while(1); /* loop if Location: */
Daniel Stenberg
committed
if(newurl)
free(newurl);
/* run post-transfer uncondionally, but don't clobber the return code if
we already have an error code recorder */
res2 = Curl_posttransfer(data);
if(!res && res2)
res = res2;
return res;
}
/*
* Curl_Transfer() is called to setup some basic properties for the upcoming
* transfer.
*/
Curl_Transfer(struct connectdata *c_conn, /* connection data */
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */
curl_off_t *bytecountp, /* return number of bytes read or NULL */
Daniel Stenberg
committed
int writesockindex, /* socket index to write to, it may very
well be the same we read from. -1
disables */
curl_off_t *writecountp /* return number of bytes written or
NULL */
)
{
struct connectdata *conn = (struct connectdata *)c_conn;
if(!conn)
return CURLE_BAD_FUNCTION_ARGUMENT;
curlassert((sockindex <= 1) && (sockindex >= -1));
/* now copy all input parameters */
conn->sockfd = sockindex==-1?
CURL_SOCKET_BAD:conn->sock[sockindex];
conn->bits.getheader = getheader;
conn->bytecountp = bytecountp;
conn->writesockfd = writesockindex==-1?
CURL_SOCKET_BAD:conn->sock[writesockindex];
conn->writebytecountp = writecountp;
return CURLE_OK;
}
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
/*
* Curl_pretransfersec() prepares the secondary connection (used for 3rd party
* FTP transfers).
*/
CURLcode Curl_pretransfersec(struct connectdata *conn)
{
CURLcode status = CURLE_OK;
struct SessionHandle *data = conn->data;
struct connectdata *sec_conn = NULL; /* secondary connection */
/* update data with source host options */
char *url = aprintf( "%s://%s/", conn->protostr, data->set.source_host);
if(!url)
return CURLE_OUT_OF_MEMORY;
if(data->change.url_alloc)
free(data->change.url);
data->change.url_alloc = TRUE;
data->change.url = url;
data->set.ftpport = data->set.source_port;
data->set.userpwd = data->set.source_userpwd;
/* secondary connection */
status = Curl_connect_host(data, &sec_conn);
if(CURLE_OK == status) {
sec_conn->data = data;
conn->sec_conn = sec_conn;
}
return status;
}