1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04: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:
Daniel Stenberg 2006-10-23 20:34:56 +00:00
parent 13e60c55a1
commit e1edd41e1b
6 changed files with 104 additions and 60 deletions

View File

@ -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

View File

@ -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);

View File

@ -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) {
memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
conn->read_pos += bytestocopy;
conn->bits.stream_was_rewound = FALSE;
/* Copy from our master buffer first */ *n = (ssize_t)bytestocopy;
memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy); return CURLE_OK;
conn->read_pos += bytestocopy;
conn->bits.stream_was_rewound = FALSE;
*n = (ssize_t)bytestocopy;
if (bytesremaining == 0) {
return CURLE_OK;
} }
/* If we come here, it means that there is no data to read from the buffer,
* so we read from the socket */
bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer));
if(conn->ssl[num].use) { if(conn->ssl[num].use) {
nread = Curl_ssl_recv(conn, num, conn->master_buffer, bytesremaining); nread = Curl_ssl_recv(conn, num, conn->master_buffer, bytesfromsocket);
if(nread == -1 && bytestocopy == 0) { 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;

View File

@ -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
Curl_read_rewind(conn, excess); " bytes on url %s (size = %" FORMAT_OFF_T
conn->bits.stream_was_rewound = TRUE; ", 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);
} }
nread = (ssize_t) (k->maxdownload - k->bytecount); nread = (ssize_t) (k->maxdownload - k->bytecount);

View File

@ -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 */
@ -2012,10 +2034,13 @@ ConnectionExists(struct SessionHandle *data,
handle in a multi stack may nick it */ handle in a multi stack may nick it */
if (canPipeline) { if (canPipeline) {
/* Mark the connection as being in a pipeline */ /* Mark the connection as being in a pipeline */
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) {

View File

@ -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 ************/