~ubuntu-branches/ubuntu/vivid/curl/vivid

« back to all changes in this revision

Viewing changes to lib/multi.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2013-05-07 12:16:37 UTC
  • mfrom: (3.4.37 sid)
  • Revision ID: package-import@ubuntu.com-20130507121637-9t3i98qgsyr9dw5d
Tags: 7.30.0-1ubuntu1
* Resynchronize on Debian. Remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from binary package Depends.
  - Add new libcurl3-udeb package.
  - Add new curl-udeb package.
* Add warning to debian/patches/series.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
#include "conncache.h"
41
41
#include "bundles.h"
42
42
#include "multihandle.h"
 
43
#include "pipeline.h"
43
44
 
44
45
#define _MPRINTF_REPLACE /* use our functions only */
45
46
#include <curl/mprintf.h>
69
70
                         struct Curl_one_easy *easy);
70
71
static int update_timer(struct Curl_multi *multi);
71
72
 
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,
85
79
#ifdef DEBUGBUILD
86
80
static const char * const statename[]={
87
81
  "INIT",
 
82
  "CONNECT_PEND",
88
83
  "CONNECT",
89
84
  "WAITRESOLVE",
90
85
  "WAITCONNECT",
125
120
  easy->state = state;
126
121
 
127
122
#ifdef DEBUGBUILD
128
 
  if(easy->easy_conn) {
129
 
    if(easy->state > CURLM_STATE_CONNECT &&
130
 
       easy->state < CURLM_STATE_COMPLETED)
 
123
  if(easy->state >= CURLM_STATE_CONNECT_PEND &&
 
124
     easy->state < CURLM_STATE_COMPLETED) {
 
125
    if(easy->easy_conn)
131
126
      connection_id = easy->easy_conn->connection_id;
132
127
 
133
128
    infof(easy->easy_handle,
218
213
    free(p);
219
214
}
220
215
 
221
 
static size_t fd_key_compare(void*k1, size_t k1_len, void*k2, size_t k2_len)
 
216
static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
222
217
{
223
218
  (void) k1_len; (void) k2_len;
224
219
 
225
 
  return (*((int* ) k1)) == (*((int* ) k2));
 
220
  return (*((int *) k1)) == (*((int *) k2));
226
221
}
227
222
 
228
 
static size_t hash_fd(void* key, size_t key_length, size_t slots_num)
 
223
static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
229
224
{
230
 
  int fd = * ((int* ) key);
 
225
  int fd = *((int *) key);
231
226
  (void) key_length;
232
227
 
233
228
  return (fd % (int)slots_num);
314
309
  multi->easy.next = &multi->easy;
315
310
  multi->easy.prev = &multi->easy;
316
311
 
 
312
  multi->max_pipeline_length = 5;
317
313
  return (CURLM *) multi;
318
314
 
319
315
  error:
580
576
 
581
577
    /* as this was using a shared connection cache we clear the pointer
582
578
       to that since we're not part of that multi handle anymore */
583
 
    easy->easy_handle->state.conn_cache = NULL;
 
579
      easy->easy_handle->state.conn_cache = NULL;
584
580
 
585
581
    /* change state without using multistate(), only to make singlesocket() do
586
582
       what we want */
638
634
    return CURLM_BAD_EASY_HANDLE; /* twasn't found */
639
635
}
640
636
 
641
 
bool Curl_multi_canPipeline(const struct Curl_multi* multi)
 
637
bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi)
642
638
{
643
 
  return multi->pipelining_enabled;
 
639
  return (multi && multi->pipelining_enabled) ? TRUE : FALSE;
644
640
}
645
641
 
646
642
void Curl_multi_handlePipeBreak(struct SessionHandle *data)
802
798
  curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
803
799
  int bitmap;
804
800
  unsigned int i;
805
 
  unsigned int nfds = extra_nfds;
 
801
  unsigned int nfds = 0;
 
802
  unsigned int curlfds;
806
803
  struct pollfd *ufds = NULL;
807
804
 
808
805
  if(!GOOD_MULTI_HANDLE(multi))
832
829
    easy = easy->next; /* check next handle */
833
830
  }
834
831
 
 
832
  curlfds = nfds; /* number of internal file descriptors */
 
833
  nfds += extra_nfds; /* add the externally provided ones */
 
834
 
835
835
  if(nfds) {
836
836
    ufds = malloc(nfds * sizeof(struct pollfd));
837
837
    if(!ufds)
839
839
  }
840
840
  nfds = 0;
841
841
 
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);
846
 
 
847
 
    for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
