~ubuntu-branches/ubuntu/gutsy/curl/gutsy

« back to all changes in this revision

Viewing changes to lib/multi.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2006-06-29 15:04:24 UTC
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20060629150424-be178abcwks1n519
Tags: upstream-7.15.4
ImportĀ upstreamĀ versionĀ 7.15.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: multi.c,v 1.68 2005/03/08 22:21:59 bagder Exp $
 
21
 * $Id: multi.c,v 1.79 2006-05-27 22:26:16 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
46
46
#include "easyif.h"
47
47
#include "multiif.h"
48
48
#include "sendf.h"
 
49
#include "timeval.h"
49
50
 
50
51
/* The last #include file should be: */
51
52
#include "memdebug.h"
73
74
  CURLM_STATE_LAST /* not a true state, never use this */
74
75
} CURLMstate;
75
76
 
 
77
/* we support 16 sockets per easy handle. Set the corresponding bit to what
 
78
   action we should wait for */
 
79
#define MAX_SOCKSPEREASYHANDLE 16
 
80
#define GETSOCK_READABLE (0x00ff)
 
81
#define GETSOCK_WRITABLE (0xff00)
 
82
 
 
83
struct socketstate {
 
84
  curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
 
85
  unsigned int action; /* socket action bitmap */
 
86
};
 
87
 
76
88
struct Curl_one_easy {
77
89
  /* first, two fields for the linked list of these */
78
90
  struct Curl_one_easy *next;
90
102
                               will be deleted when this handle is removed
91
103
                               from the multi-handle */
92
104
  int msg_num; /* number of messages left in 'msg' to return */
 
105
 
 
106
  struct socketstate sockstate; /* for the socket API magic */
93
107
};
94
108
 
95
 
 
96
109
#define CURL_MULTI_HANDLE 0x000bab1e
97
110
 
98
 
#define GOOD_MULTI_HANDLE(x) ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE))
 
111
#define GOOD_MULTI_HANDLE(x) \
 
112
  ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE))
99
113
#define GOOD_EASY_HANDLE(x) (x)
100
114
 
101
115
/* This is the struct known as CURLM on the outside */
111
125
 
112
126
  int num_msgs; /* total amount of messages in the easy handles */
113
127
 
 
128
  /* callback function and user data pointer for the *socket() API */
 
129
  curl_socket_callback socket_cb;
 
130
  void *socket_userp;
 
131
 
114
132
  /* Hostname cache */
115
133
  struct curl_hash *hostcache;
 
134
 
 
135
  /* timetree points to the splay-tree of time nodes to figure out expire
 
136
     times of all currently set timers */
 
137
  struct Curl_tree *timetree;
 
138
 
 
139
  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
 
140
     the pluralis form, there can be more than one easy handle waiting on the
 
141
     same actual socket) */
 
142
  struct curl_hash *sockhash;
116
143
};
117
144
 
118
145
/* always use this function to change state, to make debugging easier */
134
161
  };
135
162
  CURLMstate oldstate = easy->state;
136
163
#endif
 
164
 
137
165
  easy->state = state;
138
166
 
139
167
#ifdef CURLDEBUG
143
171
#endif
144
172
}
145
173
 
 
174
/*
 
175
 * We add one of these structs to the sockhash for a particular socket
 
176
 */
 
177
 
 
178
struct Curl_sh_entry {
 
179
  struct SessionHandle *easy;
 
180
  time_t timestamp;
 
181
  long inuse;
 
182
  int action;  /* what action READ/WRITE this socket waits for */
 
183
  void *userp; /* settable by users (not yet decided exactly how) */
 
184
};
 
185
/* bits for 'action' having no bits means this socket is not expecting any
 
186
   action */
 
187
#define SH_READ  1
 
188
#define SH_WRITE 2
 
189
 
 
190
/* make sure this socket is present in the hash for this handle */
 
191
static int sh_addentry(struct curl_hash *sh,
 
192
                       curl_socket_t s,
 
193
                       struct SessionHandle *data)
 
194
{
 
195
  struct Curl_sh_entry *there =
 
196
    Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
 
197
  struct Curl_sh_entry *check;
 
198
 
 
199
  if(there)
 
200
    /* it is present, return fine */
 
201
    return 0;
 
202
 
 
203
  /* not present, add it */
 
204
  check = calloc(sizeof(struct Curl_sh_entry), 1);
 
205
  if(!check)
 
206
    return 1; /* major failure */
 
207
  check->easy = data;
 
208
 
 
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 */
 
212
 
 
213
  return 0; /* things are good in sockhash land */
 
214
}
 
215
 
 
216
 
 
217
/* delete the given socket + handle from the hash */
 
218
static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
 
219
{
 
220
  struct Curl_sh_entry *there =
 
221
    Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
 
222
 
 
223
  if(there) {
 
224
    /* this socket is in the hash */
 
225
    /* We remove the hash entry. (This'll end up in a call to
 
226
       sh_freeentry().) */
 
227
    Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
 
228
  }
 
229
}
 
230
 
 
231
/*
 
232
 * free a sockhash entry
 
233
 */
 
234
static void sh_freeentry(void *freethis)
 
235
{
 
236
  struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
 
237
 
 
238
  free(p);
 
239
}
 
240
 
 
241
/*
 
242
 * sh_init() creates a new socket hash and returns the handle for it.
 
243
 *
 
244
 * Quote from README.multi_socket:
 
245
 *
 
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
 
256
 * per call."
 
257
 *
 
258
 */
 
259
static struct curl_hash *sh_init(void)
 
260
{
 
261
  return Curl_hash_alloc(97, sh_freeentry);
 
262
}
 
263
 
