69
70
struct Curl_one_easy *easy);
70
71
static int update_timer(struct Curl_multi *multi);
72
static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
73
struct connectdata *conn);
74
static int checkPendPipeline(struct connectdata *conn);
75
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
76
struct connectdata *conn);
77
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
78
struct connectdata *conn);
79
73
static bool isHandleAtHead(struct SessionHandle *handle,
80
74
struct curl_llist *pipeline);
81
75
static CURLMcode add_next_timeout(struct timeval now,
842
/* Add the curl handles to our pollfds first */
843
easy=multi->easy.next;
844
while(easy != &multi->easy) {
845
bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
847
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
848
curl_socket_t s = CURL_SOCKET_BAD;
850
if(bitmap & GETSOCK_READSOCK(i)) {
851
ufds[nfds].fd = sockbunch[i];
852
ufds[nfds].events = POLLIN;
856
if(bitmap & GETSOCK_WRITESOCK(i)) {
857
ufds[nfds].fd = sockbunch[i];
858
ufds[nfds].events = POLLOUT;
862
if(s == CURL_SOCKET_BAD) {
842
/* only do the second loop if we found descriptors in the first stage run
846
/* Add the curl handles to our pollfds first */
847
easy=multi->easy.next;
848
while(easy != &multi->easy) {
849
bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
851
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
852
curl_socket_t s = CURL_SOCKET_BAD;
854
if(bitmap & GETSOCK_READSOCK(i)) {
855
ufds[nfds].fd = sockbunch[i];
856
ufds[nfds].events = POLLIN;
860
if(bitmap & GETSOCK_WRITESOCK(i)) {
861
ufds[nfds].fd = sockbunch[i];
862
ufds[nfds].events = POLLOUT;
866
if(s == CURL_SOCKET_BAD) {
871
easy = easy->next; /* check next handle */
867
easy = easy->next; /* check next handle */
870
875
/* Add external file descriptions from poll-like struct curl_waitfd */
1006
case CURLM_STATE_CONNECT_PEND:
1007
/* We will stay here until there is a connection available. Then
1008
we try again in the CURLM_STATE_CONNECT state. */
1001
1011
case CURLM_STATE_CONNECT:
1002
/* Connect. We get a connection identifier filled in. */
1012
/* Connect. We want to get a connection identifier filled in. */
1003
1013
Curl_pgrsTime(data, TIMER_STARTSINGLE);
1004
1014
easy->result = Curl_connect(data, &easy->easy_conn,
1005
1015
&async, &protocol_connect);
1016
if(CURLE_NO_CONNECTION_AVAILABLE == easy->result) {
1017
/* There was no connection available. We will go to the pending
1018
state and wait for an available connection. */
1019
multistate(easy, CURLM_STATE_CONNECT_PEND);
1020
easy->result = CURLE_OK;
1007
1024
if(CURLE_OK == easy->result) {
1008
1025
/* Add this handle to the send or pend pipeline */
1009
easy->result = addHandleToSendOrPendPipeline(data,
1026
easy->result = Curl_add_handle_to_pipeline(data, easy->easy_conn);
1011
1027
if(CURLE_OK != easy->result)
1012
1028
disconnect_conn = TRUE;
1543
1560
case CURLM_STATE_DONE:
1545
1562
if(easy->easy_conn) {
1546
/* Remove ourselves from the receive and done pipelines. Handle
1547
should be on one of these lists, depending upon how we got here. */
1563
/* Remove ourselves from the receive pipeline, if we are there. */
1548
1564
Curl_removeHandleFromPipeline(data,
1549
1565
easy->easy_conn->recv_pipe);
1550
Curl_removeHandleFromPipeline(data,
1551
easy->easy_conn->done_pipe);
1552
1566
/* Check if we can move pending requests to send pipe */
1553
checkPendPipeline(easy->easy_conn);
1567
Curl_multi_process_pending_handles(multi);
1555
1569
if(easy->easy_conn->bits.stream_was_rewound) {
1556
1570
/* This request read past its response boundary so we quickly let
2231
2247
case CURLMOPT_MAXCONNECTS:
2232
2248
multi->maxconnects = va_arg(param, long);
2250
case CURLMOPT_MAX_HOST_CONNECTIONS:
2251
multi->max_host_connections = va_arg(param, long);
2253
case CURLMOPT_MAX_PIPELINE_LENGTH:
2254
multi->max_pipeline_length = va_arg(param, long);
2256
case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
2257
multi->content_length_penalty_size = va_arg(param, long);
2259
case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
2260
multi->chunk_length_penalty_size = va_arg(param, long);
2262
case CURLMOPT_PIPELINING_SITE_BL:
2263
res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
2264
&multi->pipelining_site_bl);
2266
case CURLMOPT_PIPELINING_SERVER_BL:
2267
res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
2268
&multi->pipelining_server_bl);
2270
case CURLMOPT_MAX_TOTAL_CONNECTIONS:
2271
multi->max_total_connections = va_arg(param, long);
2235
2274
res = CURLM_UNKNOWN_OPTION;
2355
2394
return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
2358
static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
2397
void Curl_multi_set_easy_connection(struct SessionHandle *handle,
2359
2398
struct connectdata *conn)
2361
size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
2362
struct curl_llist_element *sendhead = conn->send_pipe->head;
2363
struct curl_llist *pipeline;
2366
if(!Curl_isPipeliningEnabled(handle) ||
2368
pipeline = conn->send_pipe;
2370
if(conn->server_supports_pipelining &&
2371
pipeLen < MAX_PIPELINE_LENGTH)
2372
pipeline = conn->send_pipe;
2374
pipeline = conn->pend_pipe;
2377
rc = Curl_addHandleToPipeline(handle, pipeline);
2379
if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
2380
/* this is a new one as head, expire it */
2381
conn->writechannel_inuse = FALSE; /* not in use yet */
2383
infof(conn->data, "%p is at send pipe head!\n",
2384
conn->send_pipe->head->ptr);
2386
Curl_expire(conn->send_pipe->head->ptr, 1);
2392
static int checkPendPipeline(struct connectdata *conn)
2395
struct curl_llist_element *sendhead = conn->send_pipe->head;
2397
size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
2398
if(conn->server_supports_pipelining || pipeLen == 0) {
2399
struct curl_llist_element *curr = conn->pend_pipe->head;
2400
const size_t maxPipeLen =
2401
conn->server_supports_pipelining ? MAX_PIPELINE_LENGTH : 1;
2403
while(pipeLen < maxPipeLen && curr) {
2404
Curl_llist_move(conn->pend_pipe, curr,
2405
conn->send_pipe, conn->send_pipe->tail);
2406
Curl_pgrsTime(curr->ptr, TIMER_PRETRANSFER);
2407
++result; /* count how many handles we moved */
2408
curr = conn->pend_pipe->head;
2414
conn->now = Curl_tvnow();
2415
/* something moved, check for a new send pipeline leader */
2416
if(sendhead != conn->send_pipe->head) {
2417
/* this is a new one as head, expire it */
2418
conn->writechannel_inuse = FALSE; /* not in use yet */
2420
infof(conn->data, "%p is at send pipe head!\n",
2421
conn->send_pipe->head->ptr);
2423
Curl_expire(conn->send_pipe->head->ptr, 1);
2430
/* Move this transfer from the sending list to the receiving list.
2432
Pay special attention to the new sending list "leader" as it needs to get
2433
checked to update what sockets it acts on.
2436
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
2437
struct connectdata *conn)
2439
struct curl_llist_element *curr;
2441
curr = conn->send_pipe->head;
2443
if(curr->ptr == handle) {
2444
Curl_llist_move(conn->send_pipe, curr,
2445
conn->recv_pipe, conn->recv_pipe->tail);
2447
if(conn->send_pipe->head) {
2448
/* Since there's a new easy handle at the start of the send pipeline,
2449
set its timeout value to 1ms to make it trigger instantly */
2450
conn->writechannel_inuse = FALSE; /* not used now */
2452
infof(conn->data, "%p is at send pipe head B!\n",
2453
conn->send_pipe->head->ptr);
2455
Curl_expire(conn->send_pipe->head->ptr, 1);
2458
/* The receiver's list is not really interesting here since either this
2459
handle is now first in the list and we'll deal with it soon, or
2460
another handle is already first and thus is already taken care of */
2462
break; /* we're done! */
2468
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
2469
struct connectdata *conn)
2471
struct curl_llist_element *curr;
2473
curr = conn->recv_pipe->head;
2475
if(curr->ptr == handle) {
2476
Curl_llist_move(conn->recv_pipe, curr,
2477
conn->done_pipe, conn->done_pipe->tail);
2400
handle->set.one_easy->easy_conn = conn;
2483
2403
static bool isHandleAtHead(struct SessionHandle *handle,
2484
2404
struct curl_llist *pipeline)
2659
2579
return CURLM_OK;
2582
size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
2584
return multi ? multi->max_host_connections : 0;
2587
size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
2589
return multi ? multi->max_total_connections : 0;
2592
size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi)
2594
return multi ? multi->max_pipeline_length : 0;
2597
curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
2599
return multi ? multi->content_length_penalty_size : 0;
2602
curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
2604
return multi ? multi->chunk_length_penalty_size : 0;
2607
struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
2609
return multi->pipelining_site_bl;
2612
struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
2614
return multi->pipelining_server_bl;
2617
void Curl_multi_process_pending_handles(struct Curl_multi *multi)
2619
struct Curl_one_easy *easy;
2621
easy=multi->easy.next;
2622
while(easy != &multi->easy) {
2623
if(easy->state == CURLM_STATE_CONNECT_PEND) {
2624
multistate(easy, CURLM_STATE_CONNECT);
2625
/* Make sure that the handle will be processed soonish. */
2626
Curl_expire(easy->easy_handle, 1);
2628
easy = easy->next; /* operate on next handle */
2662
2632
#ifdef DEBUGBUILD
2663
2633
void Curl_multi_dump(const struct Curl_multi *multi_handle)