e7a6a1d5b7d47d53f11a3800d8bf32f2cb883e7b
[platform/upstream/curl.git] / lib / multi.c
1 /***************************************************************************
2  *                                  _   _ ____  _     
3  *  Project                     ___| | | |  _ \| |    
4  *                             / __| | | | |_) | |    
5  *                            | (__| |_| |  _ <| |___ 
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  * 
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25 #include <stdlib.h>
26 #include <string.h>
27
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <curl/curl.h>
39
40 #include "urldata.h"
41 #include "transfer.h"
42 #include "url.h"
43 #include "connect.h"
44 #include "progress.h"
45
46 /* The last #include file should be: */
47 #ifdef CURLDEBUG
48 #include "memdebug.h"
49 #endif
50
51 struct Curl_message {
52   /* the 'CURLMsg' is the part that is visible to the external user */
53   struct CURLMsg extmsg;
54   struct Curl_message *next;
55 };
56
57 typedef enum {
58   CURLM_STATE_INIT,
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 */
67
68   CURLM_STATE_LAST /* not a true state, never use this */
69 } CURLMstate;
70
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;
75   
76   struct SessionHandle *easy_handle; /* the easy handle for this unit */
77   struct connectdata *easy_conn;     /* the "unit's" connection */
78
79   CURLMstate state;  /* the handle's state */
80   CURLcode result;   /* previous result */
81
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 */
88 };
89
90
91 #define CURL_MULTI_HANDLE 0x000bab1e
92
93 #define GOOD_MULTI_HANDLE(x) ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE))
94 #define GOOD_EASY_HANDLE(x) (x)
95
96 /* This is the struct known as CURLM on the outside */
97 struct Curl_multi {
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. */
100   long type;
101
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. */
105   int num_easy;
106
107   int num_msgs; /* total amount of messages in the easy handles */
108
109   /* Hostname cache */
110   curl_hash *hostcache;
111 };
112
113
114 CURLM *curl_multi_init(void)
115 {
116   struct Curl_multi *multi;
117
118   multi = (void *)malloc(sizeof(struct Curl_multi));
119
120   if(multi) {
121     memset(multi, 0, sizeof(struct Curl_multi));
122     multi->type = CURL_MULTI_HANDLE;
123   }
124
125   multi->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
126   if(!multi->hostcache) {
127     /* failure, free mem and bail out */
128     free(multi);
129     multi = NULL;
130   }
131   return (CURLM *) multi;
132 }
133
134 CURLMcode curl_multi_add_handle(CURLM *multi_handle,
135                                 CURL *easy_handle)
136 {
137   struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
138   struct Curl_one_easy *easy;
139
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;
143   
144   /* Verify that we got a somewhat good easy handle too */
145   if(!GOOD_EASY_HANDLE(easy_handle))
146     return CURLM_BAD_EASY_HANDLE;
147
148   /* Now, time to add an easy handle to the multi stack */
149   easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
150   if(!easy)
151     return CURLM_OUT_OF_MEMORY;
152   
153   /* clean it all first (just to be sure) */
154   memset(easy, 0, sizeof(struct Curl_one_easy));
155
156   /* set the easy handle */
157   easy->easy_handle = easy_handle;
158   easy->state = CURLM_STATE_INIT;
159
160   /* for multi interface connections, we share DNS cache automaticly */
161   easy->easy_handle->hostcache = multi->hostcache;
162   
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; 
167
168   /* make 'easy' the first node in the chain */
169   multi->easy.next = easy;
170
171   /* if there was a next node, make sure its 'prev' pointer links back to
172      the new node */
173   if(easy->next)
174     easy->next->prev = easy;
175
176   /* increase the node-counter */
177   multi->num_easy++;
178
179   return CURLM_CALL_MULTI_PERFORM;
180 }
181
182 CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
183                                    CURL *curl_handle)
184 {
185   struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
186   struct Curl_one_easy *easy;
187
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;
191   
192   /* Verify that we got a somewhat good easy handle too */
193   if(!GOOD_EASY_HANDLE(curl_handle))
194     return CURLM_BAD_EASY_HANDLE;
195
196   /* scan through the list and remove the 'curl_handle' */
197   easy = multi->easy.next;
198   while(easy) {
199     if(easy->easy_handle == curl_handle)
200       break;
201     easy=easy->next;
202   }
203   if(easy) {
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. */
206
207     /* clear out the usage of the shared DNS cache */
208     easy->easy_handle->hostcache = NULL;
209     
210     /* make the previous node point to our next */
211     if(easy->prev)
212       easy->prev->next = easy->next;
213     /* make our next point to our previous node */
214     if(easy->next)
215       easy->next->prev = easy->prev;
216     
217     /* NOTE NOTE NOTE
218        We do not touch the easy handle here! */
219     if (easy->msg)
220       free(easy->msg);
221     free(easy);
222
223     multi->num_easy--; /* one less to care about now */
224
225     return CURLM_OK;
226   }
227   else
228     return CURLM_BAD_EASY_HANDLE; /* twasn't found */
229 }
230
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)
234 {
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;
240   int this_max_fd=-1;
241
242   if(!GOOD_MULTI_HANDLE(multi))
243     return CURLM_BAD_HANDLE;
244
245   *max_fd = -1; /* so far none! */
246
247   easy=multi->easy.next;
248   while(easy) {
249     switch(easy->state) {
250     default:
251       break;
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,
255                             &this_max_fd);
256       if(this_max_fd > *max_fd)
257         *max_fd = this_max_fd;
258       break;
259
260     case CURLM_STATE_WAITCONNECT:
261     case CURLM_STATE_DO_MORE:
262       {
263         /* when we're waiting for a connect, we wait for the socket to
264            become writable */
265         struct connectdata *conn = easy->easy_conn;
266         int sockfd;
267
268         if(CURLM_STATE_WAITCONNECT == easy->state) {
269           sockfd = conn->sock[FIRSTSOCKET];
270           FD_SET(sockfd, write_fd_set);
271         }
272         else {
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);
280         }
281
282         if(sockfd > *max_fd)
283           *max_fd = sockfd;
284       }
285       break;
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 */
289
290       Curl_single_fdset(easy->easy_conn,
291                         read_fd_set, write_fd_set,
292                         exc_fd_set, &this_max_fd);
293
294       /* remember the maximum file descriptor */
295       if(this_max_fd > *max_fd)
296         *max_fd = this_max_fd;
297
298       break;
299     }
300     easy = easy->next; /* check next handle */
301   }
302
303   return CURLM_OK;
304 }
305
306 CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
307 {
308   struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
309   struct Curl_one_easy *easy;
310   bool done;
311   CURLMcode result=CURLM_OK;
312   struct Curl_message *msg = NULL;
313   bool connected;
314   bool async;
315
316   *running_handles = 0; /* bump this once for every living handle */
317
318   if(!GOOD_MULTI_HANDLE(multi))
319     return CURLM_BAD_HANDLE;
320
321   easy=multi->easy.next;
322   while(easy) {
323
324 #ifdef CURLDEBUG
325     fprintf(stderr, "HANDLE %p: State: %x\n",
326             (char *)easy, easy->state);
327 #endif
328
329     switch(easy->state) {
330     case CURLM_STATE_INIT:
331       /* init this transfer. */
332       easy->result=Curl_pretransfer(easy->easy_handle);
333
334       if(CURLE_OK == easy->result) {
335         /* after init, go CONNECT */
336         easy->state = CURLM_STATE_CONNECT;
337         result = CURLM_CALL_MULTI_PERFORM; 
338         
339         easy->easy_handle->state.used_interface = Curl_if_multi;
340       }
341       break;
342
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);
347
348       if(CURLE_OK == easy->result) {
349         if(async)
350           /* We're now waiting for an asynchronous name lookup */
351           easy->state = CURLM_STATE_WAITRESOLVE;
352         else {
353           /* after the connect has been sent off, go WAITCONNECT */
354           easy->state = CURLM_STATE_WAITCONNECT;
355           result = CURLM_CALL_MULTI_PERFORM;
356         }
357       }
358       break;
359
360     case CURLM_STATE_WAITRESOLVE:
361       /* awaiting an asynch name resolve to complete */
362       {
363         struct Curl_dns_entry *dns;
364
365         /* check if we have the name resolved by now */
366         easy->result = Curl_is_resolved(easy->easy_conn, &dns);
367
368         if(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);
372
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 */
377
378           easy->state = CURLM_STATE_WAITCONNECT;
379         }
380         
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 */
385           break;
386         }
387       }
388       break;
389
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],
394                                        &connected);
395       if(connected)
396         easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
397
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 */
402         break;
403       }
404
405       if(connected) {
406         /* after the connect has completed, go DO */
407         easy->state = CURLM_STATE_DO;
408         result = CURLM_CALL_MULTI_PERFORM; 
409       }
410       break;
411
412     case CURLM_STATE_DO:
413       /* Do the fetch or put request */
414       easy->result = Curl_do(&easy->easy_conn);
415       if(CURLE_OK == easy->result) {
416
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;
422           result = CURLM_OK;
423         }
424         else {
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; 
430           }
431         }
432       }
433       break;
434
435     case CURLM_STATE_DO_MORE:
436       /*
437        * First, check if we really are ready to do more.
438        */
439       easy->result = Curl_is_connected(easy->easy_conn,
440                                        easy->easy_conn->sock[SECONDARYSOCKET],
441                                        &connected);
442       if(connected) {
443         /*
444          * When we are connected, DO MORE and then go PERFORM
445          */
446         easy->result = Curl_do_more(easy->easy_conn);
447
448         if(CURLE_OK == easy->result)
449           easy->result = Curl_readwrite_init(easy->easy_conn);
450
451         if(CURLE_OK == easy->result) {
452           easy->state = CURLM_STATE_PERFORM;
453           result = CURLM_CALL_MULTI_PERFORM; 
454         }
455       }
456       break;
457
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);
461
462       if(easy->result)  {
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;
467
468         if(-1 !=easy->easy_conn->sock[SECONDARYSOCKET]) {
469           /* if we failed anywhere, we must clean up the secondary socket if
470              it was used */
471           sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
472           easy->easy_conn->sock[SECONDARYSOCKET]=-1;
473         }
474         Curl_posttransfer(easy->easy_handle);
475         Curl_done(easy->easy_conn);
476       }
477
478       /* after the transfer is done, go DONE */
479       else if(TRUE == done) {
480
481         /* call this even if the readwrite function returned error */
482         Curl_posttransfer(easy->easy_handle);
483
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;
492           }
493         }
494         else {
495           easy->state = CURLM_STATE_DONE;
496           result = CURLM_CALL_MULTI_PERFORM; 
497         }
498       }
499       break;
500     case CURLM_STATE_DONE:
501       /* post-transfer command */
502       easy->result = Curl_done(easy->easy_conn);
503
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;
507       break;
508
509     case CURLM_STATE_COMPLETED:
510       /* this is a completed transfer, it is likely to still be connected */
511
512       /* This node should be delinked from the list now and we should post
513          an information message that we are complete. */
514       break;
515     default:
516       return CURLM_INTERNAL_ERROR;
517     }
518
519     if(CURLM_STATE_COMPLETED != easy->state) {
520       if(CURLE_OK != easy->result) {
521         /*
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;
525       }
526       else
527         /* this one still lives! */
528         (*running_handles)++;
529     }
530
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;
534
535       /* now add a node to the Curl_message linked list with this info */
536       msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
537
538       if(!msg)
539         return CURLM_OUT_OF_MEMORY;
540
541       msg->extmsg.msg = CURLMSG_DONE;
542       msg->extmsg.easy_handle = easy->easy_handle;
543       msg->extmsg.data.result = easy->result;
544       msg->next=NULL;
545
546       easy->msg = msg;
547       easy->msg_num = 1; /* there is one unread message here */
548
549       multi->num_msgs++; /* increase message counter */
550     }
551
552     easy = easy->next; /* operate on next handle */
553   }
554
555   return result;
556 }
557
558 CURLMcode curl_multi_cleanup(CURLM *multi_handle)
559 {
560   struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
561   struct Curl_one_easy *easy;
562   struct Curl_one_easy *nexteasy;
563
564   if(GOOD_MULTI_HANDLE(multi)) {
565     multi->type = 0; /* not good anymore */
566     Curl_hash_destroy(multi->hostcache);
567
568     /* remove all easy handles */
569     easy = multi->easy.next;
570     while(easy) {
571       nexteasy=easy->next;
572       /* clear out the usage of the shared DNS cache */
573       easy->easy_handle->hostcache = NULL;
574
575       if (easy->msg)
576         free(easy->msg);
577       free(easy);
578       easy = nexteasy;
579     }
580
581     free(multi);
582
583     return CURLM_OK;
584   }
585   else
586     return CURLM_BAD_HANDLE;
587 }
588
589 CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
590 {
591   struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
592
593   *msgs_in_queue = 0; /* default to none */
594
595   if(GOOD_MULTI_HANDLE(multi)) {
596     struct Curl_one_easy *easy;
597     
598     if(!multi->num_msgs)
599       return NULL; /* no messages left to return */
600
601     easy=multi->easy.next;
602     while(easy) {
603       if(easy->msg_num) {
604         easy->msg_num--;
605         break;
606       }
607       easy = easy->next;
608     }
609     if(!easy)
610       return NULL; /* this means internal count confusion really */
611
612     multi->num_msgs--;
613     *msgs_in_queue = multi->num_msgs;
614
615     return &easy->msg->extmsg;
616   }
617   else
618     return NULL;
619 }