18
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
* KIND, either express or implied.
21
* $Id: multi.c,v 1.198 2009-05-11 07:53:38 bagder Exp $
21
* $Id: multi.c,v 1.204 2009-08-24 08:41:17 bagder Exp $
22
22
***************************************************************************/
192
192
static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
193
193
struct connectdata *conn);
194
194
static int checkPendPipeline(struct connectdata *conn);
195
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *habdle,
195
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
196
struct connectdata *conn);
197
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
196
198
struct connectdata *conn);
197
199
static bool isHandleAtHead(struct SessionHandle *handle,
198
200
struct curl_llist *pipeline);
201
203
static const char * const statename[]={
221
223
/* always use this function to change state, to make debugging easier */
222
224
static void multistate(struct Curl_one_easy *easy, CURLMstate state)
225
227
long connectindex = -5000;
227
229
CURLMstate oldstate = easy->state;
233
235
easy->state = state;
236
if(easy->state > CURLM_STATE_CONNECT &&
237
easy->state < CURLM_STATE_COMPLETED)
238
connectindex = easy->easy_conn->connectindex;
238
if(easy->easy_conn) {
239
if(easy->state > CURLM_STATE_CONNECT &&
240
easy->state < CURLM_STATE_COMPLETED)
241
connectindex = easy->easy_conn->connectindex;
240
infof(easy->easy_handle,
241
"STATE: %s => %s handle %p; (connection #%ld) \n",
242
statename[oldstate], statename[easy->state],
243
(char *)easy, connectindex);
243
infof(easy->easy_handle,
244
"STATE: %s => %s handle %p; (connection #%ld) \n",
245
statename[oldstate], statename[easy->state],
246
(char *)easy, connectindex);
245
249
if(state == CURLM_STATE_COMPLETED)
246
250
/* changing to COMPLETED means there's one less easy handle 'alive' */
452
456
/* for multi interface connections, we share DNS cache automatically if the
453
457
easy handle's one is currently private. */
454
458
if(easy->easy_handle->dns.hostcache &&
455
(easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
459
(easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
456
460
Curl_hash_destroy(easy->easy_handle->dns.hostcache);
457
461
easy->easy_handle->dns.hostcache = NULL;
458
462
easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
461
465
if(!easy->easy_handle->dns.hostcache ||
462
(easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
466
(easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
463
467
easy->easy_handle->dns.hostcache = multi->hostcache;
464
468
easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
598
602
multi->num_alive--;
600
604
if(easy->easy_conn &&
601
(easy->easy_conn->send_pipe->size +
602
easy->easy_conn->recv_pipe->size > 1) &&
603
easy->state > CURLM_STATE_WAITDO &&
604
easy->state < CURLM_STATE_COMPLETED) {
605
(easy->easy_conn->send_pipe->size +
606
easy->easy_conn->recv_pipe->size > 1) &&
607
easy->state > CURLM_STATE_WAITDO &&
608
easy->state < CURLM_STATE_COMPLETED) {
605
609
/* If the handle is in a pipeline and has started sending off its
606
610
request but not received its reponse yet, we need to close
660
664
points to this handle and are using PROT_CLOSEACTION. If there's any,
661
665
we need to add this handle to the list of "easy handles kept around for
662
666
nice connection closures".
664
668
if(multi_conn_using(multi, easy->easy_handle)) {
665
669
/* There's at least one connection using this handle so we must keep
666
670
this handle around. We also keep the connection cache pointer
778
782
/* returns bitmapped flags for this handle and its sockets */
779
783
static int multi_getsock(struct Curl_one_easy *easy,
780
784
curl_socket_t *socks, /* points to numsocks number
784
788
/* If the pipe broke, or if there's no connection left for this easy handle,
792
796
if(easy->state > CURLM_STATE_CONNECT &&
793
easy->state < CURLM_STATE_COMPLETED) {
797
easy->state < CURLM_STATE_COMPLETED) {
794
798
/* Set up ownership correctly */
795
799
easy->easy_conn->data = easy->easy_handle;
928
if(easy->state > CURLM_STATE_CONNECT &&
932
if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT &&
929
933
easy->state < CURLM_STATE_COMPLETED)
930
934
/* Make sure we set the connection's current owner */
931
935
easy->easy_conn->data = easy->easy_handle;
1079
1083
and then we continue to 'STATE_PROTOCONNECT'. If protocol
1080
1084
connect is TRUE, we move on to STATE_DO.
1081
1085
BUT if we are using a proxy we must change to WAITPROXYCONNECT
1083
1087
#ifndef CURL_DISABLE_HTTP
1084
1088
if(easy->easy_conn->bits.tunnel_connecting)
1085
1089
multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
1118
1122
case CURLM_STATE_WAITDO:
1119
1123
/* Wait for our turn to DO when we're pipelining requests */
1121
1125
infof(easy->easy_handle, "Conn %d send pipe %d inuse %d athead %d\n",
1122
1126
easy->easy_conn->connectindex,
1123
1127
easy->easy_conn->send_pipe->size,
1170
1173
result = CURLM_CALL_MULTI_PERFORM;
1176
else if ((CURLE_SEND_ERROR == easy->result) &&
1177
easy->easy_conn->bits.reuse) {
1179
* In this situation, a connection that we were trying to use
1180
* may have unexpectedly died. If possible, send the connection
1181
* back to the CONNECT phase so we can try again.
1183
char *newurl = NULL;
1184
followtype follow=FOLLOW_NONE;
1188
drc = Curl_retry_request(easy->easy_conn, &newurl);
1190
/* a failure here pretty much implies an out of memory */
1192
disconnect_conn = TRUE;
1195
retry = newurl?TRUE:FALSE;
1197
Curl_posttransfer(easy->easy_handle);
1198
drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
1200
/* When set to retry the connection, we must to go back to
1201
* the CONNECT state */
1203
if ((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) {
1204
follow = FOLLOW_RETRY;
1205
drc = Curl_follow(easy->easy_handle, newurl, follow);
1206
if(drc == CURLE_OK) {
1207
multistate(easy, CURLM_STATE_CONNECT);
1208
result = CURLM_CALL_MULTI_PERFORM;
1209
easy->result = CURLE_OK;
1218
/* done didn't return OK or SEND_ERROR */
1224
/* Have error handler disconnect conn if we can't retry */
1225
disconnect_conn = TRUE;
1174
1229
/* failure detected */
1175
1230
Curl_posttransfer(easy->easy_handle);
1253
1308
multistate(easy, CURLM_STATE_PERFORM);
1254
1309
result = CURLM_CALL_MULTI_PERFORM;
1258
1313
infof(easy->easy_handle, "Conn %d recv pipe %d inuse %d athead %d\n",
1259
1314
easy->easy_conn->connectindex,
1269
1324
/* if both rates are within spec, resume transfer */
1270
1325
Curl_pgrsUpdate(easy->easy_conn);
1271
1326
if( ( ( easy->easy_handle->set.max_send_speed == 0 ) ||
1272
( easy->easy_handle->progress.ulspeed <
1273
easy->easy_handle->set.max_send_speed ) ) &&
1274
( ( easy->easy_handle->set.max_recv_speed == 0 ) ||
1275
( easy->easy_handle->progress.dlspeed <
1276
easy->easy_handle->set.max_recv_speed ) )
1327
( easy->easy_handle->progress.ulspeed <
1328
easy->easy_handle->set.max_send_speed ) ) &&
1329
( ( easy->easy_handle->set.max_recv_speed == 0 ) ||
1330
( easy->easy_handle->progress.dlspeed <
1331
easy->easy_handle->set.max_recv_speed ) )
1278
multistate(easy, CURLM_STATE_PERFORM);
1333
multistate(easy, CURLM_STATE_PERFORM);
1281
1336
case CURLM_STATE_PERFORM:
1282
1337
/* check if over speed */
1283
1338
if( ( ( easy->easy_handle->set.max_send_speed > 0 ) &&
1284
( easy->easy_handle->progress.ulspeed >
1285
easy->easy_handle->set.max_send_speed ) ) ||
1286
( ( easy->easy_handle->set.max_recv_speed > 0 ) &&
1287
( easy->easy_handle->progress.dlspeed >
1288
easy->easy_handle->set.max_recv_speed ) )
1339
( easy->easy_handle->progress.ulspeed >
1340
easy->easy_handle->set.max_send_speed ) ) ||
1341
( ( easy->easy_handle->set.max_recv_speed > 0 ) &&
1342
( easy->easy_handle->progress.dlspeed >
1343
easy->easy_handle->set.max_recv_speed ) )
1290
1345
/* Transfer is over the speed limit. Change state. TODO: Call
1291
1346
* Curl_expire() with the time left until we're targeted to be below
1323
1378
Curl_done(&easy->easy_conn, easy->result, FALSE);
1325
1380
else if(TRUE == done) {
1327
bool retry = Curl_retry_request(easy->easy_conn, &newurl);
1381
char *newurl = NULL;
1328
1383
followtype follow=FOLLOW_NONE;
1385
easy->result = Curl_retry_request(easy->easy_conn, &newurl);
1387
retry = newurl?TRUE:FALSE;
1330
1389
/* call this even if the readwrite function returned error */
1331
1390
Curl_posttransfer(easy->easy_handle);
1333
1392
/* we're no longer receving */
1334
Curl_removeHandleFromPipeline(easy->easy_handle,
1335
easy->easy_conn->recv_pipe);
1393
moveHandleFromRecvToDonePipeline(easy->easy_handle,
1337
1396
/* expire the new receiving pipeline head */
1338
1397
if(easy->easy_conn->recv_pipe->head)
1388
1447
case CURLM_STATE_DONE:
1389
/* Remove ourselves from the receive pipeline */
1390
Curl_removeHandleFromPipeline(easy->easy_handle,
1391
easy->easy_conn->recv_pipe);
1392
/* Check if we can move pending requests to send pipe */
1393
checkPendPipeline(easy->easy_conn);
1395
if(easy->easy_conn->bits.stream_was_rewound) {
1396
/* This request read past its response boundary so we quickly let the
1397
other requests consume those bytes since there is no guarantee that
1398
the socket will become active again */
1399
result = CURLM_CALL_MULTI_PERFORM;
1449
if(easy->easy_conn) {
1450
/* Remove ourselves from the receive and done pipelines. Handle
1451
should be on one of these lists, depending upon how we got here. */
1452
Curl_removeHandleFromPipeline(easy->easy_handle,
1453
easy->easy_conn->recv_pipe);
1454
Curl_removeHandleFromPipeline(easy->easy_handle,
1455
easy->easy_conn->done_pipe);
1456
/* Check if we can move pending requests to send pipe */
1457
checkPendPipeline(easy->easy_conn);
1459
if(easy->easy_conn->bits.stream_was_rewound) {
1460
/* This request read past its response boundary so we quickly let
1461
the other requests consume those bytes since there is no
1462
guarantee that the socket will become active again */
1463
result = CURLM_CALL_MULTI_PERFORM;
1466
/* post-transfer command */
1467
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
1469
* If there are other handles on the pipeline, Curl_done won't set
1470
* easy_conn to NULL. In such a case, curl_multi_remove_handle() can
1471
* access free'd data, if the connection is free'd and the handle
1472
* removed before we perform the processing in CURLM_STATE_COMPLETED
1474
if (easy->easy_conn)
1475
easy->easy_conn = NULL;
1402
/* post-transfer command */
1403
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
1405
1478
/* after we have DONE what we're supposed to do, go COMPLETED, and
1406
1479
it doesn't matter what the Curl_done() returned! */
1407
1480
multistate(easy, CURLM_STATE_COMPLETED);
1443
1516
easy->easy_conn->send_pipe);
1444
1517
Curl_removeHandleFromPipeline(easy->easy_handle,
1445
1518
easy->easy_conn->recv_pipe);
1519
Curl_removeHandleFromPipeline(easy->easy_handle,
1520
easy->easy_conn->done_pipe);
1446
1521
/* Check if we can move pending requests to send pipe */
1447
1522
checkPendPipeline(easy->easy_conn);
1864
1939
data->set.one_easy->easy_conn->send_pipe &&
1865
1940
data->set.one_easy->easy_conn->send_pipe->head)
1866
1941
data = data->set.one_easy->easy_conn->send_pipe->head->ptr;
1868
if ((ev_bitmask & CURL_POLL_IN) &&
1869
data->set.one_easy->easy_conn->recv_pipe &&
1870
data->set.one_easy->easy_conn->recv_pipe->head)
1942
else if ((ev_bitmask & CURL_POLL_IN) &&
1943
data->set.one_easy->easy_conn->recv_pipe &&
1944
data->set.one_easy->easy_conn->recv_pipe->head)
1871
1945
data = data->set.one_easy->easy_conn->recv_pipe->head->ptr;
1992
2066
CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s,
1993
int ev_bitmask, int *running_handles)
2067
int ev_bitmask, int *running_handles)
1995
2069
CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
1996
2070
ev_bitmask, running_handles);
2143
2217
Pay special attention to the new sending list "leader" as it needs to get
2144
2218
checked to update what sockets it acts on.
2147
2221
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
2148
struct connectdata *conn)
2222
struct connectdata *conn)
2150
2224
struct curl_llist_element *curr;
2251
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
2252
struct connectdata *conn)
2254
struct curl_llist_element *curr;
2256
curr = conn->recv_pipe->head;
2258
if(curr->ptr == handle) {
2259
Curl_llist_move(conn->recv_pipe, curr,
2260
conn->done_pipe, conn->done_pipe->tail);
2177
2266
static bool isHandleAtHead(struct SessionHandle *handle,
2178
2267
struct curl_llist *pipeline)