146
264
CURLM *curl_multi_init(void)
147
265
{
148
 
  struct Curl_multi *multi;
149
 
 
150
 
  multi = (void *)malloc(sizeof(struct Curl_multi));
151
 
 
152
 
  if(multi) {
153
 
    memset(multi, 0, sizeof(struct Curl_multi));
154
 
    multi->type = CURL_MULTI_HANDLE;
155
 
  }
156
 
  else
 
266
  struct Curl_multi *multi = (void *)calloc(sizeof(struct Curl_multi), 1);
 
267
 
 
268
  if(!multi)
157
269
    return NULL;
158
270
 
 
271
  multi->type = CURL_MULTI_HANDLE;
 
272
 
159
273
  multi->hostcache = Curl_mk_dnscache();
160
274
  if(!multi->hostcache) {
161
275
    /* failure, free mem and bail out */
162
276
    free(multi);
163
 
    multi = NULL;
164
 
  }
 
277
    return NULL;
 
278
  }
 
279
 
 
280
  multi->sockhash = sh_init();
 
281
  if(!multi->sockhash) {
 
282
    /* failure, free mem and bail out */
 
283
    Curl_hash_destroy(multi->hostcache);
 
284
    free(multi);
 
285
    return NULL;
 
286
  }
 
287
 
165
288
  return (CURLM *) multi;
166
289
}
167
290
 
170
293
{
171
294
  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
172
295
  struct Curl_one_easy *easy;
 
296
  int i;
173
297
 
174
298
  /* First, make some basic checks that the CURLM handle is a good handle */
175
299
  if(!GOOD_MULTI_HANDLE(multi))
180
304
    return CURLM_BAD_EASY_HANDLE;
181
305
 
182
306
  /* Now, time to add an easy handle to the multi stack */
183
 
  easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
 
307
  easy = (struct Curl_one_easy *)calloc(sizeof(struct Curl_one_easy), 1);
184
308
  if(!easy)
185
309
    return CURLM_OUT_OF_MEMORY;
186
310
 
187
 
  /* clean it all first (just to be sure) */
188
 
  memset(easy, 0, sizeof(struct Curl_one_easy));
 
311
  for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
 
312
    easy->sockstate.socks[i] = CURL_SOCKET_BAD;
189
313
 
190
314
  /* set the easy handle */
191
315
  easy->easy_handle = easy_handle;
192
316
  multistate(easy, CURLM_STATE_INIT);
193
317
 
194
 
  /* for multi interface connections, we share DNS cache automaticly */
 
318
  /* for multi interface connections, we share DNS cache automaticly.
 
319
     First kill the existing one if there is any. */
 
320
  if (easy->easy_handle->hostcache &&
 
321
      easy->easy_handle->hostcache != multi->hostcache)
 
322
    Curl_hash_destroy(easy->easy_handle->hostcache);
 
323
 
195
324
  easy->easy_handle->hostcache = multi->hostcache;
196
325
 
197
326
  /* We add this new entry first in the list. We make our 'next' point to the
209
338
 
210
339
  Curl_easy_addmulti(easy_handle, multi_handle);
211
340
 
 
341
  /* make the SessionHandle struct refer back to this struct */
 
342
  easy->easy_handle->set.one_easy = easy;
 
343
 
212
344
  /* increase the node-counter */
213
345
  multi->num_easy++;
214
346
 
245
377
    Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association
246
378
                                                    to this multi handle */
247
379
 
 
380
    /* if we have a connection we must call Curl_done() here so that we
 
381
       don't leave a half-baked one around */
 
382
    if(easy->easy_conn)
 
383
      Curl_done(&easy->easy_conn, easy->result);
 
384
 
248
385
    /* make the previous node point to our next */
249
386
    if(easy->prev)
250
387
      easy->prev->next = easy->next;
252
389
    if(easy->next)
253
390
      easy->next->prev = easy->prev;
254
391
 
 
392
    easy->easy_handle->set.one_easy = NULL; /* detached */
 
393
 
255
394
    /* NOTE NOTE NOTE
256
395
       We do not touch the easy handle here! */
257
396
    if (easy->msg)
266
405
    return CURLM_BAD_EASY_HANDLE; /* twasn't found */
267
406
}
268
407
 
 
408
static int waitconnect_getsock(struct connectdata *conn,
 
409
                               curl_socket_t *sock,
 
410
                               int numsocks)
 
411
{
 
412
  if(!numsocks)
 
413
    return GETSOCK_BLANK;
 
414
 
 
415
  sock[0] = conn->sock[FIRSTSOCKET];
 
416
  return GETSOCK_WRITESOCK(0);
 
417
}
 
418
 
 
419
static int domore_getsock(struct connectdata *conn,
 
420
                          curl_socket_t *sock,
 
421
                          int numsocks)
 
422
{
 
423
  if(!numsocks)
 
424
    return GETSOCK_BLANK;
 
425
 
 
426
  /* When in DO_MORE state, we could be either waiting for us
 
427
     to connect to a remote site, or we could wait for that site
 
428
     to connect to us. It makes a difference in the way: if we
 
429
     connect to the site we wait for the socket to become writable, if
 
430
     the site connects to us we wait for it to become readable */
 
431
  sock[0] = conn->sock[SECONDARYSOCKET];
 
432
 
 
433
  return GETSOCK_WRITESOCK(0);
 
434
}
 
435
 
 
436
/* returns bitmapped flags for this handle and its sockets */
 
437
static int multi_getsock(struct Curl_one_easy *easy,
 
438
                         curl_socket_t *socks, /* points to numsocks number
 
439
                                                 of sockets */
 
440
                         int numsocks)
 
