~ubuntu-branches/ubuntu/maverick/curl/maverick

« back to all changes in this revision

Viewing changes to lib/multi.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2009-12-11 19:33:21 UTC
  • mfrom: (3.4.2 squeeze) (40.1.2 curl)
  • Revision ID: james.westby@ubuntu.com-20091211193321-tenukopudyznzbjj
* Merge with Debian testing.  Remaining changes:
  - Keep build deps in main:
    - Drop build dependencies: stunnel, libdb4.6-dev, libssh2-1-dev
    - Add build-dependency on openssh-server
    - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
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
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
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);
199
201
 
200
 
#ifdef CURLDEBUG
 
202
#ifdef DEBUGBUILD
201
203
static const char * const statename[]={
202
204
  "INIT",
203
205
  "CONNECT",
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)
223
225
{
224
 
#ifdef CURLDEBUG
 
226
#ifdef DEBUGBUILD
225
227
  long connectindex = -5000;
226
228
#endif
227
229
  CURLMstate oldstate = easy->state;
232
234
 
233
235
  easy->state = state;
234
236
 
235
 
#ifdef CURLDEBUG
236
 
  if(easy->state > CURLM_STATE_CONNECT &&
237
 
     easy->state < CURLM_STATE_COMPLETED)
238
 
    connectindex = easy->easy_conn->connectindex;
 
237
#ifdef DEBUGBUILD
 
238
  if(easy->easy_conn) {
 
239
    if(easy->state > CURLM_STATE_CONNECT &&
 
240
       easy->state < CURLM_STATE_COMPLETED)
 
241
      connectindex = easy->easy_conn->connectindex;
239
242
 
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);
 
247
  }
244
248
#endif
245
249
  if(state == CURLM_STATE_COMPLETED)
246
250
    /* changing to COMPLETED means there's one less easy handle 'alive' */
382
386
    return NULL;
383
387
  }
384
388
 
385
 
  multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1);
 
389
  multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1L);
386
390
  if(!multi->connc) {
387
391
    Curl_hash_destroy(multi->sockhash);
388
392
    Curl_hash_destroy(multi->hostcache);
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;
459
463
  }
460
464
 
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;
465
469
  }
598
602
      multi->num_alive--;
599
603
 
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
607
611
         connection. */
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".
663
 
     */
 
667
    */
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
781
 
                                                 of sockets */
 
785
                                                  of sockets */
782
786
                         int numsocks)
783
787
{
784
788
  /* If the pipe broke, or if there's no connection left for this easy handle,
790
794
    return 0;
791
795
 
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;
796
800
  }
925
929
      break;
926
930
    }
927
931
 
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
1082
 
             */
 
1086
          */
1083
1087
#ifndef CURL_DISABLE_HTTP
1084
1088
          if(easy->easy_conn->bits.tunnel_connecting)
1085
1089
            multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
1117
1121
 
1118
1122
    case CURLM_STATE_WAITDO:
1119
1123
      /* Wait for our turn to DO when we're pipelining requests */
1120
 
#ifdef CURLDEBUG
 
1124
#ifdef DEBUGBUILD
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,
1149
1153
                               &dophase_done);
1150
1154
 
1151
1155
        if(CURLE_OK == easy->result) {
1152
 
 
1153
1156
          if(!dophase_done) {
1154
1157
            /* DO was not completed in one function call, we must continue
1155
1158
               DOING... */
1170
1173
            result = CURLM_CALL_MULTI_PERFORM;
1171
1174
          }
1172
1175
        }
 
1176
        else if ((CURLE_SEND_ERROR == easy->result) &&
 
1177
                 easy->easy_conn->bits.reuse) {
 
1178
          /*
 
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.
 
1182
           */
 
1183
          char *newurl = NULL;
 
1184
          followtype follow=FOLLOW_NONE;
 
1185
          CURLcode drc;
 
1186
          bool retry = FALSE;
 
1187
 
 
1188
          drc = Curl_retry_request(easy->easy_conn, &newurl);
 
1189
          if(drc) {
 
1190
            /* a failure here pretty much implies an out of memory */
 
1191
            easy->result = drc;
 
1192
            disconnect_conn = TRUE;
 
1193
          }
 
1194
          else
 
1195
            retry = newurl?TRUE:FALSE;
 
1196
 
 
1197
          Curl_posttransfer(easy->easy_handle);
 
1198
          drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
 
1199
 
 
1200
          /* When set to retry the connection, we must to go back to
 
1201
           * the CONNECT state */
 
1202
          if(retry) {
 
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;
 
1210
              }
 
1211
              else {
 
1212
                /* Follow failed */
 
1213
                easy->result = drc;
 
1214
                free(newurl);
 
1215
              }
 
1216
            }
 
