doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
multi.c
Go to the documentation of this file.
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: multi.c,v 1.47 2004/03/11 13:13:35 bagder Exp $
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 {
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 */
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 */
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 */
111 };
112 
113 
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 
126  if(!multi->hostcache) {
127  /* failure, free mem and bail out */
128  free(multi);
129  multi = NULL;
130  }
131  return (CURLM *) multi;
132 }
133 
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 
180 }
181 
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 == (struct SessionHandle *)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 
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;
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 
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;
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((int)sockfd > *max_fd)
283  *max_fd = (int)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 
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 
307 {
308  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
309  struct Curl_one_easy *easy;
310  bool done;
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 #ifdef CURLDEBUG
324  fprintf(stderr, "HANDLE %p: State: %x\n",
325  (char *)easy, easy->state);
326 #endif
327  do {
328  if (CURLM_STATE_WAITCONNECT <= easy->state &&
329  easy->state <= CURLM_STATE_DO &&
330  easy->easy_handle->change.url_changed) {
331  char *gotourl;
333 
334  easy->result = Curl_done(easy->easy_conn);
335  if(CURLE_OK == easy->result) {
336  gotourl = strdup(easy->easy_handle->change.url);
338  easy->result = Curl_follow(easy->easy_handle, gotourl);
339  if(CURLE_OK == easy->result)
340  easy->state = CURLM_STATE_CONNECT;
341  else
342  free(gotourl);
343  }
344  }
345 
347 
348  switch(easy->state) {
349  case CURLM_STATE_INIT:
350  /* init this transfer. */
351  easy->result=Curl_pretransfer(easy->easy_handle);
352 
353  if(CURLE_OK == easy->result) {
354  /* after init, go CONNECT */
355  easy->state = CURLM_STATE_CONNECT;
356  result = CURLM_CALL_MULTI_PERFORM;
357 
358  easy->easy_handle->state.used_interface = Curl_if_multi;
359  }
360  break;
361 
362  case CURLM_STATE_CONNECT:
363  /* Connect. We get a connection identifier filled in. */
365  easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
366  &async);
367 
368  if(CURLE_OK == easy->result) {
369  if(async)
370  /* We're now waiting for an asynchronous name lookup */
372  else {
373  /* after the connect has been sent off, go WAITCONNECT */
375  result = CURLM_CALL_MULTI_PERFORM;
376  }
377  }
378  break;
379 
381  /* awaiting an asynch name resolve to complete */
382  {
383  struct Curl_dns_entry *dns;
384 
385  /* check if we have the name resolved by now */
386  easy->result = Curl_is_resolved(easy->easy_conn, &dns);
387 
388  if(dns) {
389  /* Perform the next step in the connection phase, and then move on
390  to the WAITCONNECT state */
391  easy->result = Curl_async_resolved(easy->easy_conn);
392 
393  if(CURLE_OK != easy->result)
394  /* if Curl_async_resolved() returns failure, the connection struct
395  is already freed and gone */
396  easy->easy_conn = NULL; /* no more connection */
397 
399  }
400 
401  if(CURLE_OK != easy->result) {
402  /* failure detected */
403  Curl_disconnect(easy->easy_conn); /* disconnect properly */
404  easy->easy_conn = NULL; /* no more connection */
405  break;
406  }
407  }
408  break;
409 
411  /* awaiting a completion of an asynch connect */
412  easy->result = Curl_is_connected(easy->easy_conn,
413  easy->easy_conn->sock[FIRSTSOCKET],
414  &connected);
415  if(connected)
416  easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
417 
418  if(CURLE_OK != easy->result) {
419  /* failure detected */
420  Curl_disconnect(easy->easy_conn); /* close the connection */
421  easy->easy_conn = NULL; /* no more connection */
422  break;
423  }
424 
425  if(connected) {
426  /* after the connect has completed, go DO */
427  easy->state = CURLM_STATE_DO;
428  result = CURLM_CALL_MULTI_PERFORM;
429  }
430  break;
431 
432  case CURLM_STATE_DO:
433  /* Do the fetch or put request */
434  easy->result = Curl_do(&easy->easy_conn);
435  if(CURLE_OK == easy->result) {
436 
437  /* after do, go PERFORM... or DO_MORE */
438  if(easy->easy_conn->bits.do_more) {
439  /* we're supposed to do more, but we need to sit down, relax
440  and wait a little while first */
441  easy->state = CURLM_STATE_DO_MORE;
442  result = CURLM_OK;
443  }
444  else {
445  /* we're done with the DO, now PERFORM */
446  easy->result = Curl_readwrite_init(easy->easy_conn);
447  if(CURLE_OK == easy->result) {
448  easy->state = CURLM_STATE_PERFORM;
449  result = CURLM_CALL_MULTI_PERFORM;
450  }
451  }
452  }
453  break;
454 
455  case CURLM_STATE_DO_MORE:
456  /*
457  * First, check if we really are ready to do more.
458  */
459  easy->result =
462  &connected);
463  if(connected) {
464  /*
465  * When we are connected, DO MORE and then go PERFORM
466  */
467  easy->result = Curl_do_more(easy->easy_conn);
468 
469  if(CURLE_OK == easy->result)
470  easy->result = Curl_readwrite_init(easy->easy_conn);
471 
472  if(CURLE_OK == easy->result) {
473  easy->state = CURLM_STATE_PERFORM;
474  result = CURLM_CALL_MULTI_PERFORM;
475  }
476  }
477  break;
478 
479  case CURLM_STATE_PERFORM:
480  /* read/write data if it is ready to do so */
481  easy->result = Curl_readwrite(easy->easy_conn, &done);
482 
483  if(easy->result) {
484  /* The transfer phase returned error, we mark the connection to get
485  * closed to prevent being re-used. This is becasue we can't
486  * possibly know if the connection is in a good shape or not now. */
487  easy->easy_conn->bits.close = TRUE;
488 
490  /* if we failed anywhere, we must clean up the secondary socket if
491  it was used */
493  easy->easy_conn->sock[SECONDARYSOCKET]=-1;
494  }
496  Curl_done(easy->easy_conn);
497  }
498 
499  /* after the transfer is done, go DONE */
500  else if(TRUE == done) {
501 
502  /* call this even if the readwrite function returned error */
504 
505  /* When we follow redirects, must to go back to the CONNECT state */
506  if(easy->easy_conn->newurl) {
507  char *newurl = easy->easy_conn->newurl;
508  easy->easy_conn->newurl = NULL;
509  easy->result = Curl_done(easy->easy_conn);
510  if(easy->result == CURLE_OK)
511  easy->result = Curl_follow(easy->easy_handle, newurl);
512  if(CURLE_OK == easy->result) {
513  easy->state = CURLM_STATE_CONNECT;
514  result = CURLM_CALL_MULTI_PERFORM;
515  }
516  }
517  else {
518  easy->state = CURLM_STATE_DONE;
519  result = CURLM_CALL_MULTI_PERFORM;
520  }
521  }
522  break;
523  case CURLM_STATE_DONE:
524  /* post-transfer command */
525  easy->result = Curl_done(easy->easy_conn);
526 
527  /* after we have DONE what we're supposed to do, go COMPLETED, and
528  it doesn't matter what the Curl_done() returned! */
530  break;
531 
533  /* this is a completed transfer, it is likely to still be connected */
534 
535  /* This node should be delinked from the list now and we should post
536  an information message that we are complete. */
537  break;
538  default:
539  return CURLM_INTERNAL_ERROR;
540  }
541 
542  if(CURLM_STATE_COMPLETED != easy->state) {
543  if(CURLE_OK != easy->result) {
544  /*
545  * If an error was returned, and we aren't in completed state now,
546  * then we go to completed and consider this transfer aborted. */
548  }
549  else
550  /* this one still lives! */
551  (*running_handles)++;
552  }
553 
554  } while (easy->easy_handle->change.url_changed);
555 
556  if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
557  /* clear out the usage of the shared DNS cache */
558  easy->easy_handle->hostcache = NULL;
559 
560  /* now add a node to the Curl_message linked list with this info */
561  msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
562 
563  if(!msg)
564  return CURLM_OUT_OF_MEMORY;
565 
566  msg->extmsg.msg = CURLMSG_DONE;
567  msg->extmsg.easy_handle = easy->easy_handle;
568  msg->extmsg.data.result = easy->result;
569  msg->next=NULL;
570 
571  easy->msg = msg;
572  easy->msg_num = 1; /* there is one unread message here */
573 
574  multi->num_msgs++; /* increase message counter */
575  }
576 
577  easy = easy->next; /* operate on next handle */
578  }
579 
580  return result;
581 }
582 
584 {
585  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
586  struct Curl_one_easy *easy;
587  struct Curl_one_easy *nexteasy;
588 
589  if(GOOD_MULTI_HANDLE(multi)) {
590  multi->type = 0; /* not good anymore */
592 
593  /* remove all easy handles */
594  easy = multi->easy.next;
595  while(easy) {
596  nexteasy=easy->next;
597  /* clear out the usage of the shared DNS cache */
598  easy->easy_handle->hostcache = NULL;
599 
600  if (easy->msg)
601  free(easy->msg);
602  free(easy);
603  easy = nexteasy;
604  }
605 
606  free(multi);
607 
608  return CURLM_OK;
609  }
610  else
611  return CURLM_BAD_HANDLE;
612 }
613 
615 {
616  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
617 
618  *msgs_in_queue = 0; /* default to none */
619 
620  if(GOOD_MULTI_HANDLE(multi)) {
621  struct Curl_one_easy *easy;
622 
623  if(!multi->num_msgs)
624  return NULL; /* no messages left to return */
625 
626  easy=multi->easy.next;
627  while(easy) {
628  if(easy->msg_num) {
629  easy->msg_num--;
630  break;
631  }
632  easy = easy->next;
633  }
634  if(!easy)
635  return NULL; /* this means internal count confusion really */
636 
637  multi->num_msgs--;
638  *msgs_in_queue = multi->num_msgs;
639 
640  return &easy->msg->extmsg;
641  }
642  else
643  return NULL;
644 }
#define GOOD_MULTI_HANDLE(x)
Definition: multi.c:93
CURLcode Curl_pretransfer(struct SessionHandle *data)
Definition: transfer.c:1450
CURLMstate state
Definition: multi.c:79
struct Curl_one_easy easy
Definition: multi.c:103
enum UrlState::@12 used_interface
struct ConnectBits bits
Definition: urldata.h:462
struct Curl_one_easy * next
Definition: multi.c:73
struct connectdata * easy_conn
Definition: multi.c:77
CURLMstate
Definition: multi.c:57
union CURLMsg::@3 data
int curl_socket_t
Definition: setup.h:254
int msg_num
Definition: multi.c:87
struct Curl_message * next
Definition: multi.c:54
void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
Definition: progress.c:126
#define FIRSTSOCKET
Definition: urldata.h:394
CURLcode Curl_posttransfer(struct SessionHandle *data)
Definition: transfer.c:1513
curl_hash * Curl_hash_alloc(int slots, curl_hash_dtor dtor)
Definition: hash.c:95
struct DynamicStatic change
Definition: urldata.h:899
case const int
Definition: Callbacks.cpp:52
#define CURL_MULTI_HANDLE
Definition: multi.c:91
CURLcode Curl_connect(struct SessionHandle *data, struct connectdata **in_connect, bool *asyncp)
Definition: url.c:3217
curl_socket_t sockfd
Definition: urldata.h:493
long type
Definition: multi.c:100
CURLcode
Definition: curl.h:209
int num_easy
Definition: multi.c:105
CURLcode result
Definition: multi.h:100
CURLcode Curl_is_connected(struct connectdata *conn, curl_socket_t sockfd, bool *connected)
Definition: connect.c:437
CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd)
Definition: multi.c:231
#define SECONDARYSOCKET
Definition: urldata.h:395
struct UrlState state
Definition: urldata.h:903
CURLM * curl_multi_init(void)
Definition: multi.c:114
CURLcode Curl_do(struct connectdata **connp)
Definition: url.c:3330
curl_hash * hostcache
Definition: multi.c:110
void Curl_single_fdset(struct connectdata *conn, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd)
Definition: transfer.c:1353
Boolean result
curl_hash * hostcache
Definition: urldata.h:896
struct Curl_one_easy * prev
Definition: multi.c:74
struct CURLMsg extmsg
Definition: multi.c:53
CURLcode Curl_multi_ares_fdset(struct connectdata *conn, fd_set *read_fd_set, fd_set *write_fd_set, int *max_fdp)
Definition: hostip.c:695
CURLM * multi_handle
Definition: fopen.c:81
char * url
Definition: urldata.h:734
CURLcode Curl_protocol_connect(struct connectdata *conn, struct Curl_dns_entry *hostaddr)
Definition: url.c:1931
Definition: hostip.h:40
#define NULL
Definition: Lib.h:88
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
Definition: multi.c:306
CURLcode Curl_follow(struct SessionHandle *data, char *newurl)
Definition: transfer.c:1580
void Curl_freednsinfo(void *freethis)
Definition: hostip.c:443
#define GOOD_EASY_HANDLE(x)
Definition: multi.c:94
CURLcode Curl_async_resolved(struct connectdata *conn)
Definition: url.c:3254
CURL * easy_handle
Definition: multi.h:97
struct Curl_message * msg
Definition: multi.c:82
void Curl_hash_destroy(curl_hash *h)
Definition: hash.c:278
Definition: curl.h:210
char * newurl
Definition: urldata.h:517
bool close
Definition: urldata.h:278
CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle)
Definition: multi.c:134
char * strdup(char *s1)
Definition: main.c:183
#define sclose(x)
Definition: setup.h:220
CURLcode result
Definition: multi.c:80
CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle)
Definition: multi.c:182
CURLMcode
Definition: multi.h:78
CURLMSG msg
Definition: multi.h:96
CURLcode Curl_disconnect(struct connectdata *conn)
Definition: url.c:1313
CURLcode Curl_readwrite(struct connectdata *conn, bool *done)
Definition: transfer.c:193
int num_msgs
Definition: multi.c:107
curl_socket_t sock[2]
Definition: urldata.h:454
CURLMcode curl_multi_cleanup(CURLM *multi_handle)
Definition: multi.c:583
void CURLM
Definition: multi.h:76
CURLcode Curl_do_more(struct connectdata *conn)
Definition: url.c:3388
#define CURL_SOCKET_BAD
Definition: setup.h:255
bool url_changed
Definition: urldata.h:736
CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns)
Definition: hostip.c:684
struct SessionHandle * easy_handle
Definition: multi.c:76
#define FALSE
Definition: mprintf.c:70
Definition: multi.h:80
void CURL
Definition: types.h:25
CURLMsg * curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
Definition: multi.c:614
#define TRUE
Definition: mprintf.c:69
CURLcode Curl_readwrite_init(struct connectdata *conn)
Definition: transfer.c:1274
Definition: multi.h:95
bool do_more
Definition: urldata.h:289
CURLcode Curl_done(struct connectdata *conn)
Definition: url.c:3272