441
{
 
442
  switch(easy->state) {
 
443
  default:
 
444
    return 0;
 
445
 
 
446
  case CURLM_STATE_WAITRESOLVE:
 
447
    return Curl_resolv_getsock(easy->easy_conn, socks, numsocks);
 
448
 
 
449
  case CURLM_STATE_PROTOCONNECT:
 
450
    return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
 
451
 
 
452
  case CURLM_STATE_DOING:
 
453
    return Curl_doing_getsock(easy->easy_conn, socks, numsocks);
 
454
 
 
455
  case CURLM_STATE_WAITCONNECT:
 
456
    return waitconnect_getsock(easy->easy_conn, socks, numsocks);
 
457
 
 
458
  case CURLM_STATE_DO_MORE:
 
459
    return domore_getsock(easy->easy_conn, socks, numsocks);
 
460
 
 
461
  case CURLM_STATE_PERFORM:
 
462
    return Curl_single_getsock(easy->easy_conn, socks, numsocks);
 
463
  }
 
464
 
 
465
}
 
466
 
269
467
CURLMcode curl_multi_fdset(CURLM *multi_handle,
270
468
                           fd_set *read_fd_set, fd_set *write_fd_set,
271
469
                           fd_set *exc_fd_set, int *max_fd)
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];
 
478
  int bitmap;
 
479
  int i;
 
480
  (void)exc_fd_set; /* not used */
279
481
 
280
482
  if(!GOOD_MULTI_HANDLE(multi))
281
483
    return CURLM_BAD_HANDLE;
282
484
 
283
 
  *max_fd = -1; /* so far none! */
284
 
 
285
485
  easy=multi->easy.next;
286
486
  while(easy) {
287
 
    switch(easy->state) {
288
 
    default:
289
 
      break;
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,
293
 
                        &this_max_fd);
294
 
      if(this_max_fd > *max_fd)
295
 
        *max_fd = this_max_fd;
296
 
      break;
297
 
 
298
 
    case CURLM_STATE_PROTOCONNECT:
299
 
      Curl_protocol_fdset(easy->easy_conn, read_fd_set, write_fd_set,
300
 
                          &this_max_fd);
301
 
      if(this_max_fd > *max_fd)
302
 
        *max_fd = this_max_fd;
303
 
      break;
304
 
 
305
 
    case CURLM_STATE_DOING:
306
 
      Curl_doing_fdset(easy->easy_conn, read_fd_set, write_fd_set,
307
 
                       &this_max_fd);
308
 
      if(this_max_fd > *max_fd)
309
 
        *max_fd = this_max_fd;
310
 
      break;
311
 
 
312
 
    case CURLM_STATE_WAITCONNECT:
313
 
    case CURLM_STATE_DO_MORE:
314
 
      {
315
 
        /* when we're waiting for a connect, we wait for the socket to
316
 
           become writable */
317
 
        struct connectdata *conn = easy->easy_conn;
318
 
        curl_socket_t sockfd;
319
 
 
320
 
        if(CURLM_STATE_WAITCONNECT == easy->state) {
321
 
          sockfd = conn->sock[FIRSTSOCKET];
322
 
          FD_SET(sockfd, write_fd_set);
323
 
        }
324
 
        else {
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);
332
 
        }
333
 
 
334
 
        if((int)sockfd > *max_fd)
335
 
          *max_fd = (int)sockfd;
336
 
      }
337
 
      break;
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 */
341
 
 
342
 
      Curl_single_fdset(easy->easy_conn,
343
 
                        read_fd_set, write_fd_set,
344
 
                        exc_fd_set, &this_max_fd);
345
 
 
346
 
      /* remember the maximum file descriptor */
347
 
      if(this_max_fd > *max_fd)
348
 
        *max_fd = this_max_fd;
349
 
 
350
 
      break;
 
487
    bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
 
488
 
 
489
    for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
 
490
      curl_socket_t s = CURL_SOCKET_BAD;
 
491
 
 
492
      if(bitmap & GETSOCK_READSOCK(i)) {
 
493
        FD_SET(sockbunch[i], read_fd_set);
 
494
        s = sockbunch[i];
 
495
      }
 
496
      if(bitmap & GETSOCK_WRITESOCK(i)) {
 
497
        FD_SET(sockbunch[i], write_fd_set);
 
498
        s = sockbunch[i];
 
499
      }
 
500
      if(s == CURL_SOCKET_BAD)
 
501
        /* this socket is unused, break out of loop */
 
502
        break;
 
503
      else {
 
504
        if(s > (curl_socket_t)this_max_fd)
 
505
          this_max_fd = (int)s;
 
506
      }
351
507
    }
 
508
 
352
509
    easy = easy->next; /* check next handle */
353
510
  }
354
511
 
 
512
  *max_fd = this_max_fd;
 
513
 
355
514
  return CURLM_OK;