848
 
      curl_socket_t s = CURL_SOCKET_BAD;
849
 
 
850
 
      if(bitmap & GETSOCK_READSOCK(i)) {
851
 
        ufds[nfds].fd = sockbunch[i];
852
 
        ufds[nfds].events = POLLIN;
853
 
        ++nfds;
854
 
        s = sockbunch[i];
855
 
      }
856
 
      if(bitmap & GETSOCK_WRITESOCK(i)) {
857
 
        ufds[nfds].fd = sockbunch[i];
858
 
        ufds[nfds].events = POLLOUT;
859
 
        ++nfds;
860
 
        s = sockbunch[i];
861
 
      }
862
 
      if(s == CURL_SOCKET_BAD) {
863
 
        break;
864
 
      }
 
842
  /* only do the second loop if we found descriptors in the first stage run
 
843
     above */
 
844
 
 
845
  if(curlfds) {
 
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);
 
850
 
 
851
      for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
 
852
        curl_socket_t s = CURL_SOCKET_BAD;
 
853
 
 
854
        if(bitmap & GETSOCK_READSOCK(i)) {
 
855
          ufds[nfds].fd = sockbunch[i];
 
856
          ufds[nfds].events = POLLIN;
 
857
          ++nfds;
 
858
          s = sockbunch[i];
 
859
        }
 
860
        if(bitmap & GETSOCK_WRITESOCK(i)) {
 
861
          ufds[nfds].fd = sockbunch[i];
 
862
          ufds[nfds].events = POLLOUT;
 
863
          ++nfds;
 
864
          s = sockbunch[i];
 
865
        }
 
866
        if(s == CURL_SOCKET_BAD) {
 
867
          break;
 
868
        }
 
869
      }
 
870
 
 
871
      easy = easy->next; /* check next handle */
865
872
    }
866
 
 
867
 
    easy = easy->next; /* check next handle */
868
873
  }
869
874
 
870
875
  /* Add external file descriptions from poll-like struct curl_waitfd */
998
1003
      }
999
1004
      break;
1000
1005
 
 
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. */
 
1009
      break;
 
1010
 
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;
 
1021
        break;
 
1022
      }
1006
1023
 
