175
* We add one of these structs to the sockhash for a particular socket
178
struct Curl_sh_entry {
179
struct SessionHandle *easy;
182
int action; /* what action READ/WRITE this socket waits for */
183
void *userp; /* settable by users (not yet decided exactly how) */
185
/* bits for 'action' having no bits means this socket is not expecting any
190
/* make sure this socket is present in the hash for this handle */
191
static int sh_addentry(struct curl_hash *sh,
193
struct SessionHandle *data)
195
struct Curl_sh_entry *there =
196
Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
197
struct Curl_sh_entry *check;
200
/* it is present, return fine */
203
/* not present, add it */
204
check = calloc(sizeof(struct Curl_sh_entry), 1);
206
return 1; /* major failure */
209
/* make/add new hash entry */
210
if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check))
211
return 1; /* major failure */
213
return 0; /* things are good in sockhash land */
217
/* delete the given socket + handle from the hash */
218
static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
220
struct Curl_sh_entry *there =
221
Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
224
/* this socket is in the hash */
225
/* We remove the hash entry. (This'll end up in a call to
227
Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
232
* free a sockhash entry
234
static void sh_freeentry(void *freethis)
236
struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
242
* sh_init() creates a new socket hash and returns the handle for it.
244
* Quote from README.multi_socket:
246
* "Some tests at 7000 and 9000 connections showed that the socket hash lookup
247
* is somewhat of a bottle neck. Its current implementation may be a bit too
248
* limiting. It simply has a fixed-size array, and on each entry in the array
249
* it has a linked list with entries. So the hash only checks which list to
250
* scan through. The code I had used so for used a list with merely 7 slots
251
* (as that is what the DNS hash uses) but with 7000 connections that would
252
* make an average of 1000 nodes in each list to run through. I upped that to
253
* 97 slots (I believe a prime is suitable) and noticed a significant speed
254
* increase. I need to reconsider the hash implementation or use a rather
255
* large default value like this. At 9000 connections I was still below 10us
259
static struct curl_hash *sh_init(void)
261
return Curl_hash_alloc(97, sh_freeentry);
146
264
CURLM *curl_multi_init(void)
148
struct Curl_multi *multi;
150
multi = (void *)malloc(sizeof(struct Curl_multi));
153
memset(multi, 0, sizeof(struct Curl_multi));
154
multi->type = CURL_MULTI_HANDLE;
266
struct Curl_multi *multi = (void *)calloc(sizeof(struct Curl_multi), 1);
271
multi->type = CURL_MULTI_HANDLE;
159
273
multi->hostcache = Curl_mk_dnscache();
160
274
if(!multi->hostcache) {
161
275
/* failure, free mem and bail out */
280
multi->sockhash = sh_init();
281
if(!multi->sockhash) {
282
/* failure, free mem and bail out */
283
Curl_hash_destroy(multi->hostcache);
165
288
return (CURLM *) multi;
276
474
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
277
475
struct Curl_one_easy *easy;
278
476
int this_max_fd=-1;
477
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
480
(void)exc_fd_set; /* not used */
280
482
if(!GOOD_MULTI_HANDLE(multi))
281
483
return CURLM_BAD_HANDLE;
283
*max_fd = -1; /* so far none! */
285
485
easy=multi->easy.next;
287
switch(easy->state) {
290
case CURLM_STATE_WAITRESOLVE:
291
/* waiting for a resolve to complete */
292
Curl_resolv_fdset(easy->easy_conn, read_fd_set, write_fd_set,
294
if(this_max_fd > *max_fd)
295
*max_fd = this_max_fd;
298
case CURLM_STATE_PROTOCONNECT:
299
Curl_protocol_fdset(easy->easy_conn, read_fd_set, write_fd_set,
301
if(this_max_fd > *max_fd)
302
*max_fd = this_max_fd;
305
case CURLM_STATE_DOING:
306
Curl_doing_fdset(easy->easy_conn, read_fd_set, write_fd_set,
308
if(this_max_fd > *max_fd)
309
*max_fd = this_max_fd;
312
case CURLM_STATE_WAITCONNECT:
313
case CURLM_STATE_DO_MORE:
315
/* when we're waiting for a connect, we wait for the socket to
317
struct connectdata *conn = easy->easy_conn;
318
curl_socket_t sockfd;
320
if(CURLM_STATE_WAITCONNECT == easy->state) {
321
sockfd = conn->sock[FIRSTSOCKET];
322
FD_SET(sockfd, write_fd_set);
325
/* When in DO_MORE state, we could be either waiting for us
326
to connect to a remote site, or we could wait for that site
327
to connect to us. It makes a difference in the way: if we
328
connect to the site we wait for the socket to become writable, if
329
the site connects to us we wait for it to become readable */
330
sockfd = conn->sock[SECONDARYSOCKET];
331
FD_SET(sockfd, write_fd_set);
334
if((int)sockfd > *max_fd)
335
*max_fd = (int)sockfd;
338
case CURLM_STATE_PERFORM:
339
/* This should have a set of file descriptors for us to set. */
340
/* after the transfer is done, go DONE */
342
Curl_single_fdset(easy->easy_conn,
343
read_fd_set, write_fd_set,
344
exc_fd_set, &this_max_fd);
346
/* remember the maximum file descriptor */
347
if(this_max_fd > *max_fd)
348
*max_fd = this_max_fd;
487
bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
489
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
490
curl_socket_t s = CURL_SOCKET_BAD;
492
if(bitmap & GETSOCK_READSOCK(i)) {
493
FD_SET(sockbunch[i], read_fd_set);
496
if(bitmap & GETSOCK_WRITESOCK(i)) {
497
FD_SET(sockbunch[i], write_fd_set);
500
if(s == CURL_SOCKET_BAD)
501
/* this socket is unused, break out of loop */
504
if(s > (curl_socket_t)this_max_fd)
505
this_max_fd = (int)s;
352
509
easy = easy->next; /* check next handle */
512
*max_fd = this_max_fd;
358
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
517
static CURLMcode multi_runsingle(struct Curl_multi *multi,
518
struct Curl_one_easy *easy,
519
int *running_handles)
360
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
361
struct Curl_one_easy *easy;
363
CURLMcode result=CURLM_OK;
364
521
struct Curl_message *msg = NULL;
367
524
bool protocol_connect;
368
525
bool dophase_done;
370
*running_handles = 0; /* bump this once for every living handle */
372
if(!GOOD_MULTI_HANDLE(multi))
373
return CURLM_BAD_HANDLE;
375
easy=multi->easy.next;
378
if (CURLM_STATE_WAITCONNECT <= easy->state &&
379
easy->state <= CURLM_STATE_DO &&
380
easy->easy_handle->change.url_changed) {
382
Curl_posttransfer(easy->easy_handle);
384
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
385
if(CURLE_OK == easy->result) {
386
gotourl = strdup(easy->easy_handle->change.url);
388
easy->easy_handle->change.url_changed = FALSE;
389
easy->result = Curl_follow(easy->easy_handle, gotourl, FALSE);
390
if(CURLE_OK == easy->result)
391
multistate(easy, CURLM_STATE_CONNECT);
396
easy->result = CURLE_OUT_OF_MEMORY;
397
multistate(easy, CURLM_STATE_COMPLETED);
403
easy->easy_handle->change.url_changed = FALSE;
405
switch(easy->state) {
406
case CURLM_STATE_INIT:
407
/* init this transfer. */
408
easy->result=Curl_pretransfer(easy->easy_handle);
410
if(CURLE_OK == easy->result) {
411
/* after init, go CONNECT */
412
multistate(easy, CURLM_STATE_CONNECT);
527
CURLMcode result = CURLM_OK;
530
if (CURLM_STATE_WAITCONNECT <= easy->state &&
531
easy->state <= CURLM_STATE_DO &&
532
easy->easy_handle->change.url_changed) {
534
Curl_posttransfer(easy->easy_handle);
536
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
537
if(CURLE_OK == easy->result) {
538
gotourl = strdup(easy->easy_handle->change.url);
540
easy->easy_handle->change.url_changed = FALSE;
541
easy->result = Curl_follow(easy->easy_handle, gotourl, FALSE);
542
if(CURLE_OK == easy->result)
543
multistate(easy, CURLM_STATE_CONNECT);
548
easy->result = CURLE_OUT_OF_MEMORY;
549
multistate(easy, CURLM_STATE_COMPLETED);
555
easy->easy_handle->change.url_changed = FALSE;
557
switch(easy->state) {
558
case CURLM_STATE_INIT:
559
/* init this transfer. */
560
easy->result=Curl_pretransfer(easy->easy_handle);
562
if(CURLE_OK == easy->result) {
563
/* after init, go CONNECT */
564
multistate(easy, CURLM_STATE_CONNECT);
565
result = CURLM_CALL_MULTI_PERFORM;
567
easy->easy_handle->state.used_interface = Curl_if_multi;
571
case CURLM_STATE_CONNECT:
572
/* Connect. We get a connection identifier filled in. */
573
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
574
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
575
&async, &protocol_connect);
577
if(CURLE_OK == easy->result) {
579
/* We're now waiting for an asynchronous name lookup */
580
multistate(easy, CURLM_STATE_WAITRESOLVE);
582
/* after the connect has been sent off, go WAITCONNECT unless the
583
protocol connect is already done and we can go directly to
413
585
result = CURLM_CALL_MULTI_PERFORM;
415
easy->easy_handle->state.used_interface = Curl_if_multi;
419
case CURLM_STATE_CONNECT:
420
/* Connect. We get a connection identifier filled in. */
421
Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
422
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
423
&async, &protocol_connect);
425
if(CURLE_OK == easy->result) {
427
/* We're now waiting for an asynchronous name lookup */
428
multistate(easy, CURLM_STATE_WAITRESOLVE);
430
/* after the connect has been sent off, go WAITCONNECT unless the
431
protocol connect is already done and we can go directly to
433
result = CURLM_CALL_MULTI_PERFORM;
436
multistate(easy, CURLM_STATE_DO);
438
multistate(easy, CURLM_STATE_WAITCONNECT);
443
case CURLM_STATE_WAITRESOLVE:
444
/* awaiting an asynch name resolve to complete */
446
struct Curl_dns_entry *dns = NULL;
448
/* check if we have the name resolved by now */
449
easy->result = Curl_is_resolved(easy->easy_conn, &dns);
452
/* Perform the next step in the connection phase, and then move on
453
to the WAITCONNECT state */
454
easy->result = Curl_async_resolved(easy->easy_conn,
588
multistate(easy, CURLM_STATE_DO);
590
multistate(easy, CURLM_STATE_WAITCONNECT);
595
case CURLM_STATE_WAITRESOLVE:
596
/* awaiting an asynch name resolve to complete */
598
struct Curl_dns_entry *dns = NULL;
600
/* check if we have the name resolved by now */
601
easy->result = Curl_is_resolved(easy->easy_conn, &dns);
604
/* Perform the next step in the connection phase, and then move on
605
to the WAITCONNECT state */
606
easy->result = Curl_async_resolved(easy->easy_conn,
609
if(CURLE_OK != easy->result)
610
/* if Curl_async_resolved() returns failure, the connection struct
611
is already freed and gone */
612
easy->easy_conn = NULL; /* no more connection */
614
/* FIX: what if protocol_connect is TRUE here?! */
615
multistate(easy, CURLM_STATE_WAITCONNECT);
619
if(CURLE_OK != easy->result) {
620
/* failure detected */
621
Curl_disconnect(easy->easy_conn); /* disconnect properly */
622
easy->easy_conn = NULL; /* no more connection */
628
case CURLM_STATE_WAITCONNECT:
629
/* awaiting a completion of an asynch connect */
630
easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
633
easy->result = Curl_protocol_connect(easy->easy_conn,
455
634
&protocol_connect);
457
if(CURLE_OK != easy->result)
458
/* if Curl_async_resolved() returns failure, the connection struct
459
is already freed and gone */
460
easy->easy_conn = NULL; /* no more connection */
462
/* FIX: what if protocol_connect is TRUE here?! */
463
multistate(easy, CURLM_STATE_WAITCONNECT);
467
if(CURLE_OK != easy->result) {
468
/* failure detected */
469
Curl_disconnect(easy->easy_conn); /* disconnect properly */
470
easy->easy_conn = NULL; /* no more connection */
636
if(CURLE_OK != easy->result) {
637
/* failure detected */
638
Curl_disconnect(easy->easy_conn); /* close the connection */
639
easy->easy_conn = NULL; /* no more connection */
476
case CURLM_STATE_WAITCONNECT:
477
/* awaiting a completion of an asynch connect */
478
easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
481
easy->result = Curl_protocol_connect(easy->easy_conn,
484
if(CURLE_OK != easy->result) {
485
/* failure detected */
486
Curl_disconnect(easy->easy_conn); /* close the connection */
487
easy->easy_conn = NULL; /* no more connection */
492
if(!protocol_connect) {
493
/* We have a TCP connection, but 'protocol_connect' may be false
494
and then we continue to 'STATE_PROTOCONNECT'. If protocol
495
connect is TRUE, we move on to STATE_DO. */
496
multistate(easy, CURLM_STATE_PROTOCONNECT);
499
/* after the connect has completed, go DO */
500
multistate(easy, CURLM_STATE_DO);
501
result = CURLM_CALL_MULTI_PERFORM;
506
case CURLM_STATE_PROTOCONNECT:
507
/* protocol-specific connect phase */
508
easy->result = Curl_protocol_connecting(easy->easy_conn,
510
if(protocol_connect) {
644
if(!protocol_connect) {
645
/* We have a TCP connection, but 'protocol_connect' may be false
646
and then we continue to 'STATE_PROTOCONNECT'. If protocol
647
connect is TRUE, we move on to STATE_DO. */
648
multistate(easy, CURLM_STATE_PROTOCONNECT);
511
651
/* after the connect has completed, go DO */
512
652
multistate(easy, CURLM_STATE_DO);
513
653
result = CURLM_CALL_MULTI_PERFORM;
515
else if(easy->result) {
516
/* failure detected */
517
Curl_posttransfer(easy->easy_handle);
518
Curl_done(&easy->easy_conn, easy->result);
519
Curl_disconnect(easy->easy_conn); /* close the connection */
520
easy->easy_conn = NULL; /* no more connection */
658
case CURLM_STATE_PROTOCONNECT:
659
/* protocol-specific connect phase */
660
easy->result = Curl_protocol_connecting(easy->easy_conn,
662
if(protocol_connect) {
663
/* after the connect has completed, go DO */
664
multistate(easy, CURLM_STATE_DO);
665
result = CURLM_CALL_MULTI_PERFORM;
667
else if(easy->result) {
668
/* failure detected */
669
Curl_posttransfer(easy->easy_handle);
670
Curl_done(&easy->easy_conn, easy->result);
671
Curl_disconnect(easy->easy_conn); /* close the connection */
672
easy->easy_conn = NULL; /* no more connection */
677
if(easy->easy_handle->set.connect_only) {
678
/* keep connection open for application to use the socket */
679
easy->easy_conn->bits.close = FALSE;
680
multistate(easy, CURLM_STATE_DONE);
681
easy->result = CURLE_OK;
525
685
/* Perform the protocol's DO action */
526
686
easy->result = Curl_do(&easy->easy_conn, &dophase_done);
557
717
Curl_disconnect(easy->easy_conn); /* close the connection */
558
718
easy->easy_conn = NULL; /* no more connection */
562
case CURLM_STATE_DOING:
563
/* we continue DOING until the DO phase is complete */
564
easy->result = Curl_protocol_doing(easy->easy_conn, &dophase_done);
723
case CURLM_STATE_DOING:
724
/* we continue DOING until the DO phase is complete */
725
easy->result = Curl_protocol_doing(easy->easy_conn, &dophase_done);
726
if(CURLE_OK == easy->result) {
728
/* after DO, go PERFORM... or DO_MORE */
729
if(easy->easy_conn->bits.do_more) {
730
/* we're supposed to do more, but we need to sit down, relax
731
and wait a little while first */
732
multistate(easy, CURLM_STATE_DO_MORE);
736
/* we're done with the DO, now PERFORM */
737
easy->result = Curl_readwrite_init(easy->easy_conn);
738
if(CURLE_OK == easy->result) {
739
multistate(easy, CURLM_STATE_PERFORM);
740
result = CURLM_CALL_MULTI_PERFORM;
746
/* failure detected */
747
Curl_posttransfer(easy->easy_handle);
748
Curl_done(&easy->easy_conn, easy->result);
749
Curl_disconnect(easy->easy_conn); /* close the connection */
750
easy->easy_conn = NULL; /* no more connection */
754
case CURLM_STATE_DO_MORE:
755
/* Ready to do more? */
756
easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
760
* When we are connected, DO MORE and then go PERFORM
762
easy->result = Curl_do_more(easy->easy_conn);
764
if(CURLE_OK == easy->result)
765
easy->result = Curl_readwrite_init(easy->easy_conn);
565
767
if(CURLE_OK == easy->result) {
567
/* after DO, go PERFORM... or DO_MORE */
568
if(easy->easy_conn->bits.do_more) {
569
/* we're supposed to do more, but we need to sit down, relax
570
and wait a little while first */
571
multistate(easy, CURLM_STATE_DO_MORE);
575
/* we're done with the DO, now PERFORM */
576
easy->result = Curl_readwrite_init(easy->easy_conn);
577
if(CURLE_OK == easy->result) {
578
multistate(easy, CURLM_STATE_PERFORM);
579
result = CURLM_CALL_MULTI_PERFORM;
585
/* failure detected */
586
Curl_posttransfer(easy->easy_handle);
587
Curl_done(&easy->easy_conn, easy->result);
588
Curl_disconnect(easy->easy_conn); /* close the connection */
589
easy->easy_conn = NULL; /* no more connection */
593
case CURLM_STATE_DO_MORE:
594
/* Ready to do more? */
595
easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
599
* When we are connected, DO MORE and then go PERFORM
601
easy->result = Curl_do_more(easy->easy_conn);
603
if(CURLE_OK == easy->result)
604
easy->result = Curl_readwrite_init(easy->easy_conn);
768
multistate(easy, CURLM_STATE_PERFORM);
769
result = CURLM_CALL_MULTI_PERFORM;
774
case CURLM_STATE_PERFORM:
775
/* read/write data if it is ready to do so */
776
easy->result = Curl_readwrite(easy->easy_conn, &done);
779
/* The transfer phase returned error, we mark the connection to get
780
* closed to prevent being re-used. This is becasue we can't
781
* possibly know if the connection is in a good shape or not now. */
782
easy->easy_conn->bits.close = TRUE;
784
if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
785
/* if we failed anywhere, we must clean up the secondary socket if
787
sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
788
easy->easy_conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
790
Curl_posttransfer(easy->easy_handle);
791
Curl_done(&easy->easy_conn, easy->result);
794
else if(TRUE == done) {
796
bool retry = Curl_retry_request(easy->easy_conn, &newurl);
798
/* call this even if the readwrite function returned error */
799
Curl_posttransfer(easy->easy_handle);
801
/* When we follow redirects, must to go back to the CONNECT state */
802
if(easy->easy_conn->newurl || retry) {
804
/* if the URL is a follow-location and not just a retried request
805
then figure out the URL here */
806
newurl = easy->easy_conn->newurl;
807
easy->easy_conn->newurl = NULL;
809
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
810
if(easy->result == CURLE_OK)
811
easy->result = Curl_follow(easy->easy_handle, newurl, retry);
606
812
if(CURLE_OK == easy->result) {
607
multistate(easy, CURLM_STATE_PERFORM);
608
result = CURLM_CALL_MULTI_PERFORM;
613
case CURLM_STATE_PERFORM:
614
/* read/write data if it is ready to do so */
615
easy->result = Curl_readwrite(easy->easy_conn, &done);
618
/* The transfer phase returned error, we mark the connection to get
619
* closed to prevent being re-used. This is becasue we can't
620
* possibly know if the connection is in a good shape or not now. */
621
easy->easy_conn->bits.close = TRUE;
623
if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
624
/* if we failed anywhere, we must clean up the secondary socket if
626
sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
627
easy->easy_conn->sock[SECONDARYSOCKET]=-1;
629
Curl_posttransfer(easy->easy_handle);
630
Curl_done(&easy->easy_conn, easy->result);
633
else if(TRUE == done) {
635
bool retry = Curl_retry_request(easy->easy_conn, &newurl);
637
/* call this even if the readwrite function returned error */
638
Curl_posttransfer(easy->easy_handle);
640
/* When we follow redirects, must to go back to the CONNECT state */
641
if(easy->easy_conn->newurl || retry) {
643
/* if the URL is a follow-location and not just a retried request
644
then figure out the URL here */
645
newurl = easy->easy_conn->newurl;
646
easy->easy_conn->newurl = NULL;
648
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
649
if(easy->result == CURLE_OK)
650
easy->result = Curl_follow(easy->easy_handle, newurl, retry);
651
if(CURLE_OK == easy->result) {
652
multistate(easy, CURLM_STATE_CONNECT);
653
result = CURLM_CALL_MULTI_PERFORM;
656
/* Since we "took it", we are in charge of freeing this on
661
/* after the transfer is done, go DONE */
662
multistate(easy, CURLM_STATE_DONE);
663
result = CURLM_CALL_MULTI_PERFORM;
667
case CURLM_STATE_DONE:
668
/* post-transfer command */
669
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
671
/* after we have DONE what we're supposed to do, go COMPLETED, and
672
it doesn't matter what the Curl_done() returned! */
813
multistate(easy, CURLM_STATE_CONNECT);
814
result = CURLM_CALL_MULTI_PERFORM;
817
/* Since we "took it", we are in charge of freeing this on
822
/* after the transfer is done, go DONE */
823
multistate(easy, CURLM_STATE_DONE);
824
result = CURLM_CALL_MULTI_PERFORM;
828
case CURLM_STATE_DONE:
829
/* post-transfer command */
830
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
832
/* after we have DONE what we're supposed to do, go COMPLETED, and
833
it doesn't matter what the Curl_done() returned! */
834
multistate(easy, CURLM_STATE_COMPLETED);
837
case CURLM_STATE_COMPLETED:
838
/* this is a completed transfer, it is likely to still be connected */
840
/* This node should be delinked from the list now and we should post
841
an information message that we are complete. */
844
return CURLM_INTERNAL_ERROR;
847
if(CURLM_STATE_COMPLETED != easy->state) {
848
if(CURLE_OK != easy->result) {
850
* If an error was returned, and we aren't in completed state now,
851
* then we go to completed and consider this transfer aborted. */
673
852
multistate(easy, CURLM_STATE_COMPLETED);
676
case CURLM_STATE_COMPLETED:
677
/* this is a completed transfer, it is likely to still be connected */
679
/* This node should be delinked from the list now and we should post
680
an information message that we are complete. */
683
return CURLM_INTERNAL_ERROR;
686
if(CURLM_STATE_COMPLETED != easy->state) {
687
if(CURLE_OK != easy->result) {
689
* If an error was returned, and we aren't in completed state now,
690
* then we go to completed and consider this transfer aborted. */
691
multistate(easy, CURLM_STATE_COMPLETED);
694
/* this one still lives! */
695
(*running_handles)++;
698
} while (easy->easy_handle->change.url_changed);
700
if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
701
/* clear out the usage of the shared DNS cache */
702
easy->easy_handle->hostcache = NULL;
704
/* now add a node to the Curl_message linked list with this info */
705
msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
708
return CURLM_OUT_OF_MEMORY;
710
msg->extmsg.msg = CURLMSG_DONE;
711
msg->extmsg.easy_handle = easy->easy_handle;
712
msg->extmsg.data.result = easy->result;
716
easy->msg_num = 1; /* there is one unread message here */
718
multi->num_msgs++; /* increase message counter */
855
/* this one still lives! */
856
(*running_handles)++;
859
} while (easy->easy_handle->change.url_changed);
861
if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
862
/* clear out the usage of the shared DNS cache */
863
easy->easy_handle->hostcache = NULL;
865
/* now add a node to the Curl_message linked list with this info */
866
msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
869
return CURLM_OUT_OF_MEMORY;
871
msg->extmsg.msg = CURLMSG_DONE;
872
msg->extmsg.easy_handle = easy->easy_handle;
873
msg->extmsg.data.result = easy->result;
877
easy->msg_num = 1; /* there is one unread message here */
879
multi->num_msgs++; /* increase message counter */
886
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
888
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
889
struct Curl_one_easy *easy;
890
CURLMcode returncode=CURLM_OK;
893
*running_handles = 0; /* bump this once for every living handle */
895
if(!GOOD_MULTI_HANDLE(multi))
896
return CURLM_BAD_HANDLE;
898
easy=multi->easy.next;
900
CURLMcode result = multi_runsingle(multi, easy, running_handles);
720
904
easy = easy->next; /* operate on next handle */
908
* Simply remove all expired timers from the splay since handles are dealt
909
* with unconditionally by this function and curl_multi_timeout() requires
910
* that already passed/handled expire times are removed from the splay.
913
struct timeval now = Curl_tvnow();
914
int key = now.tv_sec; /* drop the usec part */
916
multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
726
922
/* This is called when an easy handle is cleanup'ed that is part of a multi
995
* singlesocket() checks what sockets we deal with and their "action state"
996
* and if we have a different state in any of those sockets from last time we
997
* call the callback accordingly.
999
static void singlesocket(struct Curl_multi *multi,
1000
struct Curl_one_easy *easy)
1002
struct socketstate current;
1005
memset(¤t, 0, sizeof(current));
1006
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
1007
current.socks[i] = CURL_SOCKET_BAD;
1009
/* first fill in the 'current' struct with the state as it is now */
1010
current.action = multi_getsock(easy, current.socks, MAX_SOCKSPEREASYHANDLE);
1012
/* when filled in, we compare with the previous round's state in a first
1013
quick memory compare check */
1014
if(memcmp(¤t, &easy->sockstate, sizeof(struct socketstate))) {
1016
/* there is difference, call the callback once for every socket change ! */
1017
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
1019
curl_socket_t s = current.socks[i];
1021
/* Ok, this approach is probably too naive and simple-minded but
1022
it might work for a start */
1024
if((easy->sockstate.socks[i] == CURL_SOCKET_BAD) &&
1025
(s == CURL_SOCKET_BAD)) {
1026
/* no socket now and there was no socket before */
1030
if(s == CURL_SOCKET_BAD) {
1031
/* socket is removed */
1032
action = CURL_POLL_REMOVE;
1033
s = easy->sockstate.socks[i]; /* this is the removed socket */
1036
if(easy->sockstate.socks[i] == s) {
1037
/* still the same socket, but are we waiting for the same actions? */
1041
/* the current read/write bits for this particular socket */
1042
curr = current.action & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i));
1044
/* the previous read/write bits for this particular socket */
1045
prev = easy->sockstate.action &
1046
(GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i));
1052
action = ((current.action & GETSOCK_READSOCK(i))?CURL_POLL_IN:0) |
1053
((current.action & GETSOCK_WRITESOCK(i))?CURL_POLL_OUT:0);
1056
/* call the callback with this new info */
1057
if(multi->socket_cb) {
1058
multi->socket_cb(easy->easy_handle,
1061
multi->socket_userp);
1064
/* Update the sockhash accordingly */
1065
if(action == CURL_POLL_REMOVE)
1066
/* remove from hash for this easy handle */
1067
sh_delentry(multi->sockhash, s);
1069
/* make sure this socket is present in the hash for this handle */
1070
sh_addentry(multi->sockhash, s, easy->easy_handle);
1072
/* copy the current state to the storage area */
1073
memcpy(&easy->sockstate, ¤t, sizeof(struct socketstate));
1076
/* identical, nothing new happened so we don't do any callbacks */
1081
static CURLMcode multi_socket(struct Curl_multi *multi,
1085
CURLMcode result = CURLM_OK;
1086
int running_handles;
1087
struct SessionHandle *data = NULL;
1088
struct Curl_tree *t;
1091
struct Curl_one_easy *easyp;
1092
result = curl_multi_perform(multi, &running_handles);
1094
/* walk through each easy handle and do the socket state change magic
1096
easyp=multi->easy.next;
1098
singlesocket(multi, easyp);
1099
easyp = easyp->next;
1102
/* or should we fall-through and do the timer-based stuff? */
1105
else if (s != CURL_SOCKET_TIMEOUT) {
1107
struct Curl_sh_entry *entry =
1108
Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
1111
/* unmatched socket, major problemo! */
1112
return CURLM_BAD_SOCKET; /* better return code? */
1114
/* Now, there is potentially a chain of easy handles in this hash
1115
entry struct and we need to deal with all of them */
1119
result = multi_runsingle(multi, data->set.one_easy, &running_handles);
1121
if(result == CURLM_OK)
1122
/* get the socket(s) and check if the state has been changed since
1124
singlesocket(multi, data->set.one_easy);
1126
/* or should we fall-through and do the timer-based stuff? */
1131
* The loop following here will go on as long as there are expire-times left
1132
* to process in the splay and 'data' will be re-assigned for every expired
1133
* handle we deal with.
1139
/* the first loop lap 'data' can be NULL */
1141
result = multi_runsingle(multi, data->set.one_easy, &running_handles);
1143
if(result == CURLM_OK)
1144
/* get the socket(s) and check if the state has been changed since
1146
singlesocket(multi, data->set.one_easy);
1149
/* Check if there's one (more) expired timer to deal with! This function
1150
extracts a matching node if there is one */
1153
key = now.tv_sec; /* drop the usec part */
1155
multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
1164
CURLMcode curl_multi_setopt(CURLM *multi_handle,
1165
CURLMoption option, ...)
1167
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1168
CURLMcode res = CURLM_OK;
1171
if(!GOOD_MULTI_HANDLE(multi))
1172
return CURLM_BAD_HANDLE;
1174
va_start(param, option);
1177
case CURLMOPT_SOCKETFUNCTION:
1178
multi->socket_cb = va_arg(param, curl_socket_callback);
1180
case CURLMOPT_SOCKETDATA:
1181
multi->socket_userp = va_arg(param, void *);
1184
res = CURLM_UNKNOWN_OPTION;
1191
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s)
1194
printf("multi_socket(%d)\n", (int)s);
1197
return multi_socket((struct Curl_multi *)multi_handle, FALSE, s);
1200
CURLMcode curl_multi_socket_all(CURLM *multi_handle)
1203
return multi_socket((struct Curl_multi *)multi_handle,
1204
TRUE, CURL_SOCKET_BAD);
1207
CURLMcode curl_multi_timeout(CURLM *multi_handle,
1210
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1212
/* First, make some basic checks that the CURLM handle is a good handle */
1213
if(!GOOD_MULTI_HANDLE(multi))
1214
return CURLM_BAD_HANDLE;
1216
if(multi->timetree) {
1217
/* we have a tree of expire times */
1218
struct timeval now = Curl_tvnow();
1220
/* splay the lowest to the bottom */
1221
multi->timetree = Curl_splay(0, multi->timetree);
1223
/* At least currently, the splay key is a time_t for the expire time */
1224
*timeout_ms = (multi->timetree->key - now.tv_sec) * 1000 -
1227
/* 0 means immediately */
1236
/* given a number of milliseconds from now to use to set the 'act before
1237
this'-time for the transfer, to be extracted by curl_multi_timeout() */
1238
void Curl_expire(struct SessionHandle *data, long milli)
1240
struct Curl_multi *multi = data->multi;
1241
struct timeval *nowp = &data->state.expiretime;
1244
/* this is only interesting for multi-interface using libcurl, and only
1245
while there is still a multi interface struct remaining! */
1250
/* No timeout, clear the time data. */
1252
/* Since this is an cleared time, we must remove the previous entry from
1254
rc = Curl_splayremovebyaddr(multi->timetree,
1255
&data->state.timenode,
1258
infof(data, "Internal error clearing splay node = %d\n", rc);
1259
infof(data, "Expire cleared\n");
1260
nowp->tv_sec = nowp->tv_usec = 0;
1268
set.tv_sec += milli/1000;
1269
set.tv_usec += (milli%1000)*1000;
1271
rest = (int)(set.tv_usec - 1000000);
1273
/* bigger than a full microsec */
1275
set.tv_usec -= 1000000;
1279
/* This means that the struct is added as a node in the splay tree.
1280
Compare if the new time is earlier, and only remove-old/add-new if it
1282
long diff = curlx_tvdiff(set, *nowp);
1284
/* the new expire time was later so we don't change this */
1287
/* Since this is an updated time, we must remove the previous entry from
1288
the splay tree first and then re-add the new value */
1289
rc = Curl_splayremovebyaddr(multi->timetree,
1290
&data->state.timenode,
1293
infof(data, "Internal error removing splay node = %d\n", rc);
1297
infof(data, "Expire at %ld / %ld (%ldms)\n",
1298
(long)nowp->tv_sec, (long)nowp->tv_usec, milli);
1300
data->state.timenode.payload = data;
1301
multi->timetree = Curl_splayinsert((int)nowp->tv_sec,
1303
&data->state.timenode);
1306
Curl_splayprint(multi->timetree, 0, TRUE);