356
515
}
357
516
 
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)
359
520
{
360
 
  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
361
 
  struct Curl_one_easy *easy;
362
 
  bool done;
363
 
  CURLMcode result=CURLM_OK;
364
521
  struct Curl_message *msg = NULL;
365
522
  bool connected;
366
523
  bool async;
367
524
  bool protocol_connect;
368
525
  bool dophase_done;
369
 
 
370
 
  *running_handles = 0; /* bump this once for every living handle */
371
 
 
372
 
  if(!GOOD_MULTI_HANDLE(multi))
373
 
    return CURLM_BAD_HANDLE;
374
 
 
375
 
  easy=multi->easy.next;
376
 
  while(easy) {
377
 
    do {
378
 
      if (CURLM_STATE_WAITCONNECT <= easy->state &&
379
 
          easy->state <= CURLM_STATE_DO &&
380
 
          easy->easy_handle->change.url_changed) {
381
 
        char *gotourl;
382
 
        Curl_posttransfer(easy->easy_handle);
383
 
 
384
 
        easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
385
 
        if(CURLE_OK == easy->result) {
386
 
          gotourl = strdup(easy->easy_handle->change.url);
387
 
          if(gotourl) {
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);
392
 
            else
393
 
              free(gotourl);
394
 
          }
395
 
          else {
396
 
            easy->result = CURLE_OUT_OF_MEMORY;
397
 
            multistate(easy, CURLM_STATE_COMPLETED);
398
 
            break;
399
 
          }
400
 
        }
401
 
      }
402
 
 
403
 
      easy->easy_handle->change.url_changed = FALSE;
404
 
 
405
 
      switch(easy->state) {
406
 
      case CURLM_STATE_INIT:
407
 
        /* init this transfer. */
408
 
        easy->result=Curl_pretransfer(easy->easy_handle);
409
 
 
410
 
        if(CURLE_OK == easy->result) {
411
 
          /* after init, go CONNECT */
412
 
          multistate(easy, CURLM_STATE_CONNECT);
 
526
  bool done;
 
527
  CURLMcode result = CURLM_OK;
 
528
 
 
529
  do {
 
530
    if (CURLM_STATE_WAITCONNECT <= easy->state &&
 
531
        easy->state <= CURLM_STATE_DO &&
 
532
        easy->easy_handle->change.url_changed) {
 
533
      char *gotourl;
 
534
      Curl_posttransfer(easy->easy_handle);
 
535
 
 
536
      easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
 
537
      if(CURLE_OK == easy->result) {
 
538
        gotourl = strdup(easy->easy_handle->change.url);
 
539
        if(gotourl) {
 
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);
 
544
          else
 
545
            free(gotourl);
 
546
        }
 
547
        else {
 
548
          easy->result = CURLE_OUT_OF_MEMORY;
 
549
          multistate(easy, CURLM_STATE_COMPLETED);
 
550
          break;
 
551
        }
 
552
      }
 
553
    }
 
554
 
 
555
    easy->easy_handle->change.url_changed = FALSE;
 
556
 
 
557
    switch(easy->state) {
 
558
    case CURLM_STATE_INIT:
 
559
      /* init this transfer. */
 
560
      easy->result=Curl_pretransfer(easy->easy_handle);
 
561
 
 
562
      if(CURLE_OK == easy->result) {
 
563
        /* after init, go CONNECT */
 
564
        multistate(easy, CURLM_STATE_CONNECT);
 
565
        result = CURLM_CALL_MULTI_PERFORM;
 
566
 
 
567
        easy->easy_handle->state.used_interface = Curl_if_multi;
 
568
      }
 
569
      break;
 
570
 
 
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);
 
576
 
 
577
      if(CURLE_OK == easy->result) {
 
578
        if(async)
 
579
          /* We're now waiting for an asynchronous name lookup */
 
580
          multistate(easy, CURLM_STATE_WAITRESOLVE);
 
581
        else {
 
582
          /* after the connect has been sent off, go WAITCONNECT unless the
 
583
             protocol connect is already done and we can go directly to
 
584
             DO! */
413
585
          result = CURLM_CALL_MULTI_PERFORM;
414
586
 
415
 
          easy->easy_handle->state.used_interface = Curl_if_multi;
416
 
        }
417
 
        break;
418
 
 
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);
424
 
 
425
 
        if(CURLE_OK == easy->result) {
426
 
          if(async)
427
 
            /* We're now waiting for an asynchronous name lookup */
428
 
            multistate(easy, CURLM_STATE_WAITRESOLVE);
429
 
          else {
430
 
            /* after the connect has been sent off, go WAITCONNECT unless the
431
 
               protocol connect is already done and we can go directly to
432
 
               DO! */
433
 
            result = CURLM_CALL_MULTI_PERFORM;
434
 
 
435
 
            if(protocol_connect)
436
 
              multistate(easy, CURLM_STATE_DO);
437
 
            else
438
 
              multistate(easy, CURLM_STATE_WAITCONNECT);
439
 
          }
440
 
        }
441
 
        break;
442
 
 
443
 
      case CURLM_STATE_WAITRESOLVE:
444
 
        /* awaiting an asynch name resolve to complete */
445
 
      {
446
 
        struct Curl_dns_entry *dns = NULL;
447
 
 
448
 
        /* check if we have the name resolved by now */
449
 
        easy->result = Curl_is_resolved(easy->easy_conn, &dns);
450
 
 
451
 
        if(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,
 
587
          if(protocol_connect)
 
588
            multistate(easy, CURLM_STATE_DO);
 
589
          else
 
590
            multistate(easy, CURLM_STATE_WAITCONNECT);
 
591
        }
 
592
      }
 
593
      break;
 
594
 
 
595
    case CURLM_STATE_WAITRESOLVE:
 
596
      /* awaiting an asynch name resolve to complete */
 
597
    {
 
598
      struct Curl_dns_entry *dns = NULL;
 
599
 
 
600
      /* check if we have the name resolved by now */
 
601
      easy->result = Curl_is_resolved(easy->easy_conn, &dns);
 
602
 
 
603
      if(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,
 
607
                                           &protocol_connect);
 
608
 
 
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 */
 
613
        else {
 
614
          /* FIX: what if protocol_connect is TRUE here?! */
 
615
          multistate(easy, CURLM_STATE_WAITCONNECT);
 
616
        }
 
617
      }
 
618
 
 
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 */
 
623
        break;
 
624
      }
 
625
    }
 
626
    break;
 
627
 
 
628
    case CURLM_STATE_WAITCONNECT:
 
629
      /* awaiting a completion of an asynch connect */
 
630
      easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
 
631
                                       &connected);
 
632
      if(connected)
 
633
        easy->result = Curl_protocol_connect(easy->easy_conn,
455
634
                                             &protocol_connect);
456
635
 
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 */
461
 
          else {
462
 
            /* FIX: what if protocol_connect is TRUE here?! */
463
 
            multistate(easy, CURLM_STATE_WAITCONNECT);
464
 
          }
465
 
        }
466
 
 
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 */
471
 
          break;
472
 
        }
 
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 */
 
640
        break;
473
641
      }
474
 
      break;
475
 
 
476
 
      case CURLM_STATE_WAITCONNECT:
477
 
        /* awaiting a completion of an asynch connect */
478
 
        easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
479
 
                                         &connected);
480
 
        if(connected)
481
 
          easy->result = Curl_protocol_connect(easy->easy_conn,
482
 
                                               &protocol_connect);
483
 
 
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 */
488
 
          break;
489
 
        }
490
 
 
491
 
        if(connected) {
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);
497
 
          }
498
 
          else {
499
 
            /* after the connect has completed, go DO */
500
 
            multistate(easy, CURLM_STATE_DO);
501
 
            result = CURLM_CALL_MULTI_PERFORM;
502
 
          }
503
 
        }
504
 
        break;
505
 
 
506
 
      case CURLM_STATE_PROTOCONNECT:
507
 
        /* protocol-specific connect phase */
508
 
        easy->result = Curl_protocol_connecting(easy->easy_conn,
509
 
                                                &protocol_connect);
510
 
        if(protocol_connect) {
 
642
 
 
643
      if(connected) {
 
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);
 
649
        }
 
650
        else {
511
651
          /* after the connect has completed, go DO */
512
652
          multistate(easy, CURLM_STATE_DO);
513
653
          result = CURLM_CALL_MULTI_PERFORM;
514
654
        }
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 */
521
 
        }
522
 
        break;
523
 
 
524
 
      case CURLM_STATE_DO:
 
655
      }
 
656
      break;
 
657
 
 
658
    case CURLM_STATE_PROTOCONNECT:
 
659
      /* protocol-specific connect phase */
 
660
      easy->result = Curl_protocol_connecting(easy->easy_conn,
 
661
                                              &protocol_connect);
 
662
      if(protocol_connect) {
 
663
        /* after the connect has completed, go DO */
 
664
        multistate(easy, CURLM_STATE_DO);
 
665
        result = CURLM_CALL_MULTI_PERFORM;
 
666
      }
 
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 */
 
673
      }
 
674
      break;
 
675
 
 
676
    case CURLM_STATE_DO:
 
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;
 
682
        result = CURLM_OK;
 
683
      }
 
684
      else {
525
685
        /* Perform the protocol's DO action */
526
686
        easy->result = Curl_do(&easy->easy_conn, &dophase_done);
527
687
 
557
717
          Curl_disconnect(easy->easy_conn); /* close the connection */
558
718
          easy->easy_conn = NULL;           /* no more connection */
559
719
        }
560
 
        break;
561
 
 
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);
 
720
      }
 
721
      break;
 
722
 
 
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) {
 
727
        if(dophase_done) {
 
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);
 
733
            result = CURLM_OK;
 
734
          }
 
735
          else {
 
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;
 
741
            }
 
742
          }
 
743
        } /* dophase_done */
 
744
      }
 
745
      else {
 
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 */
 
751
      }
 
752
      break;
 
753
 
 
754
    case CURLM_STATE_DO_MORE:
 
755
      /* Ready to do more? */
 
756
      easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
 
757
                                       &connected);
 
758
      if(connected) {
 
759
        /*
 
760
         * When we are connected, DO MORE and then go PERFORM
 
761
         */
 
762
        easy->result = Curl_do_more(easy->easy_conn);
 
763
 
 
764
        if(CURLE_OK == easy->result)
 
765
          easy->result = Curl_readwrite_init(easy->easy_conn);
 
766
 
565
767
        if(CURLE_OK == easy->result) {
566
 
          if(dophase_done) {
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);
572
 
              result = CURLM_OK;
573
 
            }
574
 
            else {
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;
580
 
              }
581
 
            }
582
 
          } /* dophase_done */
583
 
        }
584
 
        else {
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 */
590
 
        }
591
 
        break;
592
 
 
593
 
      case CURLM_STATE_DO_MORE:
594
 
        /* Ready to do more? */
595
 
        easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
596
 
                                         &connected);
597
 
        if(connected) {
598
 
          /*
599
 
           * When we are connected, DO MORE and then go PERFORM
600
 
           */
601
 
          easy->result = Curl_do_more(easy->easy_conn);
602
 
 
603
 
          if(CURLE_OK == easy->result)
604
 
            easy->result = Curl_readwrite_init(easy->easy_conn);
605
 
 
 
768
          multistate(easy, CURLM_STATE_PERFORM);
 
769
          result = CURLM_CALL_MULTI_PERFORM;
 
770
        }
 
771
      }
 
772
      break;
 
773
 
 
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);
 
777
 
 
778
      if(easy->result)  {
 
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;
 
783
 
 
784
        if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
 
785
          /* if we failed anywhere, we must clean up the secondary socket if
 
786
             it was used */
 
787
          sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
 
788
          easy->easy_conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
 
789
        }
 
790
        Curl_posttransfer(easy->easy_handle);
 
791
        Curl_done(&easy->easy_conn, easy->result);
 
792
      }
 
793
 
 
794
      else if(TRUE == done) {
 
795
        char *newurl;
 
796
        bool retry = Curl_retry_request(easy->easy_conn, &newurl);
 
797
 
 
798
        /* call this even if the readwrite function returned error */
 
799
        Curl_posttransfer(easy->easy_handle);
 
800
 
 
801
        /* When we follow redirects, must to go back to the CONNECT state */
 
802
        if(easy->easy_conn->newurl || retry) {
 
803
          if(!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;
 
808
          }
 
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;
609
 
          }
610
 
        }
611
 
        break;
612
 
 
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);
616
 
 
617
 
        if(easy->result)  {
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;
622
 
 
623
 
          if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
624
 
            /* if we failed anywhere, we must clean up the secondary socket if
625
 
               it was used */
626
 
            sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
627
 
            easy->easy_conn->sock[SECONDARYSOCKET]=-1;
628
 
          }
629
 
          Curl_posttransfer(easy->easy_handle);
630
 
          Curl_done(&easy->easy_conn, easy->result);
