00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #include <curl/curl.h>
00026
00027 #include "urldata.h"
00028 #include "transfer.h"
00029 #include "url.h"
00030 #include "connect.h"
00031 #include "progress.h"
00032 #include "easyif.h"
00033 #include "share.h"
00034 #include "multiif.h"
00035 #include "sendf.h"
00036 #include "timeval.h"
00037 #include "http.h"
00038 #include "select.h"
00039 #include "warnless.h"
00040 #include "speedcheck.h"
00041 #include "conncache.h"
00042 #include "multihandle.h"
00043 #include "pipeline.h"
00044 #include "sigpipe.h"
00045 #include "vtls/vtls.h"
00046 #include "connect.h"
00047
00048 #include "curl_printf.h"
00049 #include "curl_memory.h"
00050 #include "memdebug.h"
00051
00052
00053
00054
00055
00056
00057 #ifndef CURL_SOCKET_HASH_TABLE_SIZE
00058 #define CURL_SOCKET_HASH_TABLE_SIZE 911
00059 #endif
00060
00061 #define CURL_CONNECTION_HASH_SIZE 97
00062
00063 #define CURL_MULTI_HANDLE 0x000bab1e
00064
00065 #define GOOD_MULTI_HANDLE(x) \
00066 ((x) && (x)->type == CURL_MULTI_HANDLE)
00067
00068 static void singlesocket(struct Curl_multi *multi,
00069 struct Curl_easy *data);
00070 static int update_timer(struct Curl_multi *multi);
00071
00072 static CURLMcode add_next_timeout(struct timeval now,
00073 struct Curl_multi *multi,
00074 struct Curl_easy *d);
00075 static CURLMcode multi_timeout(struct Curl_multi *multi,
00076 long *timeout_ms);
00077
00078 #ifdef DEBUGBUILD
00079 static const char * const statename[]={
00080 "INIT",
00081 "CONNECT_PEND",
00082 "CONNECT",
00083 "WAITRESOLVE",
00084 "WAITCONNECT",
00085 "WAITPROXYCONNECT",
00086 "SENDPROTOCONNECT",
00087 "PROTOCONNECT",
00088 "WAITDO",
00089 "DO",
00090 "DOING",
00091 "DO_MORE",
00092 "DO_DONE",
00093 "WAITPERFORM",
00094 "PERFORM",
00095 "TOOFAST",
00096 "DONE",
00097 "COMPLETED",
00098 "MSGSENT",
00099 };
00100 #endif
00101
00102 static void multi_freetimeout(void *a, void *b);
00103
00104
00105 typedef void (*init_multistate_func)(struct Curl_easy *data);
00106
00107
00108 static void mstate(struct Curl_easy *data, CURLMstate state
00109 #ifdef DEBUGBUILD
00110 , int lineno
00111 #endif
00112 )
00113 {
00114 CURLMstate oldstate = data->mstate;
00115 static const init_multistate_func finit[CURLM_STATE_LAST] = {
00116 NULL,
00117 NULL,
00118 Curl_init_CONNECT,
00119
00120 };
00121
00122 #if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
00123 (void) lineno;
00124 #endif
00125
00126 if(oldstate == state)
00127
00128 return;
00129
00130 data->mstate = state;
00131
00132 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00133 if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
00134 data->mstate < CURLM_STATE_COMPLETED) {
00135 long connection_id = -5000;
00136
00137 if(data->easy_conn)
00138 connection_id = data->easy_conn->connection_id;
00139
00140 infof(data,
00141 "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
00142 statename[oldstate], statename[data->mstate],
00143 (void *)data, lineno, connection_id);
00144 }
00145 #endif
00146
00147 if(state == CURLM_STATE_COMPLETED)
00148
00149 data->multi->num_alive--;
00150
00151
00152 if(finit[state])
00153 finit[state](data);
00154 }
00155
00156 #ifndef DEBUGBUILD
00157 #define multistate(x,y) mstate(x,y)
00158 #else
00159 #define multistate(x,y) mstate(x,y, __LINE__)
00160 #endif
00161
00162
00163
00164
00165
00166 struct Curl_sh_entry {
00167 struct Curl_easy *easy;
00168 int action;
00169 curl_socket_t socket;
00170 void *socketp;
00171 };
00172
00173
00174 #define SH_READ 1
00175 #define SH_WRITE 2
00176
00177
00178 static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
00179 curl_socket_t s)
00180 {
00181 if(s != CURL_SOCKET_BAD)
00182
00183 return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
00184 return NULL;
00185 }
00186
00187
00188 static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
00189 curl_socket_t s,
00190 struct Curl_easy *data)
00191 {
00192 struct Curl_sh_entry *there = sh_getentry(sh, s);
00193 struct Curl_sh_entry *check;
00194
00195 if(there)
00196
00197 return there;
00198
00199
00200 check = calloc(1, sizeof(struct Curl_sh_entry));
00201 if(!check)
00202 return NULL;
00203
00204 check->easy = data;
00205 check->socket = s;
00206
00207
00208 if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
00209 free(check);
00210 return NULL;
00211 }
00212
00213 return check;
00214 }
00215
00216
00217
00218 static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
00219 {
00220
00221
00222 Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
00223 }
00224
00225
00226
00227
00228 static void sh_freeentry(void *freethis)
00229 {
00230 struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
00231
00232 free(p);
00233 }
00234
00235 static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
00236 {
00237 (void) k1_len; (void) k2_len;
00238
00239 return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
00240 }
00241
00242 static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
00243 {
00244 curl_socket_t fd = *((curl_socket_t *) key);
00245 (void) key_length;
00246
00247 return (fd % slots_num);
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 static int sh_init(struct curl_hash *hash, int hashsize)
00269 {
00270 return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
00271 sh_freeentry);
00272 }
00273
00274
00275
00276
00277
00278
00279
00280 static CURLMcode multi_addmsg(struct Curl_multi *multi,
00281 struct Curl_message *msg)
00282 {
00283 if(!Curl_llist_insert_next(multi->msglist, multi->msglist->tail, msg))
00284 return CURLM_OUT_OF_MEMORY;
00285
00286 return CURLM_OK;
00287 }
00288
00289
00290
00291
00292
00293
00294 static void multi_freeamsg(void *a, void *b)
00295 {
00296 (void)a;
00297 (void)b;
00298 }
00299
00300 struct Curl_multi *Curl_multi_handle(int hashsize,
00301 int chashsize)
00302 {
00303 struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
00304
00305 if(!multi)
00306 return NULL;
00307
00308 multi->type = CURL_MULTI_HANDLE;
00309
00310 if(Curl_mk_dnscache(&multi->hostcache))
00311 goto error;
00312
00313 if(sh_init(&multi->sockhash, hashsize))
00314 goto error;
00315
00316 if(Curl_conncache_init(&multi->conn_cache, chashsize))
00317 goto error;
00318
00319 multi->msglist = Curl_llist_alloc(multi_freeamsg);
00320 if(!multi->msglist)
00321 goto error;
00322
00323 multi->pending = Curl_llist_alloc(multi_freeamsg);
00324 if(!multi->pending)
00325 goto error;
00326
00327
00328 multi->closure_handle = curl_easy_init();
00329 if(!multi->closure_handle)
00330 goto error;
00331
00332 multi->closure_handle->multi = multi;
00333 multi->closure_handle->state.conn_cache = &multi->conn_cache;
00334
00335 multi->max_pipeline_length = 5;
00336
00337
00338 multi->maxconnects = -1;
00339 return multi;
00340
00341 error:
00342
00343 Curl_hash_destroy(&multi->sockhash);
00344 Curl_hash_destroy(&multi->hostcache);
00345 Curl_conncache_destroy(&multi->conn_cache);
00346 Curl_close(multi->closure_handle);
00347 multi->closure_handle = NULL;
00348 Curl_llist_destroy(multi->msglist, NULL);
00349 Curl_llist_destroy(multi->pending, NULL);
00350
00351 free(multi);
00352 return NULL;
00353 }
00354
00355 struct Curl_multi *curl_multi_init(void)
00356 {
00357 return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
00358 CURL_CONNECTION_HASH_SIZE);
00359 }
00360
00361 CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
00362 struct Curl_easy *data)
00363 {
00364 struct curl_llist *timeoutlist;
00365
00366
00367 if(!GOOD_MULTI_HANDLE(multi))
00368 return CURLM_BAD_HANDLE;
00369
00370
00371 if(!GOOD_EASY_HANDLE(data))
00372 return CURLM_BAD_EASY_HANDLE;
00373
00374
00375
00376 if(data->multi)
00377 return CURLM_ADDED_ALREADY;
00378
00379
00380 timeoutlist = Curl_llist_alloc(multi_freetimeout);
00381 if(!timeoutlist)
00382 return CURLM_OUT_OF_MEMORY;
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 data->state.timeoutlist = timeoutlist;
00393 timeoutlist = NULL;
00394
00395
00396 multistate(data, CURLM_STATE_INIT);
00397
00398 if((data->set.global_dns_cache) &&
00399 (data->dns.hostcachetype != HCACHE_GLOBAL)) {
00400
00401 struct curl_hash *global = Curl_global_host_cache_init();
00402 if(global) {
00403
00404 data->dns.hostcache = global;
00405 data->dns.hostcachetype = HCACHE_GLOBAL;
00406 }
00407 }
00408
00409
00410 else if(!data->dns.hostcache ||
00411 (data->dns.hostcachetype == HCACHE_NONE)) {
00412 data->dns.hostcache = &multi->hostcache;
00413 data->dns.hostcachetype = HCACHE_MULTI;
00414 }
00415
00416
00417 data->state.conn_cache = &multi->conn_cache;
00418
00419
00420
00421
00422
00423
00424
00425 data->next = NULL;
00426 if(multi->easyp) {
00427 struct Curl_easy *last = multi->easylp;
00428 last->next = data;
00429 data->prev = last;
00430 multi->easylp = data;
00431 }
00432 else {
00433
00434 data->prev = NULL;
00435 multi->easylp = multi->easyp = data;
00436 }
00437
00438
00439 data->multi = multi;
00440
00441
00442
00443
00444
00445
00446
00447 Curl_expire(data, 0);
00448
00449
00450 multi->num_easy++;
00451
00452
00453 multi->num_alive++;
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
00466
00467
00468
00469
00470
00471 multi->closure_handle->set.timeout = data->set.timeout;
00472 multi->closure_handle->set.server_response_timeout =
00473 data->set.server_response_timeout;
00474
00475 update_timer(multi);
00476 return CURLM_OK;
00477 }
00478
00479 #if 0
00480
00481
00482
00483
00484
00485
00486 static void debug_print_sock_hash(void *p)
00487 {
00488 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
00489
00490 fprintf(stderr, " [easy %p/magic %x/socket %d]",
00491 (void *)sh->data, sh->data->magic, (int)sh->socket);
00492 }
00493 #endif
00494
00495
00496
00497 static bool
00498 ConnectionDone(struct Curl_easy *data, struct connectdata *conn)
00499 {
00500
00501 size_t maxconnects =
00502 (data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
00503 data->multi->maxconnects;
00504 struct connectdata *conn_candidate = NULL;
00505
00506
00507 conn->inuse = FALSE;
00508
00509 if(maxconnects > 0 &&
00510 data->state.conn_cache->num_connections > maxconnects) {
00511 infof(data, "Connection cache is full, closing the oldest one.\n");
00512
00513 conn_candidate = Curl_oldest_idle_connection(data);
00514
00515 if(conn_candidate) {
00516
00517 conn_candidate->data = data;
00518
00519
00520 (void)Curl_disconnect(conn_candidate, FALSE);
00521 }
00522 }
00523
00524 return (conn_candidate == conn) ? FALSE : TRUE;
00525 }
00526
00527 static CURLcode multi_done(struct connectdata **connp,
00528 CURLcode status,
00529
00530 bool premature)
00531 {
00532 CURLcode result;
00533 struct connectdata *conn;
00534 struct Curl_easy *data;
00535
00536 DEBUGASSERT(*connp);
00537
00538 conn = *connp;
00539 data = conn->data;
00540
00541 DEBUGF(infof(data, "multi_done\n"));
00542
00543 if(data->state.done)
00544
00545 return CURLE_OK;
00546
00547 Curl_getoff_all_pipelines(data, conn);
00548
00549
00550 free(data->req.newurl);
00551 data->req.newurl = NULL;
00552 free(data->req.location);
00553 data->req.location = NULL;
00554
00555 switch(status) {
00556 case CURLE_ABORTED_BY_CALLBACK:
00557 case CURLE_READ_ERROR:
00558 case CURLE_WRITE_ERROR:
00559
00560
00561
00562
00563 premature = TRUE;
00564 default:
00565 break;
00566 }
00567
00568
00569 if(conn->handler->done)
00570 result = conn->handler->done(conn, status, premature);
00571 else
00572 result = status;
00573
00574 if(CURLE_ABORTED_BY_CALLBACK != result) {
00575
00576
00577 CURLcode rc = Curl_pgrsDone(conn);
00578 if(!result && rc)
00579 result = CURLE_ABORTED_BY_CALLBACK;
00580 }
00581
00582 if(conn->send_pipe->size + conn->recv_pipe->size != 0 &&
00583 !data->set.reuse_forbid &&
00584 !conn->bits.close) {
00585
00586
00587 data->easy_conn = NULL;
00588 DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n"));
00589 return CURLE_OK;
00590 }
00591
00592 data->state.done = TRUE;
00593 Curl_resolver_cancel(conn);
00594
00595 if(conn->dns_entry) {
00596 Curl_resolv_unlock(data, conn->dns_entry);
00597 conn->dns_entry = NULL;
00598 }
00599
00600
00601
00602 free(data->state.tempwrite);
00603 data->state.tempwrite = NULL;
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 if((data->set.reuse_forbid
00621 #if defined(USE_NTLM)
00622 && !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
00623 conn->proxyntlm.state == NTLMSTATE_TYPE2)
00624 #endif
00625 ) || conn->bits.close || premature) {
00626 CURLcode res2 = Curl_disconnect(conn, premature);
00627
00628
00629
00630 if(!result && res2)
00631 result = res2;
00632 }
00633 else {
00634
00635 if(ConnectionDone(data, conn)) {
00636
00637 data->state.lastconnect = conn;
00638
00639 infof(data, "Connection #%ld to host %s left intact\n",
00640 conn->connection_id,
00641 conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
00642 }
00643 else
00644 data->state.lastconnect = NULL;
00645 }
00646
00647 *connp = NULL;
00648
00649
00650
00651 Curl_free_request_state(data);
00652
00653 return result;
00654 }
00655
00656 CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
00657 struct Curl_easy *data)
00658 {
00659 struct Curl_easy *easy = data;
00660 bool premature;
00661 bool easy_owns_conn;
00662 struct curl_llist_element *e;
00663
00664
00665 if(!GOOD_MULTI_HANDLE(multi))
00666 return CURLM_BAD_HANDLE;
00667
00668
00669 if(!GOOD_EASY_HANDLE(data))
00670 return CURLM_BAD_EASY_HANDLE;
00671
00672
00673 if(!data->multi)
00674 return CURLM_OK;
00675
00676 premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
00677 easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ?
00678 TRUE : FALSE;
00679
00680
00681
00682 if(premature) {
00683
00684
00685 multi->num_alive--;
00686
00687
00688
00689 Curl_multi_process_pending_handles(multi);
00690 }
00691
00692 if(data->easy_conn &&
00693 data->mstate > CURLM_STATE_DO &&
00694 data->mstate < CURLM_STATE_COMPLETED) {
00695
00696
00697
00698 streamclose(data->easy_conn, "Removed with partial response");
00699
00700
00701 data->easy_conn->data = easy;
00702 easy_owns_conn = TRUE;
00703 }
00704
00705
00706
00707
00708 Curl_expire_clear(data);
00709
00710 if(data->dns.hostcachetype == HCACHE_MULTI) {
00711
00712 data->dns.hostcache = NULL;
00713 data->dns.hostcachetype = HCACHE_NONE;
00714 }
00715
00716 if(data->easy_conn) {
00717
00718
00719
00720 if(easy_owns_conn) {
00721
00722
00723
00724
00725
00726
00727 (void)multi_done(&data->easy_conn, data->result, premature);
00728 }
00729 else
00730
00731 Curl_getoff_all_pipelines(data, data->easy_conn);
00732 }
00733
00734 Curl_wildcard_dtor(&data->wildcard);
00735
00736
00737
00738 if(data->state.timeoutlist) {
00739 Curl_llist_destroy(data->state.timeoutlist, NULL);
00740 data->state.timeoutlist = NULL;
00741 }
00742
00743
00744
00745 data->state.conn_cache = NULL;
00746
00747
00748
00749 data->mstate = CURLM_STATE_COMPLETED;
00750 singlesocket(multi, easy);
00751
00752
00753
00754 if(data->easy_conn) {
00755 data->easy_conn->data = NULL;
00756 data->easy_conn = NULL;
00757 }
00758
00759 data->multi = NULL;
00760
00761
00762
00763
00764 for(e = multi->msglist->head; e; e = e->next) {
00765 struct Curl_message *msg = e->ptr;
00766
00767 if(msg->extmsg.easy_handle == easy) {
00768 Curl_llist_remove(multi->msglist, e, NULL);
00769
00770 break;
00771 }
00772 }
00773
00774
00775 if(data->prev)
00776 data->prev->next = data->next;
00777 else
00778 multi->easyp = data->next;
00779
00780
00781 if(data->next)
00782 data->next->prev = data->prev;
00783 else
00784 multi->easylp = data->prev;
00785
00786
00787
00788 multi->num_easy--;
00789
00790 update_timer(multi);
00791 return CURLM_OK;
00792 }
00793
00794
00795 bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
00796 {
00797 return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
00798 }
00799
00800 void Curl_multi_handlePipeBreak(struct Curl_easy *data)
00801 {
00802 data->easy_conn = NULL;
00803 }
00804
00805 static int waitconnect_getsock(struct connectdata *conn,
00806 curl_socket_t *sock,
00807 int numsocks)
00808 {
00809 int i;
00810 int s=0;
00811 int rc=0;
00812
00813 if(!numsocks)
00814 return GETSOCK_BLANK;
00815
00816 #ifdef USE_SSL
00817 if(CONNECT_FIRSTSOCKET_PROXY_SSL())
00818 return Curl_ssl_getsock(conn, sock, numsocks);
00819 #endif
00820
00821 for(i=0; i<2; i++) {
00822 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
00823 sock[s] = conn->tempsock[i];
00824 rc |= GETSOCK_WRITESOCK(s++);
00825 }
00826 }
00827
00828 return rc;
00829 }
00830
00831 static int waitproxyconnect_getsock(struct connectdata *conn,
00832 curl_socket_t *sock,
00833 int numsocks)
00834 {
00835 if(!numsocks)
00836 return GETSOCK_BLANK;
00837
00838 sock[0] = conn->sock[FIRSTSOCKET];
00839
00840
00841
00842 if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
00843 return GETSOCK_READSOCK(0);
00844
00845 return GETSOCK_WRITESOCK(0);
00846 }
00847
00848 static int domore_getsock(struct connectdata *conn,
00849 curl_socket_t *socks,
00850 int numsocks)
00851 {
00852 if(conn && conn->handler->domore_getsock)
00853 return conn->handler->domore_getsock(conn, socks, numsocks);
00854 return GETSOCK_BLANK;
00855 }
00856
00857
00858 static int multi_getsock(struct Curl_easy *data,
00859 curl_socket_t *socks,
00860
00861 int numsocks)
00862 {
00863
00864
00865
00866
00867
00868 if(data->state.pipe_broke || !data->easy_conn)
00869 return 0;
00870
00871 if(data->mstate > CURLM_STATE_CONNECT &&
00872 data->mstate < CURLM_STATE_COMPLETED) {
00873
00874 data->easy_conn->data = data;
00875 }
00876
00877 switch(data->mstate) {
00878 default:
00879 #if 0
00880
00881 case CURLM_STATE_TOOFAST:
00882 case CURLM_STATE_COMPLETED:
00883 case CURLM_STATE_MSGSENT:
00884 case CURLM_STATE_INIT:
00885 case CURLM_STATE_CONNECT:
00886 case CURLM_STATE_WAITDO:
00887 case CURLM_STATE_DONE:
00888 case CURLM_STATE_LAST:
00889
00890
00891 #endif
00892 return 0;
00893
00894 case CURLM_STATE_WAITRESOLVE:
00895 return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
00896
00897 case CURLM_STATE_PROTOCONNECT:
00898 case CURLM_STATE_SENDPROTOCONNECT:
00899 return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
00900
00901 case CURLM_STATE_DO:
00902 case CURLM_STATE_DOING:
00903 return Curl_doing_getsock(data->easy_conn, socks, numsocks);
00904
00905 case CURLM_STATE_WAITPROXYCONNECT:
00906 return waitproxyconnect_getsock(data->easy_conn, socks, numsocks);
00907
00908 case CURLM_STATE_WAITCONNECT:
00909 return waitconnect_getsock(data->easy_conn, socks, numsocks);
00910
00911 case CURLM_STATE_DO_MORE:
00912 return domore_getsock(data->easy_conn, socks, numsocks);
00913
00914 case CURLM_STATE_DO_DONE:
00915
00916
00917 case CURLM_STATE_PERFORM:
00918 case CURLM_STATE_WAITPERFORM:
00919 return Curl_single_getsock(data->easy_conn, socks, numsocks);
00920 }
00921
00922 }
00923
00924 CURLMcode curl_multi_fdset(struct Curl_multi *multi,
00925 fd_set *read_fd_set, fd_set *write_fd_set,
00926 fd_set *exc_fd_set, int *max_fd)
00927 {
00928
00929
00930
00931 struct Curl_easy *data;
00932 int this_max_fd=-1;
00933 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
00934 int bitmap;
00935 int i;
00936 (void)exc_fd_set;
00937
00938 if(!GOOD_MULTI_HANDLE(multi))
00939 return CURLM_BAD_HANDLE;
00940
00941 data=multi->easyp;
00942 while(data) {
00943 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
00944
00945 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
00946 curl_socket_t s = CURL_SOCKET_BAD;
00947
00948 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
00949 FD_SET(sockbunch[i], read_fd_set);
00950 s = sockbunch[i];
00951 }
00952 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
00953 FD_SET(sockbunch[i], write_fd_set);
00954 s = sockbunch[i];
00955 }
00956 if(s == CURL_SOCKET_BAD)
00957
00958 break;
00959 else {
00960 if((int)s > this_max_fd)
00961 this_max_fd = (int)s;
00962 }
00963 }
00964
00965 data = data->next;
00966 }
00967
00968 *max_fd = this_max_fd;
00969
00970 return CURLM_OK;
00971 }
00972
00973 CURLMcode curl_multi_wait(struct Curl_multi *multi,
00974 struct curl_waitfd extra_fds[],
00975 unsigned int extra_nfds,
00976 int timeout_ms,
00977 int *ret)
00978 {
00979 struct Curl_easy *data;
00980 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
00981 int bitmap;
00982 unsigned int i;
00983 unsigned int nfds = 0;
00984 unsigned int curlfds;
00985 struct pollfd *ufds = NULL;
00986 long timeout_internal;
00987 int retcode = 0;
00988
00989 if(!GOOD_MULTI_HANDLE(multi))
00990 return CURLM_BAD_HANDLE;
00991
00992
00993
00994
00995 (void)multi_timeout(multi, &timeout_internal);
00996 if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
00997 timeout_ms = (int)timeout_internal;
00998
00999
01000 data=multi->easyp;
01001 while(data) {
01002 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
01003
01004 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
01005 curl_socket_t s = CURL_SOCKET_BAD;
01006
01007 if(bitmap & GETSOCK_READSOCK(i)) {
01008 ++nfds;
01009 s = sockbunch[i];
01010 }
01011 if(bitmap & GETSOCK_WRITESOCK(i)) {
01012 ++nfds;
01013 s = sockbunch[i];
01014 }
01015 if(s == CURL_SOCKET_BAD) {
01016 break;
01017 }
01018 }
01019
01020 data = data->next;
01021 }
01022
01023 curlfds = nfds;
01024 nfds += extra_nfds;
01025
01026 if(nfds || extra_nfds) {
01027 ufds = malloc(nfds * sizeof(struct pollfd));
01028 if(!ufds)
01029 return CURLM_OUT_OF_MEMORY;
01030 }
01031 nfds = 0;
01032
01033
01034
01035
01036 if(curlfds) {
01037
01038 data=multi->easyp;
01039 while(data) {
01040 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
01041
01042 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
01043 curl_socket_t s = CURL_SOCKET_BAD;
01044
01045 if(bitmap & GETSOCK_READSOCK(i)) {
01046 ufds[nfds].fd = sockbunch[i];
01047 ufds[nfds].events = POLLIN;
01048 ++nfds;
01049 s = sockbunch[i];
01050 }
01051 if(bitmap & GETSOCK_WRITESOCK(i)) {
01052 ufds[nfds].fd = sockbunch[i];
01053 ufds[nfds].events = POLLOUT;
01054 ++nfds;
01055 s = sockbunch[i];
01056 }
01057 if(s == CURL_SOCKET_BAD) {
01058 break;
01059 }
01060 }
01061
01062 data = data->next;
01063 }
01064 }
01065
01066
01067 for(i = 0; i < extra_nfds; i++) {
01068 ufds[nfds].fd = extra_fds[i].fd;
01069 ufds[nfds].events = 0;
01070 if(extra_fds[i].events & CURL_WAIT_POLLIN)
01071 ufds[nfds].events |= POLLIN;
01072 if(extra_fds[i].events & CURL_WAIT_POLLPRI)
01073 ufds[nfds].events |= POLLPRI;
01074 if(extra_fds[i].events & CURL_WAIT_POLLOUT)
01075 ufds[nfds].events |= POLLOUT;
01076 ++nfds;
01077 }
01078
01079 if(nfds) {
01080 int pollrc;
01081
01082 pollrc = Curl_poll(ufds, nfds, timeout_ms);
01083 DEBUGF(infof(data, "Curl_poll(%d ds, %d ms) == %d\n",
01084 nfds, timeout_ms, pollrc));
01085
01086 if(pollrc > 0) {
01087 retcode = pollrc;
01088
01089
01090
01091 for(i = 0; i < extra_nfds; i++) {
01092 unsigned short mask = 0;
01093 unsigned r = ufds[curlfds + i].revents;
01094
01095 if(r & POLLIN)
01096 mask |= CURL_WAIT_POLLIN;
01097 if(r & POLLOUT)
01098 mask |= CURL_WAIT_POLLOUT;
01099 if(r & POLLPRI)
01100 mask |= CURL_WAIT_POLLPRI;
01101
01102 extra_fds[i].revents = mask;
01103 }
01104 }
01105 }
01106
01107 free(ufds);
01108 if(ret)
01109 *ret = retcode;
01110 return CURLM_OK;
01111 }
01112
01113
01114
01115
01116
01117
01118
01119
01120 void Curl_multi_connchanged(struct Curl_multi *multi)
01121 {
01122 multi->recheckstate = TRUE;
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 static bool multi_ischanged(struct Curl_multi *multi, bool clear)
01134 {
01135 bool retval = multi->recheckstate;
01136 if(clear)
01137 multi->recheckstate = FALSE;
01138 return retval;
01139 }
01140
01141 CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
01142 struct Curl_easy *data,
01143 struct connectdata *conn)
01144 {
01145 CURLMcode rc;
01146
01147 rc = curl_multi_add_handle(multi, data);
01148 if(!rc) {
01149 struct SingleRequest *k = &data->req;
01150
01151
01152
01153 Curl_init_do(data, NULL);
01154
01155
01156 multistate(data, CURLM_STATE_PERFORM);
01157 data->easy_conn = conn;
01158 k->keepon |= KEEP_RECV;
01159 }
01160 return rc;
01161 }
01162
01163 static CURLcode multi_reconnect_request(struct connectdata **connp)
01164 {
01165 CURLcode result = CURLE_OK;
01166 struct connectdata *conn = *connp;
01167 struct Curl_easy *data = conn->data;
01168
01169
01170
01171
01172
01173
01174
01175 infof(data, "Re-used connection seems dead, get a new one\n");
01176
01177 connclose(conn, "Reconnect dead connection");
01178 result = multi_done(&conn, result, FALSE);
01179
01180
01181
01182 *connp = NULL;
01183
01184
01185
01186
01187
01188
01189 if(!result || (CURLE_SEND_ERROR == result)) {
01190 bool async;
01191 bool protocol_done = TRUE;
01192
01193
01194 result = Curl_connect(data, connp, &async, &protocol_done);
01195 if(!result) {
01196
01197
01198 conn = *connp;
01199 if(async) {
01200
01201
01202 result = Curl_resolver_wait_resolv(conn, NULL);
01203 if(result)
01204 return result;
01205
01206
01207 result = Curl_async_resolved(conn, &protocol_done);
01208 if(result)
01209 return result;
01210 }
01211 }
01212 }
01213
01214 return result;
01215 }
01216
01217
01218
01219
01220
01221
01222
01223 static void do_complete(struct connectdata *conn)
01224 {
01225 conn->data->req.chunk=FALSE;
01226 conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
01227 conn->sockfd:conn->writesockfd)+1;
01228 Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
01229 }
01230
01231 static CURLcode multi_do(struct connectdata **connp, bool *done)
01232 {
01233 CURLcode result=CURLE_OK;
01234 struct connectdata *conn = *connp;
01235 struct Curl_easy *data = conn->data;
01236
01237 if(conn->handler->do_it) {
01238
01239 result = conn->handler->do_it(conn, done);
01240
01241
01242 if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
01243
01244
01245
01246
01247
01248 if(!data->multi) {
01249 result = multi_reconnect_request(connp);
01250
01251 if(!result) {
01252
01253 conn = *connp;
01254
01255 result = conn->handler->do_it(conn, done);
01256 }
01257 }
01258 else
01259 return result;
01260 }
01261
01262 if(!result && *done)
01263
01264 do_complete(conn);
01265 }
01266 return result;
01267 }
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280 static CURLcode multi_do_more(struct connectdata *conn, int *complete)
01281 {
01282 CURLcode result=CURLE_OK;
01283
01284 *complete = 0;
01285
01286 if(conn->handler->do_more)
01287 result = conn->handler->do_more(conn, complete);
01288
01289 if(!result && (*complete == 1))
01290
01291 do_complete(conn);
01292
01293 return result;
01294 }
01295
01296 static CURLMcode multi_runsingle(struct Curl_multi *multi,
01297 struct timeval now,
01298 struct Curl_easy *data)
01299 {
01300 struct Curl_message *msg = NULL;
01301 bool connected;
01302 bool async;
01303 bool protocol_connect = FALSE;
01304 bool dophase_done = FALSE;
01305 bool done = FALSE;
01306 CURLMcode rc;
01307 CURLcode result = CURLE_OK;
01308 struct SingleRequest *k;
01309 time_t timeout_ms;
01310 int control;
01311
01312 if(!GOOD_EASY_HANDLE(data))
01313 return CURLM_BAD_EASY_HANDLE;
01314
01315 do {
01316
01317
01318 bool stream_error = FALSE;
01319 rc = CURLM_OK;
01320
01321
01322
01323 if(data->state.pipe_broke) {
01324 infof(data, "Pipe broke: handle %p, url = %s\n",
01325 (void *)data, data->state.path);
01326
01327 if(data->mstate < CURLM_STATE_COMPLETED) {
01328
01329 multistate(data, CURLM_STATE_CONNECT);
01330 rc = CURLM_CALL_MULTI_PERFORM;
01331 result = CURLE_OK;
01332 }
01333
01334 data->state.pipe_broke = FALSE;
01335 data->easy_conn = NULL;
01336 continue;
01337 }
01338
01339 if(!data->easy_conn &&
01340 data->mstate > CURLM_STATE_CONNECT &&
01341 data->mstate < CURLM_STATE_DONE) {
01342
01343
01344
01345 failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate);
01346 return CURLM_INTERNAL_ERROR;
01347 }
01348
01349 if(multi_ischanged(multi, TRUE)) {
01350 DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
01351 Curl_multi_process_pending_handles(multi);
01352 }
01353
01354 if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
01355 data->mstate < CURLM_STATE_COMPLETED)
01356
01357 data->easy_conn->data = data;
01358
01359 if(data->easy_conn &&
01360 (data->mstate >= CURLM_STATE_CONNECT) &&
01361 (data->mstate < CURLM_STATE_COMPLETED)) {
01362
01363
01364
01365 timeout_ms = Curl_timeleft(data, &now,
01366 (data->mstate <= CURLM_STATE_WAITDO)?
01367 TRUE:FALSE);
01368
01369 if(timeout_ms < 0) {
01370
01371 if(data->mstate == CURLM_STATE_WAITRESOLVE)
01372 failf(data, "Resolving timed out after %ld milliseconds",
01373 Curl_tvdiff(now, data->progress.t_startsingle));
01374 else if(data->mstate == CURLM_STATE_WAITCONNECT)
01375 failf(data, "Connection timed out after %ld milliseconds",
01376 Curl_tvdiff(now, data->progress.t_startsingle));
01377 else {
01378 k = &data->req;
01379 if(k->size != -1) {
01380 failf(data, "Operation timed out after %ld milliseconds with %"
01381 CURL_FORMAT_CURL_OFF_T " out of %"
01382 CURL_FORMAT_CURL_OFF_T " bytes received",
01383 Curl_tvdiff(now, data->progress.t_startsingle),
01384 k->bytecount, k->size);
01385 }
01386 else {
01387 failf(data, "Operation timed out after %ld milliseconds with %"
01388 CURL_FORMAT_CURL_OFF_T " bytes received",
01389 Curl_tvdiff(now, data->progress.t_startsingle),
01390 k->bytecount);
01391 }
01392 }
01393
01394
01395 if(data->mstate > CURLM_STATE_DO) {
01396 streamclose(data->easy_conn, "Disconnected with pending data");
01397 stream_error = TRUE;
01398 }
01399 result = CURLE_OPERATION_TIMEDOUT;
01400 (void)multi_done(&data->easy_conn, result, TRUE);
01401
01402 goto statemachine_end;
01403 }
01404 }
01405
01406 switch(data->mstate) {
01407 case CURLM_STATE_INIT:
01408
01409 result=Curl_pretransfer(data);
01410
01411 if(!result) {
01412
01413 multistate(data, CURLM_STATE_CONNECT);
01414 Curl_pgrsTime(data, TIMER_STARTOP);
01415 rc = CURLM_CALL_MULTI_PERFORM;
01416 }
01417 break;
01418
01419 case CURLM_STATE_CONNECT_PEND:
01420
01421
01422 break;
01423
01424 case CURLM_STATE_CONNECT:
01425
01426 Curl_pgrsTime(data, TIMER_STARTSINGLE);
01427 result = Curl_connect(data, &data->easy_conn,
01428 &async, &protocol_connect);
01429 if(CURLE_NO_CONNECTION_AVAILABLE == result) {
01430
01431
01432 multistate(data, CURLM_STATE_CONNECT_PEND);
01433
01434
01435 if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data))
01436 result = CURLE_OUT_OF_MEMORY;
01437 else
01438 result = CURLE_OK;
01439 break;
01440 }
01441
01442 if(!result) {
01443
01444 result = Curl_add_handle_to_pipeline(data, data->easy_conn);
01445 if(result)
01446 stream_error = TRUE;
01447 else {
01448 if(async)
01449
01450 multistate(data, CURLM_STATE_WAITRESOLVE);
01451 else {
01452
01453
01454
01455 rc = CURLM_CALL_MULTI_PERFORM;
01456
01457 if(protocol_connect)
01458 multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
01459 CURLM_STATE_WAITDO:CURLM_STATE_DO);
01460 else {
01461 #ifndef CURL_DISABLE_HTTP
01462 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
01463 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
01464 else
01465 #endif
01466 multistate(data, CURLM_STATE_WAITCONNECT);
01467 }
01468 }
01469 }
01470 }
01471 break;
01472
01473 case CURLM_STATE_WAITRESOLVE:
01474
01475 {
01476 struct Curl_dns_entry *dns = NULL;
01477 struct connectdata *conn = data->easy_conn;
01478 const char *hostname;
01479
01480 if(conn->bits.proxy)
01481 hostname = conn->proxy.name;
01482 else if(conn->bits.conn_to_host)
01483 hostname = conn->conn_to_host.name;
01484 else
01485 hostname = conn->host.name;
01486
01487
01488 dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
01489
01490 if(dns) {
01491 #ifdef CURLRES_ASYNCH
01492 conn->async.dns = dns;
01493 conn->async.done = TRUE;
01494 #endif
01495 result = CURLE_OK;
01496 infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
01497 }
01498
01499 if(!dns)
01500 result = Curl_resolver_is_resolved(data->easy_conn, &dns);
01501
01502
01503
01504
01505
01506
01507
01508 singlesocket(multi, data);
01509
01510 if(dns) {
01511
01512
01513 result = Curl_async_resolved(data->easy_conn, &protocol_connect);
01514
01515 if(result)
01516
01517
01518 data->easy_conn = NULL;
01519 else {
01520
01521 rc = CURLM_CALL_MULTI_PERFORM;
01522 if(protocol_connect)
01523 multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
01524 CURLM_STATE_WAITDO:CURLM_STATE_DO);
01525 else {
01526 #ifndef CURL_DISABLE_HTTP
01527 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
01528 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
01529 else
01530 #endif
01531 multistate(data, CURLM_STATE_WAITCONNECT);
01532 }
01533 }
01534 }
01535
01536 if(result) {
01537
01538 stream_error = TRUE;
01539 break;
01540 }
01541 }
01542 break;
01543
01544 #ifndef CURL_DISABLE_HTTP
01545 case CURLM_STATE_WAITPROXYCONNECT:
01546
01547 result = Curl_http_connect(data->easy_conn, &protocol_connect);
01548
01549 if(data->easy_conn->bits.proxy_connect_closed) {
01550 rc = CURLM_CALL_MULTI_PERFORM;
01551
01552 result = CURLE_OK;
01553 multi_done(&data->easy_conn, CURLE_OK, FALSE);
01554 multistate(data, CURLM_STATE_CONNECT);
01555 }
01556 else if(!result) {
01557 if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
01558 data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
01559 (data->easy_conn->tunnel_state[FIRSTSOCKET] != TUNNEL_CONNECT)) {
01560 rc = CURLM_CALL_MULTI_PERFORM;
01561
01562 multistate(data, CURLM_STATE_SENDPROTOCONNECT);
01563 }
01564 }
01565 break;
01566 #endif
01567
01568 case CURLM_STATE_WAITCONNECT:
01569
01570 result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected);
01571 if(connected && !result) {
01572 #ifndef CURL_DISABLE_HTTP
01573 if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
01574 !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
01575 (data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)) {
01576 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
01577 break;
01578 }
01579 #endif
01580 rc = CURLM_CALL_MULTI_PERFORM;
01581 multistate(data, data->easy_conn->bits.tunnel_proxy?
01582 CURLM_STATE_WAITPROXYCONNECT:
01583 CURLM_STATE_SENDPROTOCONNECT);
01584 }
01585 else if(result) {
01586
01587
01588 stream_error = TRUE;
01589 break;
01590 }
01591 break;
01592
01593 case CURLM_STATE_SENDPROTOCONNECT:
01594 result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
01595 if(!protocol_connect)
01596
01597 multistate(data, CURLM_STATE_PROTOCONNECT);
01598 else if(!result) {
01599
01600 multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
01601 CURLM_STATE_WAITDO:CURLM_STATE_DO);
01602 rc = CURLM_CALL_MULTI_PERFORM;
01603 }
01604 else if(result) {
01605
01606 Curl_posttransfer(data);
01607 multi_done(&data->easy_conn, result, TRUE);
01608 stream_error = TRUE;
01609 }
01610 break;
01611
01612 case CURLM_STATE_PROTOCONNECT:
01613
01614 result = Curl_protocol_connecting(data->easy_conn, &protocol_connect);
01615 if(!result && protocol_connect) {
01616
01617 multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
01618 CURLM_STATE_WAITDO:CURLM_STATE_DO);
01619 rc = CURLM_CALL_MULTI_PERFORM;
01620 }
01621 else if(result) {
01622
01623 Curl_posttransfer(data);
01624 multi_done(&data->easy_conn, result, TRUE);
01625 stream_error = TRUE;
01626 }
01627 break;
01628
01629 case CURLM_STATE_WAITDO:
01630
01631 if(Curl_pipeline_checkget_write(data, data->easy_conn)) {
01632
01633 multistate(data, CURLM_STATE_DO);
01634 rc = CURLM_CALL_MULTI_PERFORM;
01635 }
01636 break;
01637
01638 case CURLM_STATE_DO:
01639 if(data->set.connect_only) {
01640
01641 connkeep(data->easy_conn, "CONNECT_ONLY");
01642 multistate(data, CURLM_STATE_DONE);
01643 result = CURLE_OK;
01644 rc = CURLM_CALL_MULTI_PERFORM;
01645 }
01646 else {
01647
01648 result = multi_do(&data->easy_conn, &dophase_done);
01649
01650
01651
01652 if(!result) {
01653 if(!dophase_done) {
01654
01655 if(data->set.wildcardmatch) {
01656 struct WildcardData *wc = &data->wildcard;
01657 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
01658
01659 multi_done(&data->easy_conn, CURLE_OK, FALSE);
01660 multistate(data, CURLM_STATE_DONE);
01661 rc = CURLM_CALL_MULTI_PERFORM;
01662 break;
01663 }
01664 }
01665
01666
01667 multistate(data, CURLM_STATE_DOING);
01668 rc = CURLM_OK;
01669 }
01670
01671
01672 else if(data->easy_conn->bits.do_more) {
01673
01674
01675 multistate(data, CURLM_STATE_DO_MORE);
01676 rc = CURLM_OK;
01677 }
01678 else {
01679
01680 multistate(data, CURLM_STATE_DO_DONE);
01681 rc = CURLM_CALL_MULTI_PERFORM;
01682 }
01683 }
01684 else if((CURLE_SEND_ERROR == result) &&
01685 data->easy_conn->bits.reuse) {
01686
01687
01688
01689
01690
01691 char *newurl = NULL;
01692 followtype follow=FOLLOW_NONE;
01693 CURLcode drc;
01694 bool retry = FALSE;
01695
01696 drc = Curl_retry_request(data->easy_conn, &newurl);
01697 if(drc) {
01698
01699 result = drc;
01700 stream_error = TRUE;
01701 }
01702 else
01703 retry = (newurl)?TRUE:FALSE;
01704
01705 Curl_posttransfer(data);
01706 drc = multi_done(&data->easy_conn, result, FALSE);
01707
01708
01709
01710 if(retry) {
01711 if(!drc || (drc == CURLE_SEND_ERROR)) {
01712 follow = FOLLOW_RETRY;
01713 drc = Curl_follow(data, newurl, follow);
01714 if(!drc) {
01715 multistate(data, CURLM_STATE_CONNECT);
01716 rc = CURLM_CALL_MULTI_PERFORM;
01717 result = CURLE_OK;
01718 }
01719 else {
01720
01721 result = drc;
01722 free(newurl);
01723 }
01724 }
01725 else {
01726
01727 result = drc;
01728 free(newurl);
01729 }
01730 }
01731 else {
01732
01733 stream_error = TRUE;
01734 free(newurl);
01735 }
01736 }
01737 else {
01738
01739 Curl_posttransfer(data);
01740 if(data->easy_conn)
01741 multi_done(&data->easy_conn, result, FALSE);
01742 stream_error = TRUE;
01743 }
01744 }
01745 break;
01746
01747 case CURLM_STATE_DOING:
01748
01749 result = Curl_protocol_doing(data->easy_conn,
01750 &dophase_done);
01751 if(!result) {
01752 if(dophase_done) {
01753
01754 multistate(data, data->easy_conn->bits.do_more?
01755 CURLM_STATE_DO_MORE:
01756 CURLM_STATE_DO_DONE);
01757 rc = CURLM_CALL_MULTI_PERFORM;
01758 }
01759 }
01760 else {
01761
01762 Curl_posttransfer(data);
01763 multi_done(&data->easy_conn, result, FALSE);
01764 stream_error = TRUE;
01765 }
01766 break;
01767
01768 case CURLM_STATE_DO_MORE:
01769
01770
01771
01772 result = multi_do_more(data->easy_conn, &control);
01773
01774
01775
01776 if(!result) {
01777 if(control) {
01778
01779
01780 multistate(data, control==1?
01781 CURLM_STATE_DO_DONE:
01782 CURLM_STATE_DOING);
01783 rc = CURLM_CALL_MULTI_PERFORM;
01784 }
01785 else
01786
01787 rc = CURLM_OK;
01788 }
01789 else {
01790
01791 Curl_posttransfer(data);
01792 multi_done(&data->easy_conn, result, FALSE);
01793 stream_error = TRUE;
01794 }
01795 break;
01796
01797 case CURLM_STATE_DO_DONE:
01798
01799 Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
01800
01801 Curl_multi_process_pending_handles(multi);
01802
01803
01804
01805 if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
01806 (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
01807 multistate(data, CURLM_STATE_WAITPERFORM);
01808 else
01809 multistate(data, CURLM_STATE_DONE);
01810 rc = CURLM_CALL_MULTI_PERFORM;
01811 break;
01812
01813 case CURLM_STATE_WAITPERFORM:
01814
01815 if(Curl_pipeline_checkget_read(data, data->easy_conn)) {
01816
01817 multistate(data, CURLM_STATE_PERFORM);
01818 rc = CURLM_CALL_MULTI_PERFORM;
01819 }
01820 break;
01821
01822 case CURLM_STATE_TOOFAST:
01823
01824 if(Curl_pgrsUpdate(data->easy_conn))
01825 result = CURLE_ABORTED_BY_CALLBACK;
01826 else
01827 result = Curl_speedcheck(data, now);
01828
01829 if(( (data->set.max_send_speed == 0) ||
01830 (Curl_pgrsLimitWaitTime(data->progress.uploaded,
01831 data->progress.ul_limit_size,
01832 data->set.max_send_speed,
01833 data->progress.ul_limit_start,
01834 now) <= 0)) &&
01835 ( (data->set.max_recv_speed == 0) ||
01836 (Curl_pgrsLimitWaitTime(data->progress.downloaded,
01837 data->progress.dl_limit_size,
01838 data->set.max_recv_speed,
01839 data->progress.dl_limit_start,
01840 now) <= 0)))
01841 multistate(data, CURLM_STATE_PERFORM);
01842 break;
01843
01844 case CURLM_STATE_PERFORM:
01845 {
01846 char *newurl = NULL;
01847 bool retry = FALSE;
01848 bool comeback = FALSE;
01849
01850
01851 if(data->set.max_send_speed > 0) {
01852 timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
01853 data->progress.ul_limit_size,
01854 data->set.max_send_speed,
01855 data->progress.ul_limit_start,
01856 now);
01857 if(timeout_ms > 0) {
01858 multistate(data, CURLM_STATE_TOOFAST);
01859 Curl_expire_latest(data, timeout_ms);
01860 break;
01861 }
01862 }
01863
01864
01865 if(data->set.max_recv_speed > 0) {
01866 timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
01867 data->progress.dl_limit_size,
01868 data->set.max_recv_speed,
01869 data->progress.dl_limit_start,
01870 now);
01871 if(timeout_ms > 0) {
01872 multistate(data, CURLM_STATE_TOOFAST);
01873 Curl_expire_latest(data, timeout_ms);
01874 break;
01875 }
01876 }
01877
01878
01879 result = Curl_readwrite(data->easy_conn, data, &done, &comeback);
01880
01881 k = &data->req;
01882
01883 if(!(k->keepon & KEEP_RECV))
01884
01885 Curl_pipeline_leave_read(data->easy_conn);
01886
01887 if(!(k->keepon & KEEP_SEND))
01888
01889 Curl_pipeline_leave_write(data->easy_conn);
01890
01891 if(done || (result == CURLE_RECV_ERROR)) {
01892
01893
01894
01895
01896 CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
01897 if(!ret)
01898 retry = (newurl)?TRUE:FALSE;
01899
01900 if(retry) {
01901
01902
01903 result = CURLE_OK;
01904 done = TRUE;
01905 }
01906 }
01907
01908 if(result) {
01909
01910
01911
01912
01913
01914
01915
01916
01917 if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) &&
01918 result != CURLE_HTTP2_STREAM)
01919 streamclose(data->easy_conn, "Transfer returned error");
01920
01921 Curl_posttransfer(data);
01922 multi_done(&data->easy_conn, result, TRUE);
01923 }
01924 else if(done) {
01925 followtype follow=FOLLOW_NONE;
01926
01927
01928 Curl_posttransfer(data);
01929
01930
01931 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
01932
01933
01934 if(data->easy_conn->recv_pipe->head)
01935 Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 0);
01936
01937
01938 Curl_multi_process_pending_handles(multi);
01939
01940
01941
01942 if(data->req.newurl || retry) {
01943 if(!retry) {
01944
01945
01946 free(newurl);
01947 newurl = data->req.newurl;
01948 data->req.newurl = NULL;
01949 follow = FOLLOW_REDIR;
01950 }
01951 else
01952 follow = FOLLOW_RETRY;
01953 result = multi_done(&data->easy_conn, CURLE_OK, FALSE);
01954 if(!result) {
01955 result = Curl_follow(data, newurl, follow);
01956 if(!result) {
01957 multistate(data, CURLM_STATE_CONNECT);
01958 rc = CURLM_CALL_MULTI_PERFORM;
01959 newurl = NULL;
01960
01961
01962 }
01963 }
01964 }
01965 else {
01966
01967
01968
01969
01970 if(data->req.location) {
01971 free(newurl);
01972 newurl = data->req.location;
01973 data->req.location = NULL;
01974 result = Curl_follow(data, newurl, FOLLOW_FAKE);
01975 if(!result)
01976 newurl = NULL;
01977 else
01978 stream_error = TRUE;
01979 }
01980
01981 multistate(data, CURLM_STATE_DONE);
01982 rc = CURLM_CALL_MULTI_PERFORM;
01983 }
01984 }
01985 else if(comeback)
01986 rc = CURLM_CALL_MULTI_PERFORM;
01987
01988 free(newurl);
01989 break;
01990 }
01991
01992 case CURLM_STATE_DONE:
01993
01994 rc = CURLM_CALL_MULTI_PERFORM;
01995
01996 if(data->easy_conn) {
01997 CURLcode res;
01998
01999
02000 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
02001
02002 Curl_multi_process_pending_handles(multi);
02003
02004
02005 res = multi_done(&data->easy_conn, result, FALSE);
02006
02007
02008 if(!result)
02009 result = res;
02010
02011
02012
02013
02014
02015
02016
02017 if(data->easy_conn)
02018 data->easy_conn = NULL;
02019 }
02020
02021 if(data->set.wildcardmatch) {
02022 if(data->wildcard.state != CURLWC_DONE) {
02023
02024
02025 multistate(data, CURLM_STATE_INIT);
02026 break;
02027 }
02028 }
02029
02030
02031
02032 multistate(data, CURLM_STATE_COMPLETED);
02033 break;
02034
02035 case CURLM_STATE_COMPLETED:
02036
02037
02038
02039
02040
02041
02042
02043 data->easy_conn = NULL;
02044
02045 Curl_expire_clear(data);
02046 break;
02047
02048 case CURLM_STATE_MSGSENT:
02049 data->result = result;
02050 return CURLM_OK;
02051
02052 default:
02053 return CURLM_INTERNAL_ERROR;
02054 }
02055 statemachine_end:
02056
02057 if(data->mstate < CURLM_STATE_COMPLETED) {
02058 if(result) {
02059
02060
02061
02062
02063
02064
02065
02066
02067 data->state.pipe_broke = FALSE;
02068
02069
02070 Curl_multi_process_pending_handles(multi);
02071
02072 if(data->easy_conn) {
02073
02074 Curl_pipeline_leave_write(data->easy_conn);
02075 Curl_pipeline_leave_read(data->easy_conn);
02076 Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe);
02077 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
02078
02079 if(stream_error) {
02080
02081 bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
02082
02083 Curl_disconnect(data->easy_conn, dead_connection);
02084
02085
02086
02087
02088 data->easy_conn = NULL;
02089 }
02090 }
02091 else if(data->mstate == CURLM_STATE_CONNECT) {
02092
02093 (void)Curl_posttransfer(data);
02094 }
02095
02096 multistate(data, CURLM_STATE_COMPLETED);
02097 }
02098
02099 else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
02100
02101
02102 result = CURLE_ABORTED_BY_CALLBACK;
02103 streamclose(data->easy_conn, "Aborted by callback");
02104
02105
02106 multistate(data, (data->mstate < CURLM_STATE_DONE)?
02107 CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
02108 rc = CURLM_CALL_MULTI_PERFORM;
02109 }
02110 }
02111
02112 if(CURLM_STATE_COMPLETED == data->mstate) {
02113
02114 msg = &data->msg;
02115
02116 msg->extmsg.msg = CURLMSG_DONE;
02117 msg->extmsg.easy_handle = data;
02118 msg->extmsg.data.result = result;
02119
02120 rc = multi_addmsg(multi, msg);
02121
02122 multistate(data, CURLM_STATE_MSGSENT);
02123 }
02124 } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
02125
02126 data->result = result;
02127
02128
02129 return rc;
02130 }
02131
02132
02133 CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
02134 {
02135 struct Curl_easy *data;
02136 CURLMcode returncode=CURLM_OK;
02137 struct Curl_tree *t;
02138 struct timeval now = Curl_tvnow();
02139
02140 if(!GOOD_MULTI_HANDLE(multi))
02141 return CURLM_BAD_HANDLE;
02142
02143 data=multi->easyp;
02144 while(data) {
02145 CURLMcode result;
02146 SIGPIPE_VARIABLE(pipe_st);
02147
02148 sigpipe_ignore(data, &pipe_st);
02149 result = multi_runsingle(multi, now, data);
02150 sigpipe_restore(&pipe_st);
02151
02152 if(result)
02153 returncode = result;
02154
02155 data = data->next;
02156 }
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168 do {
02169 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
02170 if(t)
02171
02172 (void)add_next_timeout(now, multi, t->payload);
02173
02174 } while(t);
02175
02176 *running_handles = multi->num_alive;
02177
02178 if(CURLM_OK >= returncode)
02179 update_timer(multi);
02180
02181 return returncode;
02182 }
02183
02184 static void close_all_connections(struct Curl_multi *multi)
02185 {
02186 struct connectdata *conn;
02187
02188 conn = Curl_conncache_find_first_connection(&multi->conn_cache);
02189 while(conn) {
02190 SIGPIPE_VARIABLE(pipe_st);
02191 conn->data = multi->closure_handle;
02192
02193 sigpipe_ignore(conn->data, &pipe_st);
02194 conn->data->easy_conn = NULL;
02195
02196
02197 connclose(conn, "kill all");
02198 (void)Curl_disconnect(conn, FALSE);
02199 sigpipe_restore(&pipe_st);
02200
02201 conn = Curl_conncache_find_first_connection(&multi->conn_cache);
02202 }
02203 }
02204
02205 CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
02206 {
02207 struct Curl_easy *data;
02208 struct Curl_easy *nextdata;
02209
02210 if(GOOD_MULTI_HANDLE(multi)) {
02211 bool restore_pipe = FALSE;
02212 SIGPIPE_VARIABLE(pipe_st);
02213
02214 multi->type = 0;
02215
02216
02217 close_all_connections(multi);
02218
02219 if(multi->closure_handle) {
02220 sigpipe_ignore(multi->closure_handle, &pipe_st);
02221 restore_pipe = TRUE;
02222
02223 multi->closure_handle->dns.hostcache = &multi->hostcache;
02224 Curl_hostcache_clean(multi->closure_handle,
02225 multi->closure_handle->dns.hostcache);
02226
02227 Curl_close(multi->closure_handle);
02228 }
02229
02230 Curl_hash_destroy(&multi->sockhash);
02231 Curl_conncache_destroy(&multi->conn_cache);
02232 Curl_llist_destroy(multi->msglist, NULL);
02233 Curl_llist_destroy(multi->pending, NULL);
02234
02235
02236 data = multi->easyp;
02237 while(data) {
02238 nextdata=data->next;
02239 if(data->dns.hostcachetype == HCACHE_MULTI) {
02240
02241 Curl_hostcache_clean(data, data->dns.hostcache);
02242 data->dns.hostcache = NULL;
02243 data->dns.hostcachetype = HCACHE_NONE;
02244 }
02245
02246
02247 data->state.conn_cache = NULL;
02248 data->multi = NULL;
02249
02250 data = nextdata;
02251 }
02252
02253 Curl_hash_destroy(&multi->hostcache);
02254
02255
02256 Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
02257 Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
02258
02259 free(multi);
02260 if(restore_pipe)
02261 sigpipe_restore(&pipe_st);
02262
02263 return CURLM_OK;
02264 }
02265 else
02266 return CURLM_BAD_HANDLE;
02267 }
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279 CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
02280 {
02281 struct Curl_message *msg;
02282
02283 *msgs_in_queue = 0;
02284
02285 if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) {
02286
02287 struct curl_llist_element *e;
02288
02289
02290 e = multi->msglist->head;
02291
02292 msg = e->ptr;
02293
02294
02295 Curl_llist_remove(multi->msglist, e, NULL);
02296
02297 *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist));
02298
02299 return &msg->extmsg;
02300 }
02301 else
02302 return NULL;
02303 }
02304
02305
02306
02307
02308
02309
02310 static void singlesocket(struct Curl_multi *multi,
02311 struct Curl_easy *data)
02312 {
02313 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
02314 int i;
02315 struct Curl_sh_entry *entry;
02316 curl_socket_t s;
02317 int num;
02318 unsigned int curraction;
02319
02320 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
02321 socks[i] = CURL_SOCKET_BAD;
02322
02323
02324
02325 curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE);
02326
02327
02328
02329
02330
02331
02332 for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
02333 (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
02334 i++) {
02335 int action = CURL_POLL_NONE;
02336
02337 s = socks[i];
02338
02339
02340 entry = sh_getentry(&multi->sockhash, s);
02341
02342 if(curraction & GETSOCK_READSOCK(i))
02343 action |= CURL_POLL_IN;
02344 if(curraction & GETSOCK_WRITESOCK(i))
02345 action |= CURL_POLL_OUT;
02346
02347 if(entry) {
02348
02349 if(entry->action == action)
02350
02351 continue;
02352 }
02353 else {
02354
02355 entry = sh_addentry(&multi->sockhash, s, data);
02356 if(!entry)
02357
02358 return;
02359 }
02360
02361
02362 if(multi->socket_cb)
02363 multi->socket_cb(data,
02364 s,
02365 action,
02366 multi->socket_userp,
02367 entry->socketp);
02368
02369 entry->action = action;
02370 }
02371
02372 num = i;
02373
02374
02375
02376 for(i=0; i< data->numsocks; i++) {
02377 int j;
02378 s = data->sockets[i];
02379 for(j=0; j<num; j++) {
02380 if(s == socks[j]) {
02381
02382 s = CURL_SOCKET_BAD;
02383 break;
02384 }
02385 }
02386
02387 entry = sh_getentry(&multi->sockhash, s);
02388 if(entry) {
02389
02390 bool remove_sock_from_hash = TRUE;
02391
02392
02393
02394
02395 struct connectdata *easy_conn = data->easy_conn;
02396 if(easy_conn) {
02397 if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
02398
02399 remove_sock_from_hash = FALSE;
02400
02401
02402
02403
02404 if(entry->easy == data) {
02405 if(Curl_recvpipe_head(data, easy_conn))
02406 entry->easy = easy_conn->recv_pipe->head->next->ptr;
02407 else
02408 entry->easy = easy_conn->recv_pipe->head->ptr;
02409 }
02410 }
02411 if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) {
02412
02413 remove_sock_from_hash = FALSE;
02414
02415
02416
02417
02418 if(entry->easy == data) {
02419 if(Curl_sendpipe_head(data, easy_conn))
02420 entry->easy = easy_conn->send_pipe->head->next->ptr;
02421 else
02422 entry->easy = easy_conn->send_pipe->head->ptr;
02423 }
02424 }
02425
02426
02427
02428
02429 }
02430
02431 if(remove_sock_from_hash) {
02432
02433 if(multi->socket_cb)
02434 multi->socket_cb(data,
02435 s,
02436 CURL_POLL_REMOVE,
02437 multi->socket_userp,
02438 entry->socketp);
02439 sh_delentry(&multi->sockhash, s);
02440 }
02441 }
02442 }
02443
02444 memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
02445 data->numsocks = num;
02446 }
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458 void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
02459 {
02460 struct Curl_multi *multi = conn->data->multi;
02461 if(multi) {
02462
02463
02464 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
02465
02466 if(entry) {
02467 if(multi->socket_cb)
02468 multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
02469 multi->socket_userp,
02470 entry->socketp);
02471
02472
02473 sh_delentry(&multi->sockhash, s);
02474 }
02475 }
02476 }
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492 static CURLMcode add_next_timeout(struct timeval now,
02493 struct Curl_multi *multi,
02494 struct Curl_easy *d)
02495 {
02496 struct timeval *tv = &d->state.expiretime;
02497 struct curl_llist *list = d->state.timeoutlist;
02498 struct curl_llist_element *e;
02499
02500
02501
02502
02503 for(e = list->head; e;) {
02504 struct curl_llist_element *n = e->next;
02505 time_t diff = curlx_tvdiff(*(struct timeval *)e->ptr, now);
02506 if(diff <= 0)
02507
02508 Curl_llist_remove(list, e, NULL);
02509 else
02510
02511 break;
02512 e = n;
02513 }
02514 e = list->head;
02515 if(!e) {
02516
02517
02518 tv->tv_sec = 0;
02519 tv->tv_usec = 0;
02520 }
02521 else {
02522
02523 memcpy(tv, e->ptr, sizeof(*tv));
02524
02525
02526 Curl_llist_remove(list, e, NULL);
02527
02528
02529 multi->timetree = Curl_splayinsert(*tv, multi->timetree,
02530 &d->state.timenode);
02531 }
02532 return CURLM_OK;
02533 }
02534
02535 static CURLMcode multi_socket(struct Curl_multi *multi,
02536 bool checkall,
02537 curl_socket_t s,
02538 int ev_bitmask,
02539 int *running_handles)
02540 {
02541 CURLMcode result = CURLM_OK;
02542 struct Curl_easy *data = NULL;
02543 struct Curl_tree *t;
02544 struct timeval now = Curl_tvnow();
02545
02546 if(checkall) {
02547
02548 result = curl_multi_perform(multi, running_handles);
02549
02550
02551
02552 if(result != CURLM_BAD_HANDLE) {
02553 data=multi->easyp;
02554 while(data) {
02555 singlesocket(multi, data);
02556 data = data->next;
02557 }
02558 }
02559
02560
02561 return result;
02562 }
02563 else if(s != CURL_SOCKET_TIMEOUT) {
02564
02565 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
02566
02567 if(!entry)
02568
02569
02570
02571
02572
02573 ;
02574 else {
02575 SIGPIPE_VARIABLE(pipe_st);
02576
02577 data = entry->easy;
02578
02579 if(data->magic != CURLEASY_MAGIC_NUMBER)
02580
02581 return CURLM_INTERNAL_ERROR;
02582
02583
02584
02585
02586 if(data->easy_conn) {
02587 if((ev_bitmask & CURL_POLL_OUT) &&
02588 data->easy_conn->send_pipe &&
02589 data->easy_conn->send_pipe->head)
02590 data = data->easy_conn->send_pipe->head->ptr;
02591 else if((ev_bitmask & CURL_POLL_IN) &&
02592 data->easy_conn->recv_pipe &&
02593 data->easy_conn->recv_pipe->head)
02594 data = data->easy_conn->recv_pipe->head->ptr;
02595 }
02596
02597 if(data->easy_conn &&
02598 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
02599
02600 data->easy_conn->cselect_bits = ev_bitmask;
02601
02602 sigpipe_ignore(data, &pipe_st);
02603 result = multi_runsingle(multi, now, data);
02604 sigpipe_restore(&pipe_st);
02605
02606 if(data->easy_conn &&
02607 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
02608
02609 data->easy_conn->cselect_bits = 0;
02610
02611 if(CURLM_OK >= result)
02612
02613
02614 singlesocket(multi, data);
02615
02616
02617
02618
02619
02620 data = NULL;
02621
02622 now = Curl_tvnow();
02623
02624 }
02625 }
02626 else {
02627
02628
02629
02630
02631 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
02632 }
02633
02634
02635
02636
02637
02638
02639 do {
02640
02641 if(data) {
02642 SIGPIPE_VARIABLE(pipe_st);
02643
02644 sigpipe_ignore(data, &pipe_st);
02645 result = multi_runsingle(multi, now, data);
02646 sigpipe_restore(&pipe_st);
02647
02648 if(CURLM_OK >= result)
02649
02650
02651 singlesocket(multi, data);
02652 }
02653
02654
02655
02656
02657 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
02658 if(t) {
02659 data = t->payload;
02660 (void)add_next_timeout(now, multi, t->payload);
02661 }
02662
02663 } while(t);
02664
02665 *running_handles = multi->num_alive;
02666 return result;
02667 }
02668
02669 #undef curl_multi_setopt
02670 CURLMcode curl_multi_setopt(struct Curl_multi *multi,
02671 CURLMoption option, ...)
02672 {
02673 CURLMcode res = CURLM_OK;
02674 va_list param;
02675
02676 if(!GOOD_MULTI_HANDLE(multi))
02677 return CURLM_BAD_HANDLE;
02678
02679 va_start(param, option);
02680
02681 switch(option) {
02682 case CURLMOPT_SOCKETFUNCTION:
02683 multi->socket_cb = va_arg(param, curl_socket_callback);
02684 break;
02685 case CURLMOPT_SOCKETDATA:
02686 multi->socket_userp = va_arg(param, void *);
02687 break;
02688 case CURLMOPT_PUSHFUNCTION:
02689 multi->push_cb = va_arg(param, curl_push_callback);
02690 break;
02691 case CURLMOPT_PUSHDATA:
02692 multi->push_userp = va_arg(param, void *);
02693 break;
02694 case CURLMOPT_PIPELINING:
02695 multi->pipelining = va_arg(param, long);
02696 break;
02697 case CURLMOPT_TIMERFUNCTION:
02698 multi->timer_cb = va_arg(param, curl_multi_timer_callback);
02699 break;
02700 case CURLMOPT_TIMERDATA:
02701 multi->timer_userp = va_arg(param, void *);
02702 break;
02703 case CURLMOPT_MAXCONNECTS:
02704 multi->maxconnects = va_arg(param, long);
02705 break;
02706 case CURLMOPT_MAX_HOST_CONNECTIONS:
02707 multi->max_host_connections = va_arg(param, long);
02708 break;
02709 case CURLMOPT_MAX_PIPELINE_LENGTH:
02710 multi->max_pipeline_length = va_arg(param, long);
02711 break;
02712 case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
02713 multi->content_length_penalty_size = va_arg(param, long);
02714 break;
02715 case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
02716 multi->chunk_length_penalty_size = va_arg(param, long);
02717 break;
02718 case CURLMOPT_PIPELINING_SITE_BL:
02719 res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
02720 &multi->pipelining_site_bl);
02721 break;
02722 case CURLMOPT_PIPELINING_SERVER_BL:
02723 res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
02724 &multi->pipelining_server_bl);
02725 break;
02726 case CURLMOPT_MAX_TOTAL_CONNECTIONS:
02727 multi->max_total_connections = va_arg(param, long);
02728 break;
02729 default:
02730 res = CURLM_UNKNOWN_OPTION;
02731 break;
02732 }
02733 va_end(param);
02734 return res;
02735 }
02736
02737
02738 #undef curl_multi_socket
02739
02740 CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
02741 int *running_handles)
02742 {
02743 CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles);
02744 if(CURLM_OK >= result)
02745 update_timer(multi);
02746 return result;
02747 }
02748
02749 CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
02750 int ev_bitmask, int *running_handles)
02751 {
02752 CURLMcode result = multi_socket(multi, FALSE, s,
02753 ev_bitmask, running_handles);
02754 if(CURLM_OK >= result)
02755 update_timer(multi);
02756 return result;
02757 }
02758
02759 CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
02760
02761 {
02762 CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0,
02763 running_handles);
02764 if(CURLM_OK >= result)
02765 update_timer(multi);
02766 return result;
02767 }
02768
02769 static CURLMcode multi_timeout(struct Curl_multi *multi,
02770 long *timeout_ms)
02771 {
02772 static struct timeval tv_zero = {0, 0};
02773
02774 if(multi->timetree) {
02775
02776 struct timeval now = Curl_tvnow();
02777
02778
02779 multi->timetree = Curl_splay(tv_zero, multi->timetree);
02780
02781 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
02782
02783 *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now);
02784 if(!*timeout_ms)
02785
02786
02787
02788
02789
02790
02791
02792 *timeout_ms=1;
02793 }
02794 else
02795
02796 *timeout_ms = 0;
02797 }
02798 else
02799 *timeout_ms = -1;
02800
02801 return CURLM_OK;
02802 }
02803
02804 CURLMcode curl_multi_timeout(struct Curl_multi *multi,
02805 long *timeout_ms)
02806 {
02807
02808 if(!GOOD_MULTI_HANDLE(multi))
02809 return CURLM_BAD_HANDLE;
02810
02811 return multi_timeout(multi, timeout_ms);
02812 }
02813
02814
02815
02816
02817
02818 static int update_timer(struct Curl_multi *multi)
02819 {
02820 long timeout_ms;
02821
02822 if(!multi->timer_cb)
02823 return 0;
02824 if(multi_timeout(multi, &timeout_ms)) {
02825 return -1;
02826 }
02827 if(timeout_ms < 0) {
02828 static const struct timeval none={0, 0};
02829 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
02830 multi->timer_lastcall = none;
02831
02832
02833 return multi->timer_cb(multi, -1, multi->timer_userp);
02834 }
02835 return 0;
02836 }
02837
02838
02839
02840
02841
02842 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
02843 return 0;
02844
02845 multi->timer_lastcall = multi->timetree->key;
02846
02847 return multi->timer_cb(multi, timeout_ms, multi->timer_userp);
02848 }
02849
02850
02851
02852
02853
02854
02855
02856 static void multi_freetimeout(void *user, void *entryptr)
02857 {
02858 (void)user;
02859
02860
02861 free(entryptr);
02862 }
02863
02864
02865
02866
02867
02868
02869
02870
02871 static CURLMcode
02872 multi_addtimeout(struct curl_llist *timeoutlist,
02873 struct timeval *stamp)
02874 {
02875 struct curl_llist_element *e;
02876 struct timeval *timedup;
02877 struct curl_llist_element *prev = NULL;
02878
02879 timedup = malloc(sizeof(*timedup));
02880 if(!timedup)
02881 return CURLM_OUT_OF_MEMORY;
02882
02883
02884 memcpy(timedup, stamp, sizeof(*timedup));
02885
02886 if(Curl_llist_count(timeoutlist)) {
02887
02888 for(e = timeoutlist->head; e; e = e->next) {
02889 struct timeval *checktime = e->ptr;
02890 time_t diff = curlx_tvdiff(*checktime, *timedup);
02891 if(diff > 0)
02892 break;
02893 prev = e;
02894 }
02895
02896 }
02897
02898
02899
02900 if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) {
02901 free(timedup);
02902 return CURLM_OUT_OF_MEMORY;
02903 }
02904
02905 return CURLM_OK;
02906 }
02907
02908
02909
02910
02911
02912
02913
02914
02915
02916
02917 void Curl_expire(struct Curl_easy *data, time_t milli)
02918 {
02919 struct Curl_multi *multi = data->multi;
02920 struct timeval *nowp = &data->state.expiretime;
02921 int rc;
02922 struct timeval set;
02923
02924
02925
02926 if(!multi)
02927 return;
02928
02929 set = Curl_tvnow();
02930 set.tv_sec += (long)(milli/1000);
02931 set.tv_usec += (milli%1000)*1000;
02932
02933 if(set.tv_usec >= 1000000) {
02934 set.tv_sec++;
02935 set.tv_usec -= 1000000;
02936 }
02937
02938 if(nowp->tv_sec || nowp->tv_usec) {
02939
02940
02941
02942 time_t diff = curlx_tvdiff(set, *nowp);
02943 if(diff > 0) {
02944
02945
02946 multi_addtimeout(data->state.timeoutlist, &set);
02947 return;
02948 }
02949
02950
02951
02952 multi_addtimeout(data->state.timeoutlist, nowp);
02953
02954
02955
02956 rc = Curl_splayremovebyaddr(multi->timetree,
02957 &data->state.timenode,
02958 &multi->timetree);
02959 if(rc)
02960 infof(data, "Internal error removing splay node = %d\n", rc);
02961 }
02962
02963 *nowp = set;
02964 data->state.timenode.payload = data;
02965 multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
02966 &data->state.timenode);
02967 }
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980 void Curl_expire_latest(struct Curl_easy *data, time_t milli)
02981 {
02982 struct timeval *expire = &data->state.expiretime;
02983
02984 struct timeval set;
02985
02986 set = Curl_tvnow();
02987 set.tv_sec += (long)(milli / 1000);
02988 set.tv_usec += (milli % 1000) * 1000;
02989
02990 if(set.tv_usec >= 1000000) {
02991 set.tv_sec++;
02992 set.tv_usec -= 1000000;
02993 }
02994
02995 if(expire->tv_sec || expire->tv_usec) {
02996
02997
02998
02999 time_t diff = curlx_tvdiff(set, *expire);
03000 if(diff > 0)
03001
03002 return;
03003 }
03004
03005
03006 Curl_expire(data, milli);
03007 }
03008
03009
03010
03011
03012
03013
03014
03015 void Curl_expire_clear(struct Curl_easy *data)
03016 {
03017 struct Curl_multi *multi = data->multi;
03018 struct timeval *nowp = &data->state.expiretime;
03019 int rc;
03020
03021
03022
03023 if(!multi)
03024 return;
03025
03026 if(nowp->tv_sec || nowp->tv_usec) {
03027
03028
03029 struct curl_llist *list = data->state.timeoutlist;
03030
03031 rc = Curl_splayremovebyaddr(multi->timetree,
03032 &data->state.timenode,
03033 &multi->timetree);
03034 if(rc)
03035 infof(data, "Internal error clearing splay node = %d\n", rc);
03036
03037
03038 while(list->size > 0)
03039 Curl_llist_remove(list, list->tail, NULL);
03040
03041 #ifdef DEBUGBUILD
03042 infof(data, "Expire cleared\n");
03043 #endif
03044 nowp->tv_sec = 0;
03045 nowp->tv_usec = 0;
03046 }
03047 }
03048
03049
03050
03051
03052 CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
03053 void *hashp)
03054 {
03055 struct Curl_sh_entry *there = NULL;
03056
03057 there = sh_getentry(&multi->sockhash, s);
03058
03059 if(!there)
03060 return CURLM_BAD_SOCKET;
03061
03062 there->socketp = hashp;
03063
03064 return CURLM_OK;
03065 }
03066
03067 size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
03068 {
03069 return multi ? multi->max_host_connections : 0;
03070 }
03071
03072 size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
03073 {
03074 return multi ? multi->max_total_connections : 0;
03075 }
03076
03077 curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
03078 {
03079 return multi ? multi->content_length_penalty_size : 0;
03080 }
03081
03082 curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
03083 {
03084 return multi ? multi->chunk_length_penalty_size : 0;
03085 }
03086
03087 struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
03088 {
03089 return multi->pipelining_site_bl;
03090 }
03091
03092 struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
03093 {
03094 return multi->pipelining_server_bl;
03095 }
03096
03097 void Curl_multi_process_pending_handles(struct Curl_multi *multi)
03098 {
03099 struct curl_llist_element *e = multi->pending->head;
03100
03101 while(e) {
03102 struct Curl_easy *data = e->ptr;
03103 struct curl_llist_element *next = e->next;
03104
03105 if(data->mstate == CURLM_STATE_CONNECT_PEND) {
03106 multistate(data, CURLM_STATE_CONNECT);
03107
03108
03109 Curl_llist_remove(multi->pending, e, NULL);
03110
03111
03112 Curl_expire_latest(data, 0);
03113 }
03114
03115 e = next;
03116 }
03117 }
03118
03119 #ifdef DEBUGBUILD
03120 void Curl_multi_dump(struct Curl_multi *multi)
03121 {
03122 struct Curl_easy *data;
03123 int i;
03124 fprintf(stderr, "* Multi status: %d handles, %d alive\n",
03125 multi->num_easy, multi->num_alive);
03126 for(data=multi->easyp; data; data = data->next) {
03127 if(data->mstate < CURLM_STATE_COMPLETED) {
03128
03129 fprintf(stderr, "handle %p, state %s, %d sockets\n",
03130 (void *)data,
03131 statename[data->mstate], data->numsocks);
03132 for(i=0; i < data->numsocks; i++) {
03133 curl_socket_t s = data->sockets[i];
03134 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
03135
03136 fprintf(stderr, "%d ", (int)s);
03137 if(!entry) {
03138 fprintf(stderr, "INTERNAL CONFUSION\n");
03139 continue;
03140 }
03141 fprintf(stderr, "[%s %s] ",
03142 entry->action&CURL_POLL_IN?"RECVING":"",
03143 entry->action&CURL_POLL_OUT?"SENDING":"");
03144 }
03145 if(data->numsocks)
03146 fprintf(stderr, "\n");
03147 }
03148 }
03149 }
03150 #endif