1007
1024
      if(CURLE_OK == easy->result) {
1008
1025
        /* Add this handle to the send or pend pipeline */
1009
 
        easy->result = addHandleToSendOrPendPipeline(data,
1010
 
                                                     easy->easy_conn);
 
1026
        easy->result = Curl_add_handle_to_pipeline(data, easy->easy_conn);
1011
1027
        if(CURLE_OK != easy->result)
1012
1028
          disconnect_conn = TRUE;
1013
1029
        else {
1202
1218
      }
1203
1219
      else {
1204
1220
        /* Perform the protocol's DO action */
1205
 
        easy->result = Curl_do(&easy->easy_conn,
1206
 
                               &dophase_done);
 
1221
        easy->result = Curl_do(&easy->easy_conn, &dophase_done);
 
1222
 
 
1223
        /* When Curl_do() returns failure, easy->easy_conn might be NULL! */
1207
1224
 
1208
1225
        if(CURLE_OK == easy->result) {
1209
1226
          if(!dophase_done) {
1292
1309
        else {
1293
1310
          /* failure detected */
1294
1311
          Curl_posttransfer(data);
1295
 
          Curl_done(&easy->easy_conn, easy->result, FALSE);
 
1312
          if(easy->easy_conn)
 
1313
            Curl_done(&easy->easy_conn, easy->result, FALSE);
1296
1314
          disconnect_conn = TRUE;
1297
1315
        }
1298
1316
      }
1346
1364
 
1347
1365
    case CURLM_STATE_DO_DONE:
1348
1366
      /* Move ourselves from the send to recv pipeline */
1349
 
      moveHandleFromSendToRecvPipeline(data, easy->easy_conn);
 
1367
      Curl_move_handle_from_send_to_recv_pipe(data, easy->easy_conn);
1350
1368
      /* Check if we can move pending requests to send pipe */
1351
 
      checkPendPipeline(easy->easy_conn);
 
1369
      Curl_multi_process_pending_handles(multi);
1352
1370
      multistate(easy, CURLM_STATE_WAITPERFORM);
1353
1371
      result = CURLM_CALL_MULTI_PERFORM;
1354
1372
      break;
1480
1498
        Curl_posttransfer(data);
1481
1499
 
1482
1500
        /* we're no longer receiving */
1483
 
        moveHandleFromRecvToDonePipeline(data,
1484
 
                                         easy->easy_conn);
 
1501
        Curl_removeHandleFromPipeline(data, easy->easy_conn->recv_pipe);
1485
1502
 
1486
1503
        /* expire the new receiving pipeline head */
1487
1504
        if(easy->easy_conn->recv_pipe->head)
1488
1505
          Curl_expire(easy->easy_conn->recv_pipe->head->ptr, 1);
1489
1506
 
1490
1507
        /* Check if we can move pending requests to send pipe */
1491
 
        checkPendPipeline(easy->easy_conn);
 
1508
        Curl_multi_process_pending_handles(multi);
1492
1509
 
1493
1510
        /* When we follow redirects or is set to retry the connection, we must
1494
1511
           to go back to the CONNECT state */
1543
1560
    case CURLM_STATE_DONE:
1544
1561
 
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);
1554
1568
 
1555
1569
        if(easy->easy_conn->bits.stream_was_rewound) {
1556
1570
          /* This request read past its response boundary so we quickly let
1627
1641
                                        easy->easy_conn->send_pipe);
1628
1642
          Curl_removeHandleFromPipeline(data,
1629
1643
                                        easy->easy_conn->recv_pipe);
1630
 
          Curl_removeHandleFromPipeline(data,
1631
 
                                        easy->easy_conn->done_pipe);
1632
1644
          /* Check if we can move pending requests to send pipe */
1633
 
          checkPendPipeline(easy->easy_conn);
 
1645
          Curl_multi_process_pending_handles(multi);
1634
1646
 
1635
1647
          if(disconnect_conn) {
1636
1648
            /* disconnect properly */
1814
1826
    Curl_hash_destroy(multi->hostcache);
1815
1827
    multi->hostcache = NULL;
1816
1828
 
 
1829
    /* Free the blacklists by setting them to NULL */
 
1830
    Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
 
1831
    Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
 
1832
 
1817
1833
    free(multi);
1818
1834
 
1819
1835
    return CURLM_OK;
2231
2247
  case CURLMOPT_MAXCONNECTS:
2232
2248
    multi->maxconnects = va_arg(param, long);
2233
2249
    break;
 
2250
  case CURLMOPT_MAX_HOST_CONNECTIONS:
 
2251
    multi->max_host_connections = va_arg(param, long);
 
2252
    break;
 
2253
  case CURLMOPT_MAX_PIPELINE_LENGTH:
 
2254
    multi->max_pipeline_length = va_arg(param, long);
 
2255
    break;
 
2256
  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
 
2257
    multi->content_length_penalty_size = va_arg(param, long);
 
2258
    break;
 
2259
  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
 
2260
    multi->chunk_length_penalty_size = va_arg(param, long);
 
2261
    break;
 
2262
  case CURLMOPT_PIPELINING_SITE_BL:
 
2263
    res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
 
2264
                                           &multi->pipelining_site_bl);
 
2265
    break;
 
2266
  case CURLMOPT_PIPELINING_SERVER_BL:
 
2267
    res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
 
2268
                                             &multi->pipelining_server_bl);
 
2269
    break;
 
2270
  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
 
2271
    multi->max_total_connections = va_arg(param, long);
 
2272
    break;
2234
2273
  default:
2235
2274
    res = CURLM_UNKNOWN_OPTION;
2236
2275
    break;
2355
2394
  return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
2356
2395
}
2357
2396
 
2358
 
static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
 
2397
void Curl_multi_set_easy_connection(struct SessionHandle *handle,
2359
2398
                                              struct connectdata *conn)
2360
2399
{
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;
2364
 
  CURLcode rc;
2365
 
 
2366
 
  if(!Curl_isPipeliningEnabled(handle) ||
2367
 
     pipeLen == 0)
2368
 
    pipeline = conn->send_pipe;
2369
 
  else {
2370
 
    if(conn->server_supports_pipelining &&
2371
 
       pipeLen < MAX_PIPELINE_LENGTH)
2372
 
      pipeline = conn->send_pipe;
2373
 
    else
2374
 
      pipeline = conn->pend_pipe;
2375
 
  }
2376
 
 
2377
 
  rc = Curl_addHandleToPipeline(handle, pipeline);
2378
 
 
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 */
2382
 
#ifdef DEBUGBUILD
2383
 
    infof(conn->data, "%p is at send pipe head!\n",
2384
 
          conn->send_pipe->head->ptr);
2385
 
#endif
2386
 
    Curl_expire(conn->send_pipe->head->ptr, 1);
2387
 
  }
2388
 
 
2389
 
  return rc;
2390
 
}
2391
 
 
2392
 