631
 
        }
632
 
 
633
 
        else if(TRUE == done) {
634
 
          char *newurl;
635
 
          bool retry = Curl_retry_request(easy->easy_conn, &newurl);
636
 
 
637
 
          /* call this even if the readwrite function returned error */
638
 
          Curl_posttransfer(easy->easy_handle);
639
 
 
640
 
          /* When we follow redirects, must to go back to the CONNECT state */
641
 
          if(easy->easy_conn->newurl || retry) {
642
 
            if(!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;
647
 
            }
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;
654
 
            }
655
 
            else
656
 
              /* Since we "took it", we are in charge of freeing this on
657
 
                 failure */
658
 
              free(newurl);
659
 
          }
660
 
          else {
661
 
            /* after the transfer is done, go DONE */
662
 
            multistate(easy, CURLM_STATE_DONE);
663
 
            result = CURLM_CALL_MULTI_PERFORM;
664
 
          }
665
 
        }
666
 
        break;
667
 
      case CURLM_STATE_DONE:
668
 
        /* post-transfer command */
669
 
        easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
670
 
 
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;
 
815
          }
 
816
          else
 
817
            /* Since we "took it", we are in charge of freeing this on
 
818
               failure */
 
819
            free(newurl);
 
820
        }
 
821
        else {
 
822
          /* after the transfer is done, go DONE */
 
823
          multistate(easy, CURLM_STATE_DONE);
 
824
          result = CURLM_CALL_MULTI_PERFORM;
 
825
        }
 
826
      }
 
827
      break;
 
828
    case CURLM_STATE_DONE:
 
829
      /* post-transfer command */
 
830
      easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
 
831
 
 
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);
 
835
      break;
 
836
 
 
837
    case CURLM_STATE_COMPLETED:
 
838
      /* this is a completed transfer, it is likely to still be connected */
 
839
 
 
840
      /* This node should be delinked from the list now and we should post
 
841
         an information message that we are complete. */
 
842
      break;
 
843
    default:
 
844
      return CURLM_INTERNAL_ERROR;
 
845
    }
 
846
 
 
847
    if(CURLM_STATE_COMPLETED != easy->state) {
 
848
      if(CURLE_OK != easy->result) {
 
849
        /*
 
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);
674
 
        break;
675
 
 
676
 
      case CURLM_STATE_COMPLETED:
677
 
        /* this is a completed transfer, it is likely to still be connected */
678
 
 
679
 
        /* This node should be delinked from the list now and we should post
680
 
           an information message that we are complete. */
681
 
        break;
682
 
      default:
683
 
        return CURLM_INTERNAL_ERROR;
684
 
      }
685
 
 
686
 
      if(CURLM_STATE_COMPLETED != easy->state) {
687
 
        if(CURLE_OK != easy->result) {
688
 
          /*
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);
692
 
        }
693
 
        else
694
 
          /* this one still lives! */
695
 
          (*running_handles)++;
696
 
      }
697
 
 
698
 
    } while (easy->easy_handle->change.url_changed);
699
 
 
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;
703
 
 
704
 
      /* now add a node to the Curl_message linked list with this info */
705
 
      msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
706
 
 
707
 
      if(!msg)
708
 
        return CURLM_OUT_OF_MEMORY;
709
 
 
710
 
      msg->extmsg.msg = CURLMSG_DONE;
711
 
      msg->extmsg.easy_handle = easy->easy_handle;
712
 
      msg->extmsg.data.result = easy->result;
713
 
      msg->next=NULL;
714
 
 
715
 
      easy->msg = msg;
716
 
      easy->msg_num = 1; /* there is one unread message here */
717
 
 
718
 
      multi->num_msgs++; /* increase message counter */
 
853
      }
 
854
      else
 
855
        /* this one still lives! */
 
856
        (*running_handles)++;
719
857
    }
 
858
 
 
859
  } while (easy->easy_handle->change.url_changed);
 
860
 
 
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;
 
864
 
 
865
    /* now add a node to the Curl_message linked list with this info */
 
866
    msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
 
867
 
 
868
    if(!msg)
 
869
      return CURLM_OUT_OF_MEMORY;
 
870
 
 
871
    msg->extmsg.msg = CURLMSG_DONE;
 
872
    msg->extmsg.easy_handle = easy->easy_handle;
 
873
    msg->extmsg.data.result = easy->result;
 
874
    msg->next=NULL;
 
875
 
 
876
    easy->msg = msg;
 
877
    easy->msg_num = 1; /* there is one unread message here */
 
878
 
 
879
    multi->num_msgs++; /* increase message counter */
 
880
  }
 
881
 
 
882
  return result;
 
883
}
 
884
 
 
885
 
 
886
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
 
887
{
 
888
  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
 
889
  struct Curl_one_easy *easy;
 
890
  CURLMcode returncode=CURLM_OK;
 
891
  struct Curl_tree *t;
 
892
 
 
893
  *running_handles = 0; /* bump this once for every living handle */
 
894
 
 
895
  if(!GOOD_MULTI_HANDLE(multi))
 
896
    return CURLM_BAD_HANDLE;
 
897
 
 
898
  easy=multi->easy.next;
 
899
  while(easy) {
 
900
    CURLMcode result = multi_runsingle(multi, easy, running_handles);
 
901
    if(result)
 
902
      returncode = result;
 
903
 
720
904
    easy = easy->next; /* operate on next handle */
721
905
  }
722
906
 
723
 
  return result;
 
907
  /*
 
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.
 
911
   */
 
912
  do {
 
913
    struct timeval now = Curl_tvnow();
 
914
    int key = now.tv_sec; /* drop the usec part */
 
915
 
 
916
    multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
 
917
  } while(t);
 
918
 
 
919
  return returncode;
724
920
}
725
921
 
