mirror of
https://github.com/moparisthebest/curl
synced 2024-11-16 14:35:03 -05:00
Ravi Pratap provided a major update with pipelining fixes. We also no longer
re-use connections (for pipelining) before the name resolving is done.
This commit is contained in:
parent
13e60c55a1
commit
e1edd41e1b
4
CHANGES
4
CHANGES
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
Daniel (23 October 2006)
|
||||||
|
- Ravi Pratap provided a major update with pipelining fixes. We also no longer
|
||||||
|
re-use connections (for pipelining) before the name resolving is done.
|
||||||
|
|
||||||
Daniel (21 October 2006)
|
Daniel (21 October 2006)
|
||||||
- Nir Soffer made the tests/libtest/Makefile.am use a proper variable for all
|
- Nir Soffer made the tests/libtest/Makefile.am use a proper variable for all
|
||||||
the single test applications' link and dependences, so that you easier can
|
the single test applications' link and dependences, so that you easier can
|
||||||
|
@ -773,7 +773,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
return CURLM_BAD_EASY_HANDLE;
|
return CURLM_BAD_EASY_HANDLE;
|
||||||
|
|
||||||
if (easy->easy_handle->state.pipe_broke) {
|
if (easy->easy_handle->state.pipe_broke) {
|
||||||
infof(easy->easy_handle, "Pipe broke: handle 0x%x\n", easy);
|
infof(easy->easy_handle, "Pipe broke: handle 0x%x, url = %s\n",
|
||||||
|
easy, easy->easy_handle->reqdata.path);
|
||||||
if(easy->easy_handle->state.is_in_pipeline) {
|
if(easy->easy_handle->state.is_in_pipeline) {
|
||||||
/* Head back to the CONNECT state */
|
/* Head back to the CONNECT state */
|
||||||
multistate(easy, CURLM_STATE_CONNECT);
|
multistate(easy, CURLM_STATE_CONNECT);
|
||||||
|
53
lib/sendf.c
53
lib/sendf.c
@ -438,14 +438,25 @@ CURLcode Curl_client_write(struct connectdata *conn,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MIN(a,b) (a < b ? a : b)
|
||||||
|
|
||||||
void Curl_read_rewind(struct connectdata *conn,
|
void Curl_read_rewind(struct connectdata *conn,
|
||||||
size_t extraBytesRead)
|
size_t extraBytesRead)
|
||||||
{
|
{
|
||||||
|
char buf[512 + 1];
|
||||||
|
size_t bytesToShow;
|
||||||
|
|
||||||
conn->read_pos -= extraBytesRead;
|
conn->read_pos -= extraBytesRead;
|
||||||
conn->bits.stream_was_rewound = TRUE;
|
conn->bits.stream_was_rewound = TRUE;
|
||||||
}
|
|
||||||
|
|
||||||
#define MIN(a,b) (a < b ? a : b)
|
bytesToShow = MIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
|
||||||
|
memcpy(buf, conn->master_buffer + conn->read_pos, bytesToShow);
|
||||||
|
buf[bytesToShow] = '\0';
|
||||||
|
|
||||||
|
DEBUGF(infof(conn->data,
|
||||||
|
"Buffer after stream rewind (read_pos = %d): [%s]",
|
||||||
|
conn->read_pos, buf));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal read-from-socket function. This is meant to deal with plain
|
* Internal read-from-socket function. This is meant to deal with plain
|
||||||
@ -457,12 +468,12 @@ void Curl_read_rewind(struct connectdata *conn,
|
|||||||
int Curl_read(struct connectdata *conn, /* connection data */
|
int Curl_read(struct connectdata *conn, /* connection data */
|
||||||
curl_socket_t sockfd, /* read from this socket */
|
curl_socket_t sockfd, /* read from this socket */
|
||||||
char *buf, /* store read data here */
|
char *buf, /* store read data here */
|
||||||
size_t buffersize, /* max amount to read */
|
size_t sizerequested, /* max amount to read */
|
||||||
ssize_t *n) /* amount bytes read */
|
ssize_t *n) /* amount bytes read */
|
||||||
{
|
{
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, buffersize);
|
size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested);
|
||||||
size_t bytesremaining = buffersize - bytestocopy;
|
size_t bytesfromsocket = 0;
|
||||||
|
|
||||||
/* Set 'num' to 0 or 1, depending on which socket that has been sent here.
|
/* Set 'num' to 0 or 1, depending on which socket that has been sent here.
|
||||||
If it is the second socket, we set num to 1. Otherwise to 0. This lets
|
If it is the second socket, we set num to 1. Otherwise to 0. This lets
|
||||||
@ -471,34 +482,34 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
|||||||
|
|
||||||
*n=0; /* reset amount to zero */
|
*n=0; /* reset amount to zero */
|
||||||
|
|
||||||
bytesremaining = MIN(bytesremaining, sizeof(conn->master_buffer));
|
/* Copy from our master buffer first if we have some unread data there*/
|
||||||
|
if (bytestocopy > 0) {
|
||||||
/* Copy from our master buffer first */
|
|
||||||
memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
|
memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
|
||||||
conn->read_pos += bytestocopy;
|
conn->read_pos += bytestocopy;
|
||||||
|
|
||||||
conn->bits.stream_was_rewound = FALSE;
|
conn->bits.stream_was_rewound = FALSE;
|
||||||
|
|
||||||
*n = (ssize_t)bytestocopy;
|
*n = (ssize_t)bytestocopy;
|
||||||
|
|
||||||
if (bytesremaining == 0) {
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(conn->ssl[num].use) {
|
/* If we come here, it means that there is no data to read from the buffer,
|
||||||
nread = Curl_ssl_recv(conn, num, conn->master_buffer, bytesremaining);
|
* so we read from the socket */
|
||||||
|
bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer));
|
||||||
|
|
||||||
if(nread == -1 && bytestocopy == 0) {
|
if(conn->ssl[num].use) {
|
||||||
|
nread = Curl_ssl_recv(conn, num, conn->master_buffer, bytesfromsocket);
|
||||||
|
|
||||||
|
if(nread == -1)
|
||||||
return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
|
return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
} else {
|
|
||||||
if(conn->sec_complete)
|
if(conn->sec_complete)
|
||||||
nread = Curl_sec_read(conn, sockfd, conn->master_buffer, bytesremaining);
|
nread = Curl_sec_read(conn, sockfd, conn->master_buffer,
|
||||||
|
bytesfromsocket);
|
||||||
else
|
else
|
||||||
nread = sread(sockfd, conn->master_buffer, bytesremaining);
|
nread = sread(sockfd, conn->master_buffer, bytesfromsocket);
|
||||||
|
|
||||||
if(-1 == nread && bytestocopy == 0) {
|
if(-1 == nread) {
|
||||||
int err = Curl_sockerrno();
|
int err = Curl_sockerrno();
|
||||||
#ifdef USE_WINSOCK
|
#ifdef USE_WINSOCK
|
||||||
if(WSAEWOULDBLOCK == err)
|
if(WSAEWOULDBLOCK == err)
|
||||||
@ -509,12 +520,12 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nread > 0) {
|
if (nread >= 0) {
|
||||||
memcpy(buf, conn->master_buffer, nread);
|
memcpy(buf, conn->master_buffer, nread);
|
||||||
|
|
||||||
conn->buf_len = nread;
|
conn->buf_len = nread;
|
||||||
conn->read_pos = nread;
|
conn->read_pos = nread;
|
||||||
*n += nread;
|
*n = nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
@ -743,8 +743,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||||||
failf(data, "Maximum file size exceeded");
|
failf(data, "Maximum file size exceeded");
|
||||||
return CURLE_FILESIZE_EXCEEDED;
|
return CURLE_FILESIZE_EXCEEDED;
|
||||||
}
|
}
|
||||||
if(contentlength >= 0)
|
if(contentlength >= 0) {
|
||||||
k->size = contentlength;
|
k->size = contentlength;
|
||||||
|
k->maxdownload = k->size;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* Negative Content-Length is really odd, and we know it
|
/* Negative Content-Length is really odd, and we know it
|
||||||
happens for example when older Apache servers send large
|
happens for example when older Apache servers send large
|
||||||
@ -1133,13 +1135,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||||||
|
|
||||||
if((-1 != k->maxdownload) &&
|
if((-1 != k->maxdownload) &&
|
||||||
(k->bytecount + nread >= k->maxdownload)) {
|
(k->bytecount + nread >= k->maxdownload)) {
|
||||||
size_t excess = (size_t)(k->bytecount +
|
curl_off_t excess = k->bytecount +
|
||||||
(curl_off_t)nread - k->maxdownload);
|
((curl_off_t) nread) - k->maxdownload;
|
||||||
|
if (excess > 0 && !k->ignorebody) {
|
||||||
if (excess > 0) {
|
infof(data,
|
||||||
infof(data, "Rewinding stream by : %d bytes\n", excess);
|
"Rewinding stream by : %" FORMAT_OFF_T
|
||||||
|
" bytes on url %s (size = %" FORMAT_OFF_T
|
||||||
|
", maxdownload = %" FORMAT_OFF_T
|
||||||
|
", bytecount = %" FORMAT_OFF_T ", nread = %d)\n",
|
||||||
|
excess, conn->data->reqdata.path,
|
||||||
|
k->size, k->maxdownload, k->bytecount, nread);
|
||||||
Curl_read_rewind(conn, excess);
|
Curl_read_rewind(conn, excess);
|
||||||
conn->bits.stream_was_rewound = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nread = (ssize_t) (k->maxdownload - k->bytecount);
|
nread = (ssize_t) (k->maxdownload - k->bytecount);
|
||||||
|
46
lib/url.c
46
lib/url.c
@ -1854,6 +1854,7 @@ int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
|
|||||||
}
|
}
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1899,8 +1900,8 @@ static void signalPipeClose(struct curl_llist *pipe)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
data->state.pipe_broke = TRUE;
|
|
||||||
|
|
||||||
|
data->state.pipe_broke = TRUE;
|
||||||
Curl_llist_remove(pipe, curr, NULL);
|
Curl_llist_remove(pipe, curr, NULL);
|
||||||
curr = next;
|
curr = next;
|
||||||
}
|
}
|
||||||
@ -1936,12 +1937,19 @@ ConnectionExists(struct SessionHandle *data,
|
|||||||
/* NULL pointer means not filled-in entry */
|
/* NULL pointer means not filled-in entry */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
#ifdef USE_ARES
|
||||||
|
/* ip_addr_str is NULL only if the resolving of the name hasn't completed
|
||||||
|
yet and until then we don't re-use this connection */
|
||||||
|
if (!check->ip_addr_str)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
if(check->inuse && !canPipeline)
|
if(check->inuse && !canPipeline)
|
||||||
/* can only happen within multi handles, and means that another easy
|
/* can only happen within multi handles, and means that another easy
|
||||||
handle is using this connection */
|
handle is using this connection */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (check->send_pipe->size >= MAX_PIPELINE_LENGTH ||
|
if (check->send_pipe->size +
|
||||||
check->recv_pipe->size >= MAX_PIPELINE_LENGTH)
|
check->recv_pipe->size >= MAX_PIPELINE_LENGTH)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1994,14 +2002,28 @@ ConnectionExists(struct SessionHandle *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(match) {
|
if(match) {
|
||||||
|
|
||||||
bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
|
bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
|
||||||
if(dead) {
|
if(dead) {
|
||||||
/*
|
if (!check->is_in_pipeline) {
|
||||||
*/
|
|
||||||
check->data = data;
|
check->data = data;
|
||||||
infof(data, "Connection %d seems to be dead!\n", i);
|
infof(data, "Connection %d seems to be dead!\n", i);
|
||||||
|
|
||||||
Curl_disconnect(check); /* disconnect resources */
|
Curl_disconnect(check); /* disconnect resources */
|
||||||
data->state.connc->connects[i]=NULL; /* nothing here */
|
data->state.connc->connects[i]=NULL; /* nothing here */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* In the pipelining case, freeing the connection right away
|
||||||
|
* doesn't work. Instead, we mark the connection for close
|
||||||
|
* so that the handles will detect this automatically when
|
||||||
|
* they try to do something and deal with it there.
|
||||||
|
* Prematurely freeing this connection prevents handles that
|
||||||
|
* have already finished with their transfers to shut down
|
||||||
|
* cleanly.
|
||||||
|
*/
|
||||||
|
infof(data, "Connection %d seems dead - marking for close\n", i);
|
||||||
|
check->bits.close = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* There's no need to continue searching, because we only store
|
/* There's no need to continue searching, because we only store
|
||||||
one connection for each unique set of identifiers */
|
one connection for each unique set of identifiers */
|
||||||
@ -2016,6 +2038,9 @@ ConnectionExists(struct SessionHandle *data,
|
|||||||
check->is_in_pipeline = TRUE;
|
check->is_in_pipeline = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check->connectindex = i; /* Set this appropriately since it might have
|
||||||
|
been set to -1 when the easy was removed
|
||||||
|
from the multi */
|
||||||
*usethis = check;
|
*usethis = check;
|
||||||
return TRUE; /* yes, we found one to use! */
|
return TRUE; /* yes, we found one to use! */
|
||||||
}
|
}
|
||||||
@ -2690,6 +2715,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
conn->readchannel_inuse = FALSE;
|
conn->readchannel_inuse = FALSE;
|
||||||
conn->writechannel_inuse = FALSE;
|
conn->writechannel_inuse = FALSE;
|
||||||
|
|
||||||
|
conn->read_pos = 0;
|
||||||
|
conn->buf_len = 0;
|
||||||
|
|
||||||
/* Initialize the pipeline lists */
|
/* Initialize the pipeline lists */
|
||||||
conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
||||||
conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
||||||
@ -3622,12 +3650,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
infof(data, "Re-using existing connection! (#%ld) with host %s\n",
|
infof(data, "Re-using existing connection! (#%ld) with host %s\n",
|
||||||
conn->connectindex,
|
conn->connectindex,
|
||||||
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
|
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
|
||||||
#ifdef CURLRES_ASYNCH
|
|
||||||
if(!conn->ip_addr_str) {
|
|
||||||
infof(data, "... but it is not resolved yet!\n");
|
|
||||||
*async = TRUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/*
|
/*
|
||||||
@ -3990,10 +4012,10 @@ CURLcode Curl_done(struct connectdata **connp,
|
|||||||
|
|
||||||
if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
|
if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
|
||||||
conn->readchannel_inuse)
|
conn->readchannel_inuse)
|
||||||
conn->readchannel_inuse--;
|
conn->readchannel_inuse = FALSE;
|
||||||
if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
|
if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
|
||||||
conn->writechannel_inuse)
|
conn->writechannel_inuse)
|
||||||
conn->writechannel_inuse--;
|
conn->writechannel_inuse = FALSE;
|
||||||
|
|
||||||
/* cleanups done even if the connection is re-used */
|
/* cleanups done even if the connection is re-used */
|
||||||
if(data->reqdata.rangestringalloc) {
|
if(data->reqdata.rangestringalloc) {
|
||||||
|
@ -812,8 +812,8 @@ struct connectdata {
|
|||||||
their responses on this pipeline */
|
their responses on this pipeline */
|
||||||
|
|
||||||
char master_buffer[BUFSIZE]; /* The master buffer for this connection. */
|
char master_buffer[BUFSIZE]; /* The master buffer for this connection. */
|
||||||
size_t read_pos;
|
size_t read_pos; /* Current read position in the master buffer */
|
||||||
size_t buf_len;
|
size_t buf_len; /* Length of the buffer?? */
|
||||||
|
|
||||||
|
|
||||||
/*************** Request - specific items ************/
|
/*************** Request - specific items ************/
|
||||||
|
Loading…
Reference in New Issue
Block a user