1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
22 ***************************************************************************/
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
38 #include <curl/curl.h>
46 /* The last #include file should be: */
52 /* the 'CURLMsg' is the part that is visible to the external user */
53 struct CURLMsg extmsg;
54 struct Curl_message *next;
59 CURLM_STATE_CONNECT, /* resolve/connect has been sent off */
60 CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
61 CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
62 CURLM_STATE_DO, /* send off the request (part 1) */
63 CURLM_STATE_DO_MORE, /* send off the request (part 2) */
64 CURLM_STATE_PERFORM, /* transfer data */
65 CURLM_STATE_DONE, /* post data transfer operation */
66 CURLM_STATE_COMPLETED, /* operation complete */
68 CURLM_STATE_LAST /* not a true state, never use this */
71 struct Curl_one_easy {
72 /* first, two fields for the linked list of these */
73 struct Curl_one_easy *next;
74 struct Curl_one_easy *prev;
76 struct SessionHandle *easy_handle; /* the easy handle for this unit */
77 struct connectdata *easy_conn; /* the "unit's" connection */
79 CURLMstate state; /* the handle's state */
80 CURLcode result; /* previous result */
82 struct Curl_message *msg; /* A pointer to one single posted message.
83 Cleanup should be done on this pointer NOT on
84 the linked list in Curl_multi. This message
85 will be deleted when this handle is removed
86 from the multi-handle */
87 int msg_num; /* number of messages left in 'msg' to return */
91 #define CURL_MULTI_HANDLE 0x000bab1e
93 #define GOOD_MULTI_HANDLE(x) ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE))
94 #define GOOD_EASY_HANDLE(x) (x)
96 /* This is the struct known as CURLM on the outside */
98 /* First a simple identifier to easier detect if a user mix up
99 this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
102 /* We have a linked list with easy handles */
103 struct Curl_one_easy easy;
104 /* This is the amount of entries in the linked list above. */
107 int num_msgs; /* total amount of messages in the easy handles */
110 curl_hash *hostcache;
114 CURLM *curl_multi_init(void)
116 struct Curl_multi *multi;
118 multi = (void *)malloc(sizeof(struct Curl_multi));
121 memset(multi, 0, sizeof(struct Curl_multi));
122 multi->type = CURL_MULTI_HANDLE;
125 multi->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
126 if(!multi->hostcache) {
127 /* failure, free mem and bail out */
131 return (CURLM *) multi;
134 CURLMcode curl_multi_add_handle(CURLM *multi_handle,
137 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
138 struct Curl_one_easy *easy;
140 /* First, make some basic checks that the CURLM handle is a good handle */
141 if(!GOOD_MULTI_HANDLE(multi))
142 return CURLM_BAD_HANDLE;
144 /* Verify that we got a somewhat good easy handle too */
145 if(!GOOD_EASY_HANDLE(easy_handle))
146 return CURLM_BAD_EASY_HANDLE;
148 /* Now, time to add an easy handle to the multi stack */
149 easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
151 return CURLM_OUT_OF_MEMORY;
153 /* clean it all first (just to be sure) */
154 memset(easy, 0, sizeof(struct Curl_one_easy));
156 /* set the easy handle */
157 easy->easy_handle = easy_handle;
158 easy->state = CURLM_STATE_INIT;
160 /* for multi interface connections, we share DNS cache automaticly */
161 easy->easy_handle->hostcache = multi->hostcache;
163 /* We add this new entry first in the list. We make our 'next' point to the
164 previous next and our 'prev' point back to the 'first' struct */
165 easy->next = multi->easy.next;
166 easy->prev = &multi->easy;
168 /* make 'easy' the first node in the chain */
169 multi->easy.next = easy;
171 /* if there was a next node, make sure its 'prev' pointer links back to
174 easy->next->prev = easy;
176 /* increase the node-counter */
179 return CURLM_CALL_MULTI_PERFORM;
182 CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
185 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
186 struct Curl_one_easy *easy;
188 /* First, make some basic checks that the CURLM handle is a good handle */
189 if(!GOOD_MULTI_HANDLE(multi))
190 return CURLM_BAD_HANDLE;
192 /* Verify that we got a somewhat good easy handle too */
193 if(!GOOD_EASY_HANDLE(curl_handle))
194 return CURLM_BAD_EASY_HANDLE;
196 /* scan through the list and remove the 'curl_handle' */
197 easy = multi->easy.next;
199 if(easy->easy_handle == curl_handle)
204 /* If the 'state' is not INIT or COMPLETED, we might need to do something
205 nice to put the easy_handle in a good known state when this returns. */
207 /* clear out the usage of the shared DNS cache */
208 easy->easy_handle->hostcache = NULL;
210 /* make the previous node point to our next */
212 easy->prev->next = easy->next;
213 /* make our next point to our previous node */
215 easy->next->prev = easy->prev;
218 We do not touch the easy handle here! */
223 multi->num_easy--; /* one less to care about now */
228 return CURLM_BAD_EASY_HANDLE; /* twasn't found */
231 CURLMcode curl_multi_fdset(CURLM *multi_handle,
232 fd_set *read_fd_set, fd_set *write_fd_set,
233 fd_set *exc_fd_set, int *max_fd)
235 /* Scan through all the easy handles to get the file descriptors set.
236 Some easy handles may not have connected to the remote host yet,
237 and then we must make sure that is done. */
238 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
239 struct Curl_one_easy *easy;
242 if(!GOOD_MULTI_HANDLE(multi))
243 return CURLM_BAD_HANDLE;
245 *max_fd = -1; /* so far none! */
247 easy=multi->easy.next;
249 switch(easy->state) {
252 case CURLM_STATE_WAITRESOLVE:
253 /* waiting for a resolve to complete */
254 Curl_multi_ares_fdset(easy->easy_conn, read_fd_set, write_fd_set,
256 if(this_max_fd > *max_fd)
257 *max_fd = this_max_fd;
260 case CURLM_STATE_WAITCONNECT:
261 case CURLM_STATE_DO_MORE:
263 /* when we're waiting for a connect, we wait for the socket to
265 struct connectdata *conn = easy->easy_conn;
268 if(CURLM_STATE_WAITCONNECT == easy->state) {
269 sockfd = conn->sock[FIRSTSOCKET];
270 FD_SET(sockfd, write_fd_set);
273 /* When in DO_MORE state, we could be either waiting for us
274 to connect to a remote site, or we could wait for that site
275 to connect to us. It makes a difference in the way: if we
276 connect to the site we wait for the socket to become writable, if
277 the site connects to us we wait for it to become readable */
278 sockfd = conn->sock[SECONDARYSOCKET];
279 FD_SET(sockfd, write_fd_set);
286 case CURLM_STATE_PERFORM:
287 /* This should have a set of file descriptors for us to set. */
288 /* after the transfer is done, go DONE */
290 Curl_single_fdset(easy->easy_conn,
291 read_fd_set, write_fd_set,
292 exc_fd_set, &this_max_fd);
294 /* remember the maximum file descriptor */
295 if(this_max_fd > *max_fd)
296 *max_fd = this_max_fd;
300 easy = easy->next; /* check next handle */
306 CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
308 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
309 struct Curl_one_easy *easy;
311 CURLMcode result=CURLM_OK;
312 struct Curl_message *msg = NULL;
316 *running_handles = 0; /* bump this once for every living handle */
318 if(!GOOD_MULTI_HANDLE(multi))
319 return CURLM_BAD_HANDLE;
321 easy=multi->easy.next;
325 fprintf(stderr, "HANDLE %p: State: %x\n",
326 (char *)easy, easy->state);
329 switch(easy->state) {
330 case CURLM_STATE_INIT:
331 /* init this transfer. */
332 easy->result=Curl_pretransfer(easy->easy_handle);
334 if(CURLE_OK == easy->result) {
335 /* after init, go CONNECT */
336 easy->state = CURLM_STATE_CONNECT;
337 result = CURLM_CALL_MULTI_PERFORM;
339 easy->easy_handle->state.used_interface = Curl_if_multi;
343 case CURLM_STATE_CONNECT:
344 /* Connect. We get a connection identifier filled in. */
345 Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
346 easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn, &async);
348 if(CURLE_OK == easy->result) {
350 /* We're now waiting for an asynchronous name lookup */
351 easy->state = CURLM_STATE_WAITRESOLVE;
353 /* after the connect has been sent off, go WAITCONNECT */
354 easy->state = CURLM_STATE_WAITCONNECT;
355 result = CURLM_CALL_MULTI_PERFORM;
360 case CURLM_STATE_WAITRESOLVE:
361 /* awaiting an asynch name resolve to complete */
363 struct Curl_dns_entry *dns;
365 /* check if we have the name resolved by now */
366 easy->result = Curl_is_resolved(easy->easy_conn, &dns);
369 /* Perform the next step in the connection phase, and then move on
370 to the WAITCONNECT state */
371 easy->result = Curl_async_resolved(easy->easy_conn);
373 if(CURLE_OK != easy->result)
374 /* if Curl_async_resolved() returns failure, the connection struct
375 is already freed and gone */
376 easy->easy_conn = NULL; /* no more connection */
378 easy->state = CURLM_STATE_WAITCONNECT;
381 if(CURLE_OK != easy->result) {
382 /* failure detected */
383 Curl_disconnect(easy->easy_conn); /* disconnect properly */
384 easy->easy_conn = NULL; /* no more connection */
390 case CURLM_STATE_WAITCONNECT:
391 /* awaiting a completion of an asynch connect */
392 easy->result = Curl_is_connected(easy->easy_conn,
393 easy->easy_conn->sock[FIRSTSOCKET],
396 easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
398 if(CURLE_OK != easy->result) {
399 /* failure detected */
400 Curl_disconnect(easy->easy_conn); /* close the connection */
401 easy->easy_conn = NULL; /* no more connection */
406 /* after the connect has completed, go DO */
407 easy->state = CURLM_STATE_DO;
408 result = CURLM_CALL_MULTI_PERFORM;
413 /* Do the fetch or put request */
414 easy->result = Curl_do(&easy->easy_conn);
415 if(CURLE_OK == easy->result) {
417 /* after do, go PERFORM... or DO_MORE */
418 if(easy->easy_conn->bits.do_more) {
419 /* we're supposed to do more, but we need to sit down, relax
420 and wait a little while first */
421 easy->state = CURLM_STATE_DO_MORE;
425 /* we're done with the DO, now PERFORM */
426 easy->result = Curl_readwrite_init(easy->easy_conn);
427 if(CURLE_OK == easy->result) {
428 easy->state = CURLM_STATE_PERFORM;
429 result = CURLM_CALL_MULTI_PERFORM;
435 case CURLM_STATE_DO_MORE:
437 * First, check if we really are ready to do more.
439 easy->result = Curl_is_connected(easy->easy_conn,
440 easy->easy_conn->sock[SECONDARYSOCKET],
444 * When we are connected, DO MORE and then go PERFORM
446 easy->result = Curl_do_more(easy->easy_conn);
448 if(CURLE_OK == easy->result)
449 easy->result = Curl_readwrite_init(easy->easy_conn);
451 if(CURLE_OK == easy->result) {
452 easy->state = CURLM_STATE_PERFORM;
453 result = CURLM_CALL_MULTI_PERFORM;
458 case CURLM_STATE_PERFORM:
459 /* read/write data if it is ready to do so */
460 easy->result = Curl_readwrite(easy->easy_conn, &done);
463 /* The transfer phase returned error, we mark the connection to get
464 * closed to prevent being re-used. This is becasue we can't
465 * possibly know if the connection is in a good shape or not now. */
466 easy->easy_conn->bits.close = TRUE;
468 if(-1 !=easy->easy_conn->sock[SECONDARYSOCKET]) {
469 /* if we failed anywhere, we must clean up the secondary socket if
471 sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
472 easy->easy_conn->sock[SECONDARYSOCKET]=-1;
474 Curl_posttransfer(easy->easy_handle);
475 Curl_done(easy->easy_conn);
478 /* after the transfer is done, go DONE */
479 else if(TRUE == done) {
481 /* call this even if the readwrite function returned error */
482 Curl_posttransfer(easy->easy_handle);
484 /* When we follow redirects, must to go back to the CONNECT state */
485 if(easy->easy_conn->newurl) {
486 char *newurl = easy->easy_conn->newurl;
487 easy->easy_conn->newurl = NULL;
488 easy->result = Curl_follow(easy->easy_handle, newurl);
489 if(CURLE_OK == easy->result) {
490 easy->state = CURLM_STATE_CONNECT;
491 result = CURLM_CALL_MULTI_PERFORM;
495 easy->state = CURLM_STATE_DONE;
496 result = CURLM_CALL_MULTI_PERFORM;
500 case CURLM_STATE_DONE:
501 /* post-transfer command */
502 easy->result = Curl_done(easy->easy_conn);
504 /* after we have DONE what we're supposed to do, go COMPLETED, and
505 it doesn't matter what the Curl_done() returned! */
506 easy->state = CURLM_STATE_COMPLETED;
509 case CURLM_STATE_COMPLETED:
510 /* this is a completed transfer, it is likely to still be connected */
512 /* This node should be delinked from the list now and we should post
513 an information message that we are complete. */
516 return CURLM_INTERNAL_ERROR;
519 if(CURLM_STATE_COMPLETED != easy->state) {
520 if(CURLE_OK != easy->result) {
522 * If an error was returned, and we aren't in completed state now,
523 * then we go to completed and consider this transfer aborted. */
524 easy->state = CURLM_STATE_COMPLETED;
527 /* this one still lives! */
528 (*running_handles)++;
531 if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
532 /* clear out the usage of the shared DNS cache */
533 easy->easy_handle->hostcache = NULL;
535 /* now add a node to the Curl_message linked list with this info */
536 msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
539 return CURLM_OUT_OF_MEMORY;
541 msg->extmsg.msg = CURLMSG_DONE;
542 msg->extmsg.easy_handle = easy->easy_handle;
543 msg->extmsg.data.result = easy->result;
547 easy->msg_num = 1; /* there is one unread message here */
549 multi->num_msgs++; /* increase message counter */
552 easy = easy->next; /* operate on next handle */
558 CURLMcode curl_multi_cleanup(CURLM *multi_handle)
560 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
561 struct Curl_one_easy *easy;
562 struct Curl_one_easy *nexteasy;
564 if(GOOD_MULTI_HANDLE(multi)) {
565 multi->type = 0; /* not good anymore */
566 Curl_hash_destroy(multi->hostcache);
568 /* remove all easy handles */
569 easy = multi->easy.next;
572 /* clear out the usage of the shared DNS cache */
573 easy->easy_handle->hostcache = NULL;
586 return CURLM_BAD_HANDLE;
589 CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
591 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
593 *msgs_in_queue = 0; /* default to none */
595 if(GOOD_MULTI_HANDLE(multi)) {
596 struct Curl_one_easy *easy;
599 return NULL; /* no messages left to return */
601 easy=multi->easy.next;
610 return NULL; /* this means internal count confusion really */
613 *msgs_in_queue = multi->num_msgs;
615 return &easy->msg->extmsg;