726
922
/* This is called when an easy handle is cleanup'ed that is part of a multi
739
935
  if(GOOD_MULTI_HANDLE(multi)) {
740
936
    multi->type = 0; /* not good anymore */
741
937
    Curl_hash_destroy(multi->hostcache);
 
938
    Curl_hash_destroy(multi->sockhash);
742
939
 
743
940
    /* remove all easy handles */
744
941
    easy = multi->easy.next;
793
990
  else
794
991
    return NULL;
795
992
}
 
993
 
 
994
/*
 
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.
 
998
 */
 
999
static void singlesocket(struct Curl_multi *multi,
 
1000
                         struct Curl_one_easy *easy)
 
1001
{
 
1002
  struct socketstate current;
 
1003
  int i;
 
1004
 
 
1005
  memset(&current, 0, sizeof(current));
 
1006
  for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
 
1007
    current.socks[i] = CURL_SOCKET_BAD;
 
1008
 
 
1009
  /* first fill in the 'current' struct with the state as it is now */
 
1010
  current.action = multi_getsock(easy, current.socks, MAX_SOCKSPEREASYHANDLE);
 
1011
 
 
1012
  /* when filled in, we compare with the previous round's state in a first
 
1013
     quick memory compare check */
 
1014
  if(memcmp(&current, &easy->sockstate, sizeof(struct socketstate))) {
 
1015
 
 
1016
    /* there is difference, call the callback once for every socket change ! */
 
1017
    for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
 
1018
      int action;
 
1019
      curl_socket_t s = current.socks[i];
 
1020
 
 
1021
      /* Ok, this approach is probably too naive and simple-minded but
 
1022
         it might work for a start */
 
1023
 
 
1024
      if((easy->sockstate.socks[i] == CURL_SOCKET_BAD) &&
 
1025
         (s == CURL_SOCKET_BAD)) {
 
1026
        /* no socket now and there was no socket before */
 
1027
        break;
 
1028
      }
 
1029
 
 
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 */
 
1034
      }
 
1035
      else {
 
1036
        if(easy->sockstate.socks[i] == s) {
 
1037
          /* still the same socket, but are we waiting for the same actions? */
 
1038
          unsigned int curr;
 
1039
          unsigned int prev;
 
1040
 
 
1041
          /* the current read/write bits for this particular socket */
 
1042
          curr = current.action & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i));
 
1043
 
 
1044
          /* the previous read/write bits for this particular socket */
 
1045
          prev = easy->sockstate.action &
 
1046
            (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i));
 
1047
 
 
1048
          if(curr == prev)
 
1049
            continue;
 
1050
        }
 
1051
 
 
1052
        action = ((current.action & GETSOCK_READSOCK(i))?CURL_POLL_IN:0) |
 
1053
          ((current.action & GETSOCK_WRITESOCK(i))?CURL_POLL_OUT:0);
 
1054
      }
 
1055
 
 
1056
      /* call the callback with this new info */
 
1057
      if(multi->socket_cb) {
 
1058
        multi->socket_cb(easy->easy_handle,
 
1059
                         s,
 
1060
                         action,
 
1061
                         multi->socket_userp);
 
1062
      }
 
1063
 
 
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);
 
1068
      else
 
1069
        /* make sure this socket is present in the hash for this handle */
 
1070
        sh_addentry(multi->sockhash, s, easy->easy_handle);
 
1071
    }
 
1072
    /* copy the current state to the storage area */
 
1073
    memcpy(&easy->sockstate, &current, sizeof(struct socketstate));
 
1074
  }
 
1075
  else {
 
1076
    /* identical, nothing new happened so we don't do any callbacks */
 
1077
  }
 
1078
 
 
1079
}
 
1080
 
 
1081
static CURLMcode multi_socket(struct Curl_multi *multi,
 
1082
                              bool checkall,
 
1083
                              curl_socket_t s)
 
1084
{
 
1085
  CURLMcode result = CURLM_OK;
 
1086
  int running_handles;
 
1087
  struct SessionHandle *data = NULL;
 
1088
  struct Curl_tree *t;
 
1089
 
 
1090
  if(checkall) {
 
1091
    struct Curl_one_easy *easyp;
 
1092
    result = curl_multi_perform(multi, &running_handles);
 
1093
 
 
1094
    /* walk through each easy handle and do the socket state change magic
 
1095
       and callbacks */
 
1096
    easyp=multi->easy.next;
 
1097
    while(easyp) {
 
1098
      singlesocket(multi, easyp);
 
1099
      easyp = easyp->next;
 
1100
    }
 
1101
 
 
1102
    /* or should we fall-through and do the timer-based stuff? */
 
1103
    return result;
 
1104
  }
 
1105
  else if (s != CURL_SOCKET_TIMEOUT) {
 
1106
 
 
1107
    struct Curl_sh_entry *entry =
 
1108
      Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
 
1109
 
 
1110
    if(!entry)
 
1111
      /* unmatched socket, major problemo! */
 
1112
      return CURLM_BAD_SOCKET; /* better return code? */
 
1113
 
 
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 */
 
1116
 
 
1117
    data = entry->easy;
 
1118
 
 
1119
    result = multi_runsingle(multi, data->set.one_easy, &running_handles);
 
1120
 
 
1121
    if(result == CURLM_OK)
 
1122
      /* get the socket(s) and check if the state has been changed since
 
1123
         last */
 
1124
      singlesocket(multi, data->set.one_easy);
 
1125
 
 
1126
    /* or should we fall-through and do the timer-based stuff? */
 
1127
    return result;
 
1128
  }
 
1129
 
 
1130
  /*
 
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.
 
1134
   */
 
1135
  do {
 
1136
    int key;
 
1137
    struct timeval now;
 
1138
 
 
1139
    /* the first loop lap 'data' can be NULL */
 
1140
    if(data) {
 
1141
      result = multi_runsingle(multi, data->set.one_easy, &running_handles);
 
1142
 
 
1143
      if(result == CURLM_OK)
 
1144
        /* get the socket(s) and check if the state has been changed since
 
1145
           last */
 
1146
        singlesocket(multi, data->set.one_easy);
 
1147
    }
 
1148
 
 
1149
    /* Check if there's one (more) expired timer to deal with! This function
 
1150
       extracts a matching node if there is one */
 
1151
 
 
1152
    now = Curl_tvnow();
 
1153
    key = now.tv_sec; /* drop the usec part */
 
1154
 
 
1155
    multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
 
1156
    if(t)
 
1157
      data = t->payload;
 
1158
 
 
1159
  } while(t);
 
1160
 
 
1161
  return result;
 
1162
}
 