1217
            else {
 
1218
              /* done didn't return OK or SEND_ERROR */
 
1219
              easy->result = drc;
 
1220
              free(newurl);
 
1221
            }
 
1222
          }
 
1223
          else {
 
1224
            /* Have error handler disconnect conn if we can't retry */
 
1225
            disconnect_conn = TRUE;
 
1226
          }
 
1227
        }
1173
1228
        else {
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;
1255
1310
      }
1256
 
#ifdef CURLDEBUG
 
1311
#ifdef DEBUGBUILD
1257
1312
      else {
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 ) )
1277
1332
        )
1278
 
      multistate(easy, CURLM_STATE_PERFORM);
 
1333
        multistate(easy, CURLM_STATE_PERFORM);
1279
1334
      break;
1280
1335
 
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 ) )
1289
1344
        ) {
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);
1324
1379
      }
1325
1380
      else if(TRUE == done) {
1326
 
        char *newurl;
1327
 
        bool retry = Curl_retry_request(easy->easy_conn, &newurl);
 
1381
        char *newurl = NULL;
 
1382
        bool retry = FALSE;
1328
1383
        followtype follow=FOLLOW_NONE;
1329
1384
 
 
1385
        easy->result = Curl_retry_request(easy->easy_conn, &newurl);
 
1386
        if(!easy->result)
 
1387
          retry = newurl?TRUE:FALSE;
 
1388
 
1330
1389
        /* call this even if the readwrite function returned error */
1331
1390
        Curl_posttransfer(easy->easy_handle);
1332
1391
 
1333
1392
        /* we're no longer receving */
1334
 
        Curl_removeHandleFromPipeline(easy->easy_handle,
1335
 
                                      easy->easy_conn->recv_pipe);
 
1393
        moveHandleFromRecvToDonePipeline(easy->easy_handle,
 
1394
                                         easy->easy_conn);
1336
1395
 
1337
1396
        /* expire the new receiving pipeline head */
1338
1397
        if(easy->easy_conn->recv_pipe->head)
1360
1419
            multistate(easy, CURLM_STATE_CONNECT);
1361
1420
            result = CURLM_CALL_MULTI_PERFORM;
1362
1421
          }
1363
 
          else
 
1422
          else if(newurl)
1364
1423
            /* Since we "took it", we are in charge of freeing this on
1365
1424
               failure */
1366
1425
            free(newurl);
1386
1445
      break;
1387
1446
 
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);
1394
 
 
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;
 
1448
 
 
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);
 
1458
 
 
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;
 
1464
        }
 
1465
 
 
1466
        /* post-transfer command */
 
1467
        easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
 
1468
        /*
 
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
 
1473
         */
 
1474
        if (easy->easy_conn)
 
1475
          easy->easy_conn = NULL;
1400
1476
      }
1401
1477
 
1402
 
      /* post-transfer command */
1403
 
      easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
1404
 
 
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);
1448
1523
        }
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;
1867
 
        else
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;
1872
1946
      }
1873
1947
 
1990
2064
}
1991
2065
 
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)
1994
2068
{
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.
2145
2219
 
2146
 
 */
 
2220
*/
2147
2221
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
2148
 
                                            struct connectdata *conn)
 
2222
                                             struct connectdata *conn)
2149
2223
{
2150
2224
  struct curl_llist_element *curr;
2151
2225
 
2174
2248
  }
2175
2249
}
2176
2250
 
 
2251
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
 
2252
                                            struct connectdata *conn)
 
2253
{
 
2254
  struct curl_llist_element *curr;
 
2255
 
 
2256
  curr = conn->recv_pipe->head;
 
2257
  while(curr) {
 
2258
    if(curr->ptr == handle) {
 
2259
      Curl_llist_move(conn->recv_pipe, curr,
 
2260
                      conn->done_pipe, conn->done_pipe->tail);
 
2261
      break;
 
2262
    }
 
2263
    curr = curr->next;
 
2264
  }
 
2265
}
2177
2266
static bool isHandleAtHead(struct SessionHandle *handle,
2178
2267
                           struct curl_llist *pipeline)
2179
2268
{
2353
2442
 
2354
2443
}
2355
2444
 
2356
 
#ifdef CURLDEBUG
 
2445
#ifdef DEBUGBUILD
2357
2446
void Curl_multi_dump(const struct Curl_multi *multi_handle)
2358
2447
{
2359
2448
  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;