static int checkPendPipeline(struct connectdata *conn)
2393
 
{
2394
 
  int result = 0;
2395
 
  struct curl_llist_element *sendhead = conn->send_pipe->head;
2396
 
 
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;
2402
 
 
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;
2409
 
      ++pipeLen;
2410
 
    }
2411
 
  }
2412
 
 
2413
 
  if(result) {
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 */
2419
 
#ifdef DEBUGBUILD
2420
 
      infof(conn->data, "%p is at send pipe head!\n",
2421
 
            conn->send_pipe->head->ptr);
2422
 
#endif
2423
 
      Curl_expire(conn->send_pipe->head->ptr, 1);
2424
 
    }
2425
 
  }
2426
 
 
2427
 
  return result;
2428
 
}
2429
 
 
2430
 
/* Move this transfer from the sending list to the receiving list.
2431
 
 
2432
 
   Pay special attention to the new sending list "leader" as it needs to get
2433
 
   checked to update what sockets it acts on.
2434
 
 
2435
 
*/
2436
 
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
2437
 
                                             struct connectdata *conn)
2438
 
{
2439
 
  struct curl_llist_element *curr;
2440
 
 
2441
 
  curr = conn->send_pipe->head;
2442
 
  while(curr) {
2443
 
    if(curr->ptr == handle) {
2444
 
      Curl_llist_move(conn->send_pipe, curr,
2445
 
                      conn->recv_pipe, conn->recv_pipe->tail);
2446
 
 
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 */
2451
 
#ifdef DEBUGBUILD
2452
 
        infof(conn->data, "%p is at send pipe head B!\n",
2453
 
              conn->send_pipe->head->ptr);
2454
 
#endif
2455
 
        Curl_expire(conn->send_pipe->head->ptr, 1);
2456
 
      }
2457
 
 
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 */
2461
 
 
2462
 
      break; /* we're done! */
2463
 
    }
2464
 
    curr = curr->next;
2465
 
  }
2466
 
}
2467
 
 
2468
 
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
2469
 
                                            struct connectdata *conn)
2470
 
{
2471
 
  struct curl_llist_element *curr;
2472
 
 
2473
 
  curr = conn->recv_pipe->head;
2474
 
  while(curr) {
2475
 
    if(curr->ptr == handle) {
2476
 
      Curl_llist_move(conn->recv_pipe, curr,
2477
 
                      conn->done_pipe, conn->done_pipe->tail);
2478
 
      break;
2479
 
    }
2480
 
    curr = curr->next;
2481
 
  }
2482
 
}
 
2400
  handle->set.one_easy->easy_conn = conn;
 
2401
}
 
2402
 
2483
2403
static bool isHandleAtHead(struct SessionHandle *handle,
2484
2404
                           struct curl_llist *pipeline)
2485
2405
{
2659
2579
  return CURLM_OK;
2660
2580
}
2661
2581
 
 
2582
size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
 
2583
{
 
2584
  return multi ? multi->max_host_connections : 0;
 
2585
}
 
2586
 
 
2587
size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
 
2588
{
 
2589
  return multi ? multi->max_total_connections : 0;
 
2590
}
 
2591
 
 
2592
size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi)
 
2593
{
 
2594
  return multi ? multi->max_pipeline_length : 0;
 
2595
}
 
2596
 
 
2597
curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
 
2598
{
 
2599
  return multi ? multi->content_length_penalty_size : 0;
 
2600
}
 
2601
 
 
2602
curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
 
2603
{
 
2604
  return multi ? multi->chunk_length_penalty_size : 0;
 
2605
}
 
2606
 
 
2607
struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
 
2608
{
 
2609
  return multi->pipelining_site_bl;
 
2610
}
 
2611
 
 
2612
struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
 
2613
{
 
2614
  return multi->pipelining_server_bl;
 
2615
}
 
2616
 
 
2617
void Curl_multi_process_pending_handles(struct Curl_multi *multi)
 
2618
{
 
2619
  struct Curl_one_easy *easy;
 
2620
 
 
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);
 
2627
    }
 
2628
    easy = easy->next; /* operate on next handle */
 
2629
  }
 
2630
}
 
2631
 
2662
2632
#ifdef DEBUGBUILD
2663
2633
void Curl_multi_dump(const struct Curl_multi *multi_handle)
2664
2634
{