1163
 
 
1164
CURLMcode curl_multi_setopt(CURLM *multi_handle,
 
1165
                            CURLMoption option, ...)
 
1166
{
 
1167
  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
 
1168
  CURLMcode res = CURLM_OK;
 
1169
  va_list param;
 
1170
 
 
1171
  if(!GOOD_MULTI_HANDLE(multi))
 
1172
    return CURLM_BAD_HANDLE;
 
1173
 
 
1174
  va_start(param, option);
 
1175
 
 
1176
  switch(option) {
 
1177
  case CURLMOPT_SOCKETFUNCTION:
 
1178
    multi->socket_cb = va_arg(param, curl_socket_callback);
 
1179
    break;
 
1180
  case CURLMOPT_SOCKETDATA:
 
1181
    multi->socket_userp = va_arg(param, void *);
 
1182
    break;
 
1183
  default:
 
1184
    res = CURLM_UNKNOWN_OPTION;
 
1185
  }
 
1186
  va_end(param);
 
1187
  return res;
 
1188
}
 
1189
 
 
1190
 
 
1191
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s)
 
1192
{
 
1193
#if 0
 
1194
  printf("multi_socket(%d)\n", (int)s);
 
1195
#endif
 
1196
 
 
1197
  return multi_socket((struct Curl_multi *)multi_handle, FALSE, s);
 
1198
}
 
1199
 
 
1200
CURLMcode curl_multi_socket_all(CURLM *multi_handle)
 
1201
 
 
1202
{
 
1203
  return multi_socket((struct Curl_multi *)multi_handle,
 
1204
                      TRUE, CURL_SOCKET_BAD);
 
1205
}
 
1206
 
 
1207
CURLMcode curl_multi_timeout(CURLM *multi_handle,
 
1208
                             long *timeout_ms)
 
1209
{
 
1210
  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
 
1211
 
 
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;
 
1215
 
 
1216
  if(multi->timetree) {
 
1217
    /* we have a tree of expire times */
 
1218
    struct timeval now = Curl_tvnow();
 
1219
 
 
1220
    /* splay the lowest to the bottom */
 
1221
    multi->timetree = Curl_splay(0, multi->timetree);
 
1222
 
 
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 -
 
1225
      now.tv_usec/1000;
 
1226
    if(*timeout_ms < 0)
 
1227
      /* 0 means immediately */
 
1228
      *timeout_ms = 0;
 
1229
  }
 
1230
  else
 
1231
    *timeout_ms = -1;
 
1232
 
 
1233
  return CURLM_OK;
 
1234
}
 
1235
 
 
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)
 
1239
{
 
1240
  struct Curl_multi *multi = data->multi;
 
1241
  struct timeval *nowp = &data->state.expiretime;
 
1242
  int rc;
 
1243
 
 
1244
  /* this is only interesting for multi-interface using libcurl, and only
 
1245
     while there is still a multi interface struct remaining! */
 
1246
  if(!multi)
 
1247
    return;
 
1248
 
 
1249
  if(!milli) {
 
1250
    /* No timeout, clear the time data. */
 
1251
    if(nowp->tv_sec) {
 
1252
      /* Since this is an cleared time, we must remove the previous entry from
 
1253
         the splay tree */
 
1254
      rc = Curl_splayremovebyaddr(multi->timetree,
 
1255
                                  &data->state.timenode,
 
1256
                                  &multi->timetree);
 
1257
      if(rc)
 
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;
 
1261
    }
 
1262
  }
 
1263
  else {
 
1264
    struct timeval set;
 
1265
    int rest;
 
1266
 
 
1267
    set = Curl_tvnow();
 
1268
    set.tv_sec += milli/1000;
 
1269
    set.tv_usec += (milli%1000)*1000;
 
1270
 
 
1271
    rest = (int)(set.tv_usec - 1000000);
 
1272
    if(rest > 0) {
 
1273
      /* bigger than a full microsec */
 
1274
      set.tv_sec++;
 
1275
      set.tv_usec -= 1000000;
 
1276
    }
 
1277
 
 
1278
    if(nowp->tv_sec) {
 
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
 
1281
         is. */
 
1282
      long diff = curlx_tvdiff(set, *nowp);
 
1283
      if(diff > 0)
 
1284
        /* the new expire time was later so we don't change this */
 
1285
        return;
 
1286
 
 
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,
 
1291
                                  &multi->timetree);
 
1292
      if(rc)
 
1293
        infof(data, "Internal error removing splay node = %d\n", rc);
 
1294
    }
 
1295
 
 
1296
    *nowp = set;
 
1297
    infof(data, "Expire at %ld / %ld (%ldms)\n",
 
1298
          (long)nowp->tv_sec, (long)nowp->tv_usec, milli);
 
1299
 
 
1300
    data->state.timenode.payload = data;
 
1301
    multi->timetree = Curl_splayinsert((int)nowp->tv_sec,
 
1302
                                       multi->timetree,
 
1303
                                       &data->state.timenode);
 
1304
  }
 
1305
#if 0
 
1306
  Curl_splayprint(multi->timetree, 0, TRUE);
 
1307
#endif
 
1308
}
 
1309