Coverage Report

Created: 2026-05-30 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/multi.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) 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 https://curl.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
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#include "urldata.h"
27
#include "transfer.h"
28
#include "url.h"
29
#include "cfilters.h"
30
#include "connect.h"
31
#include "progress.h"
32
#include "curl_share.h"
33
#include "psl.h"
34
#include "multiif.h"
35
#include "multi_ev.h"
36
#include "sendf.h"
37
#include "curl_trc.h"
38
#include "http.h"
39
#include "select.h"
40
#include "curlx/wait.h"
41
#include "conncache.h"
42
#include "multihandle.h"
43
#include "sigpipe.h"
44
#include "vtls/vtls.h"
45
#include "vtls/vtls_scache.h"
46
#include "http_proxy.h"
47
#include "http2.h"
48
#include "socketpair.h"
49
#include "bufref.h"
50
51
/* initial multi->xfers table size for a full multi */
52
362k
#define CURL_XFER_TABLE_SIZE 512
53
54
/*
55
  CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
56
  to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
57
  curl handle takes 6K memory, therefore this 3K are not significant.
58
*/
59
#ifndef CURL_SOCKET_HASH_TABLE_SIZE
60
181k
#define CURL_SOCKET_HASH_TABLE_SIZE 911
61
#endif
62
63
#ifndef CURL_CONNECTION_HASH_SIZE
64
181k
#define CURL_CONNECTION_HASH_SIZE 97
65
#endif
66
67
#ifndef CURL_DNS_HASH_SIZE
68
181k
#define CURL_DNS_HASH_SIZE 71
69
#endif
70
71
#ifndef CURL_TLS_SESSION_SIZE
72
181k
#define CURL_TLS_SESSION_SIZE 25
73
#endif
74
75
21.8M
#define CURL_MULTI_HANDLE 0x000bab1e
76
77
#ifdef DEBUGBUILD
78
/* On a debug build, we want to fail hard on multi handles that
79
 * are not NULL, but no longer have the MAGIC touch. This gives
80
 * us early warning on things only discovered by valgrind otherwise. */
81
#define GOOD_MULTI_HANDLE(x)                         \
82
21.7M
  (((x) && (x)->magic == CURL_MULTI_HANDLE) ? TRUE : \
83
21.7M
  (DEBUGASSERT(!(x)), FALSE))
84
#else
85
#define GOOD_MULTI_HANDLE(x) \
86
  ((x) && (x)->magic == CURL_MULTI_HANDLE)
87
#endif
88
89
static void move_pending_to_connect(struct Curl_multi *multi,
90
                                    struct Curl_easy *data);
91
static CURLMcode add_next_timeout(const struct curltime *pnow,
92
                                  struct Curl_multi *multi,
93
                                  struct Curl_easy *d);
94
static void multi_timeout(struct Curl_multi *multi,
95
                          struct curltime *expire_time,
96
                          long *timeout_ms);
97
static void process_pending_handles(struct Curl_multi *multi);
98
static void multi_xfer_bufs_free(struct Curl_multi *multi);
99
#ifdef DEBUGBUILD
100
static void multi_xfer_tbl_dump(struct Curl_multi *multi);
101
#endif
102
103
static const struct curltime *multi_now(struct Curl_multi *multi)
104
10.6M
{
105
10.6M
  curlx_pnow(&multi->now);
106
10.6M
  return &multi->now;
107
10.6M
}
108
109
/* function pointer called once when switching TO a state */
110
typedef void (*init_multistate_func)(struct Curl_easy *data);
111
112
/* called in DID state, before PERFORMING state */
113
static void before_perform(struct Curl_easy *data)
114
63.2k
{
115
63.2k
  data->req.chunk = FALSE;
116
63.2k
  Curl_pgrsTime(data, TIMER_PRETRANSFER);
117
63.2k
}
118
119
static void init_completed(struct Curl_easy *data)
120
184k
{
121
  /* this is a completed transfer */
122
123
  /* Important: reset the conn pointer so that we do not point to memory
124
     that could be freed anytime */
125
184k
  Curl_detach_connection(data);
126
184k
  Curl_expire_clear(data); /* stop all timers */
127
184k
}
128
129
/* always use this function to change state, to make debugging easier */
130
static void mstate(struct Curl_easy *data, CURLMstate state
131
#ifdef DEBUGBUILD
132
                   , int lineno
133
#endif
134
)
135
1.31M
{
136
1.31M
  CURLMstate oldstate = data->mstate;
137
1.31M
  static const init_multistate_func finit[MSTATE_LAST] = {
138
1.31M
    NULL,              /* INIT */
139
1.31M
    NULL,              /* PENDING */
140
1.31M
    NULL,              /* SETUP */
141
1.31M
    Curl_init_CONNECT, /* CONNECT */
142
1.31M
    NULL,              /* CONNECTING */
143
1.31M
    NULL,              /* PROTOCONNECT */
144
1.31M
    NULL,              /* PROTOCONNECTING */
145
1.31M
    NULL,              /* DO */
146
1.31M
    NULL,              /* DOING */
147
1.31M
    NULL,              /* DOING_MORE */
148
1.31M
    before_perform,    /* DID */
149
1.31M
    NULL,              /* PERFORMING */
150
1.31M
    NULL,              /* RATELIMITING */
151
1.31M
    NULL,              /* DONE */
152
1.31M
    init_completed,    /* COMPLETED */
153
    NULL               /* MSGSENT */
154
1.31M
  };
155
156
1.31M
  if(oldstate == state)
157
    /* do not bother when the new state is the same as the old state */
158
191k
    return;
159
160
1.12M
#ifdef DEBUGBUILD
161
1.12M
  NOVERBOSE((void)lineno);
162
1.12M
  CURL_TRC_M(data, "-> [%s] (line %d)", CURL_MSTATE_NAME(state), lineno);
163
#else
164
  CURL_TRC_M(data, "-> [%s]", CURL_MSTATE_NAME(state));
165
#endif
166
167
  /* really switching state */
168
1.12M
  data->mstate = state;
169
1.12M
  switch(state) {
170
18.3k
  case MSTATE_DONE:
171
18.3k
    CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE);
172
18.3k
    break;
173
184k
  case MSTATE_COMPLETED:
174
    /* we sometimes directly jump to COMPLETED, trigger also a notification
175
     * in that case. */
176
184k
    if(oldstate < MSTATE_DONE)
177
167k
      CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE);
178
    /* changing to COMPLETED means it is in process and needs to go */
179
184k
    DEBUGASSERT(Curl_uint32_bset_contains(&data->multi->process, data->mid));
180
184k
    Curl_uint32_bset_remove(&data->multi->process, data->mid);
181
184k
    Curl_uint32_bset_remove(&data->multi->pending, data->mid); /* to be sure */
182
183
184k
    if(Curl_uint32_bset_empty(&data->multi->process)) {
184
      /* free the transfer buffer when we have no more active transfers */
185
0
      multi_xfer_bufs_free(data->multi);
186
0
    }
187
184k
    break;
188
924k
  default:
189
924k
    break;
190
1.12M
  }
191
192
  /* if this state has an init-function, run it */
193
1.12M
  if(finit[state])
194
411k
    finit[state](data);
195
1.12M
}
196
197
#ifndef DEBUGBUILD
198
#define multistate(x, y) mstate(x, y)
199
#else
200
1.31M
#define multistate(x, y) mstate(x, y, __LINE__)
201
#endif
202
203
/* multi->proto_hash destructor. Should never be called as elements
204
 * MUST be added with their own destructor */
205
static void ph_freeentry(void *p)
206
0
{
207
0
  (void)p;
208
  /* Always FALSE. Cannot use a 0 assert here since compilers
209
   * are not in agreement if they then want a NORETURN attribute or
210
   * not. *sigh* */
211
0
  DEBUGASSERT(p == NULL);
212
0
}
213
214
/*
215
 * multi_addmsg()
216
 *
217
 * Called when a transfer is completed. Adds the given msg pointer to
218
 * the list kept in the multi handle.
219
 */
220
static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
221
177k
{
222
177k
  if(!Curl_llist_count(&multi->msglist))
223
177k
    CURLM_NTFY(multi->admin, CURLMNOTIFY_INFO_READ);
224
177k
  Curl_llist_append(&multi->msglist, msg, &msg->list);
225
177k
}
226
227
struct Curl_multi *Curl_multi_handle(uint32_t xfer_table_size,
228
                                     size_t ev_hashsize,  /* event hash */
229
                                     size_t chashsize, /* connection hash */
230
                                     size_t dnssize,   /* dns hash */
231
                                     size_t sesssize)  /* TLS session cache */
232
181k
{
233
181k
  struct Curl_multi *multi = curlx_calloc(1, sizeof(struct Curl_multi));
234
235
181k
  if(!multi)
236
0
    return NULL;
237
238
181k
  multi->magic = CURL_MULTI_HANDLE;
239
240
181k
  Curl_dnscache_init(&multi->dnscache, dnssize);
241
181k
  Curl_mntfy_init(multi);
242
181k
  Curl_multi_ev_init(multi, ev_hashsize);
243
181k
  Curl_uint32_tbl_init(&multi->xfers, NULL);
244
181k
  Curl_uint32_bset_init(&multi->process);
245
181k
  Curl_uint32_bset_init(&multi->dirty);
246
181k
  Curl_uint32_bset_init(&multi->pending);
247
181k
  Curl_uint32_bset_init(&multi->msgsent);
248
181k
  Curl_hash_init(&multi->proto_hash, 23,
249
181k
                 Curl_hash_str, curlx_str_key_compare, ph_freeentry);
250
181k
  Curl_llist_init(&multi->msglist, NULL);
251
252
181k
  multi->multiplexing = TRUE;
253
181k
  multi->max_concurrent_streams = 100;
254
181k
  multi->last_timeout_ms = -1;
255
181k
#ifdef ENABLE_WAKEUP
256
181k
  multi->wakeup_pair[0] = CURL_SOCKET_BAD;
257
181k
  multi->wakeup_pair[1] = CURL_SOCKET_BAD;
258
181k
#endif
259
260
181k
  if(Curl_mntfy_resize(multi) ||
261
181k
     Curl_uint32_bset_resize(&multi->process, xfer_table_size) ||
262
181k
     Curl_uint32_bset_resize(&multi->pending, xfer_table_size) ||
263
181k
     Curl_uint32_bset_resize(&multi->dirty, xfer_table_size) ||
264
181k
     Curl_uint32_bset_resize(&multi->msgsent, xfer_table_size) ||
265
181k
     Curl_uint32_tbl_resize(&multi->xfers, xfer_table_size))
266
0
    goto error;
267
268
181k
  multi->admin = curl_easy_init();
269
181k
  if(!multi->admin)
270
0
    goto error;
271
  /* Initialize admin handle to operate inside this multi */
272
181k
  multi->admin->multi = multi;
273
181k
  multi->admin->state.internal = TRUE;
274
181k
  Curl_llist_init(&multi->admin->state.timeoutlist, NULL);
275
276
181k
#ifdef DEBUGBUILD
277
181k
  if(getenv("CURL_DEBUG"))
278
0
    multi->admin->set.verbose = TRUE;
279
181k
#endif
280
181k
  Curl_uint32_tbl_add(&multi->xfers, multi->admin, &multi->admin->mid);
281
181k
  Curl_uint32_bset_add(&multi->process, multi->admin->mid);
282
283
181k
  if(Curl_cshutdn_init(&multi->cshutdn, multi))
284
0
    goto error;
285
286
181k
  Curl_cpool_init(&multi->cpool, multi->admin, NULL, chashsize);
287
288
181k
#ifdef USE_SSL
289
181k
  if(Curl_ssl_scache_create(sesssize, 2, &multi->ssl_scache))
290
0
    goto error;
291
#else
292
  (void)sesssize;
293
#endif
294
295
#ifdef USE_WINSOCK
296
  multi->wsa_event = WSACreateEvent();
297
  if(multi->wsa_event == WSA_INVALID_EVENT)
298
    goto error;
299
#endif
300
181k
#ifdef ENABLE_WAKEUP
301
  /* When enabled, rely on this to work. We ignore this in previous
302
   * versions, but that seems an unnecessary complication. */
303
181k
  if(Curl_wakeup_init(multi->wakeup_pair, TRUE) < 0)
304
0
    goto error;
305
181k
#endif
306
307
181k
  if(Curl_probeipv6(multi))
308
0
    goto error;
309
310
181k
#ifdef USE_RESOLV_THREADED
311
181k
  if(xfer_table_size < CURL_XFER_TABLE_SIZE) { /* easy multi */
312
0
    if(Curl_async_thrdd_multi_init(multi, 0, 2, 10))
313
0
      goto error;
314
0
  }
315
181k
  else { /* real multi handle */
316
181k
    if(Curl_async_thrdd_multi_init(multi, 0, 20, 2000))
317
0
      goto error;
318
181k
  }
319
181k
#endif
320
321
181k
  return multi;
322
323
0
error:
324
325
0
#ifdef USE_RESOLV_THREADED
326
0
  Curl_async_thrdd_multi_destroy(multi, TRUE);
327
0
#endif
328
0
  Curl_multi_ev_cleanup(multi);
329
0
  Curl_hash_destroy(&multi->proto_hash);
330
0
  Curl_dnscache_destroy(&multi->dnscache);
331
0
  Curl_cpool_destroy(&multi->cpool);
332
0
  Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
333
0
#ifdef USE_SSL
334
0
  Curl_ssl_scache_destroy(multi->ssl_scache);
335
0
#endif
336
0
  if(multi->admin) {
337
0
    Curl_multi_ev_xfer_done(multi, multi->admin);
338
0
    multi->admin->multi = NULL;
339
0
    Curl_close(&multi->admin);
340
0
  }
341
0
  Curl_mntfy_cleanup(multi);
342
343
0
  Curl_uint32_bset_destroy(&multi->process);
344
0
  Curl_uint32_bset_destroy(&multi->dirty);
345
0
  Curl_uint32_bset_destroy(&multi->pending);
346
0
  Curl_uint32_bset_destroy(&multi->msgsent);
347
0
  Curl_uint32_tbl_destroy(&multi->xfers);
348
0
#ifdef ENABLE_WAKEUP
349
0
  Curl_wakeup_destroy(multi->wakeup_pair);
350
0
#endif
351
352
0
  curlx_free(multi);
353
0
  return NULL;
354
181k
}
355
356
CURLM *curl_multi_init(void)
357
181k
{
358
181k
  return Curl_multi_handle(CURL_XFER_TABLE_SIZE,
359
181k
                           CURL_SOCKET_HASH_TABLE_SIZE,
360
181k
                           CURL_CONNECTION_HASH_SIZE,
361
181k
                           CURL_DNS_HASH_SIZE,
362
181k
                           CURL_TLS_SESSION_SIZE);
363
181k
}
364
365
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
366
static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
367
24.2M
{
368
24.2M
  if(!multi->warned) {
369
181k
    infof(data, "!!! WARNING !!!");
370
181k
    infof(data, "This is a debug build of libcurl, "
371
181k
                "do not use in production.");
372
181k
    multi->warned = TRUE;
373
181k
  }
374
24.2M
}
375
#else
376
#define multi_warn_debug(x, y) Curl_nop_stmt
377
#endif
378
379
bool Curl_is_connecting(struct Curl_easy *data)
380
33.5M
{
381
33.5M
  return data->mstate < MSTATE_DO;
382
33.5M
}
383
384
static CURLMcode multi_assess_wakeup(struct Curl_multi *multi)
385
560k
{
386
560k
#ifdef ENABLE_WAKEUP
387
560k
  if(multi->socket_cb)
388
0
    return Curl_multi_ev_assess_xfer(multi, multi->admin);
389
#else
390
  (void)multi;
391
#endif
392
560k
  return CURLM_OK;
393
560k
}
394
395
static CURLMcode multi_xfers_add(struct Curl_multi *multi,
396
                                 struct Curl_easy *data)
397
191k
{
398
191k
  uint32_t capacity = Curl_uint32_tbl_capacity(&multi->xfers);
399
191k
  uint32_t new_size = 0;
400
  /* Prepare to make this into a CURLMOPT_MAX_TRANSFERS, because some
401
   * applications may want to prevent a run-away of their memory use. */
402
  /* UINT_MAX is our "invalid" id, do not let the table grow up to that. */
403
191k
  const uint32_t max_capacity = UINT_MAX - 1;
404
405
191k
  if(capacity < max_capacity) {
406
    /* We want `multi->xfers` to have "sufficient" free rows, so that we do
407
     * not have to reuse the `mid` from a removed easy right away.
408
     * Since uint_tbl and uint_bset are memory efficient,
409
     * regard less than 25% free as insufficient.
410
     * (for low capacities, e.g. multi_easy, 4 or less). */
411
191k
    uint32_t used = Curl_uint32_tbl_count(&multi->xfers);
412
191k
    uint32_t unused = capacity - used;
413
191k
    uint32_t min_unused = CURLMAX(capacity >> 2, 4);
414
191k
    if(unused <= min_unused) {
415
      /* Make sure the uint arithmetic here works on the corner
416
       * cases where we are close to max_capacity or UINT_MAX */
417
0
      if((min_unused >= max_capacity) ||
418
0
         ((max_capacity - min_unused) <= capacity) ||
419
0
         ((UINT_MAX - min_unused - 63) <= capacity)) {
420
0
        new_size = max_capacity; /* can not be larger than this */
421
0
      }
422
0
      else {
423
        /* make it a 64 multiple, since our bitsets grow by that and
424
         * small (easy_multi) grows to at least 64 on first resize. */
425
0
        new_size = (((used + min_unused) + 63) / 64) * 64;
426
0
      }
427
0
    }
428
191k
  }
429
430
191k
  if(new_size > capacity) {
431
    /* Grow the bitsets first. Should one fail, we do not need
432
     * to downsize the already resized ones. The sets continue
433
     * to work properly when larger than the table, but not
434
     * the other way around. */
435
0
    CURL_TRC_M(data, "increasing xfer table size to %u", new_size);
436
0
    if(Curl_uint32_bset_resize(&multi->process, new_size) ||
437
0
       Curl_uint32_bset_resize(&multi->dirty, new_size) ||
438
0
       Curl_uint32_bset_resize(&multi->pending, new_size) ||
439
0
       Curl_uint32_bset_resize(&multi->msgsent, new_size) ||
440
0
       Curl_uint32_tbl_resize(&multi->xfers, new_size))
441
0
      return CURLM_OUT_OF_MEMORY;
442
0
  }
443
444
  /* Insert the easy into the table now */
445
191k
  if(!Curl_uint32_tbl_add(&multi->xfers, data, &data->mid)) {
446
    /* MUST only happen when table is full */
447
0
    DEBUGASSERT(Curl_uint32_tbl_capacity(&multi->xfers) <=
448
0
                Curl_uint32_tbl_count(&multi->xfers));
449
0
    return CURLM_OUT_OF_MEMORY;
450
0
  }
451
191k
  return CURLM_OK;
452
191k
}
453
454
CURLMcode curl_multi_add_handle(CURLM *m, CURL *curl)
455
191k
{
456
191k
  CURLMcode mresult;
457
191k
  struct Curl_multi *multi = m;
458
191k
  struct Curl_easy *data = curl;
459
460
  /* First, make some basic checks that the CURLM handle is a good handle */
461
191k
  if(!GOOD_MULTI_HANDLE(multi))
462
0
    return CURLM_BAD_HANDLE;
463
464
  /* Verify that we got a somewhat good easy handle too */
465
191k
  if(!GOOD_EASY_HANDLE(data))
466
0
    return CURLM_BAD_EASY_HANDLE;
467
468
  /* Prevent users from adding same easy handle more than once and prevent
469
     adding to more than one multi stack */
470
191k
  if(data->multi)
471
0
    return CURLM_ADDED_ALREADY;
472
473
191k
  if(multi->in_callback)
474
0
    return CURLM_RECURSIVE_API_CALL;
475
476
191k
  if(multi->dead) {
477
    /* a "dead" handle cannot get added transfers while any existing easy
478
       handles are still alive - but if there are none alive anymore, it is
479
       fine to start over and unmark the "deadness" of this handle.
480
       This means only the admin handle MUST be present. */
481
0
    if((Curl_uint32_tbl_count(&multi->xfers) != 1) ||
482
0
       !Curl_uint32_tbl_contains(&multi->xfers, 0))
483
0
      return CURLM_ABORTED_BY_CALLBACK;
484
0
    multi->dead = FALSE;
485
0
    Curl_uint32_bset_clear(&multi->process);
486
0
    Curl_uint32_bset_clear(&multi->dirty);
487
0
    Curl_uint32_bset_clear(&multi->pending);
488
0
    Curl_uint32_bset_clear(&multi->msgsent);
489
0
  }
490
491
191k
  if(data->multi_easy) {
492
    /* if this easy handle was previously used for curl_easy_perform(), there
493
       is a private multi handle here that we can kill */
494
0
    curl_multi_cleanup(data->multi_easy);
495
0
    data->multi_easy = NULL;
496
0
  }
497
498
  /* Insert the easy into the multi->xfers table, assigning it a `mid`. */
499
191k
  if(multi_xfers_add(multi, data))
500
0
    return CURLM_OUT_OF_MEMORY;
501
502
  /* Initialize timeout list for this handle */
503
191k
  Curl_llist_init(&data->state.timeoutlist, NULL);
504
505
  /*
506
   * No failure allowed in this function beyond this point. No modification of
507
   * easy nor multi handle allowed before this except for potential multi's
508
   * connection pool growing which will not be undone in this function no
509
   * matter what.
510
   */
511
191k
  if(data->set.errorbuffer)
512
0
    data->set.errorbuffer[0] = 0;
513
514
191k
  data->state.os_errno = 0;
515
516
  /* make the Curl_easy refer back to this multi handle - before Curl_expire()
517
     is called. */
518
191k
  data->multi = multi;
519
520
  /* set the easy handle */
521
191k
  multistate(data, MSTATE_INIT);
522
523
#ifdef USE_LIBPSL
524
  /* Do the same for PSL. */
525
  if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL)))
526
    data->psl = &data->share->psl;
527
  else
528
    data->psl = &multi->psl;
529
#endif
530
531
  /* add the easy handle to the process set */
532
191k
  Curl_uint32_bset_add(&multi->process, data->mid);
533
191k
  ++multi->xfers_alive;
534
191k
  ++multi->xfers_total_ever;
535
536
191k
  Curl_cpool_xfer_init(data);
537
191k
  multi_warn_debug(multi, data);
538
539
  /* Make sure the new handle will run */
540
191k
  Curl_multi_mark_dirty(data);
541
542
  /* Necessary in event based processing, where dirty handles trigger
543
   * a timeout callback invocation. */
544
191k
  mresult = Curl_update_timer(multi);
545
191k
  if(mresult) {
546
0
    data->multi = NULL; /* not anymore */
547
0
    Curl_uint32_tbl_remove(&multi->xfers, data->mid);
548
0
    data->mid = UINT32_MAX;
549
0
    return mresult;
550
0
  }
551
552
  /* The admin handle only ever has default timeouts set. To improve the
553
     state somewhat we clone the timeouts from each added handle so that the
554
     admin handle always has the same timeouts as the most recently added
555
     easy handle. */
556
191k
  multi->admin->set.timeout = data->set.timeout;
557
191k
  multi->admin->set.server_response_timeout =
558
191k
    data->set.server_response_timeout;
559
191k
  multi->admin->set.no_signal = data->set.no_signal;
560
561
191k
  mresult = multi_assess_wakeup(multi);
562
191k
  if(mresult) {
563
0
    failf(data, "error enabling wakeup listening: %d", mresult);
564
0
    return mresult;
565
0
  }
566
567
191k
  CURL_TRC_M(data, "added to multi, mid=%u, running=%u, total=%u",
568
191k
             data->mid, Curl_multi_xfers_running(multi),
569
191k
             Curl_uint32_tbl_count(&multi->xfers));
570
191k
  return CURLM_OK;
571
191k
}
572
573
#if 0
574
/* Debug-function, used like this:
575
 *
576
 * Curl_hash_print(&multi->sockhash, debug_print_sock_hash);
577
 *
578
 * Enable the hash print function first by editing hash.c
579
 */
580
static void debug_print_sock_hash(void *p)
581
{
582
  struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
583
584
  curl_mfprintf(stderr, " [readers %u][writers %u]",
585
                sh->readers, sh->writers);
586
}
587
#endif
588
589
struct multi_done_ctx {
590
  BIT(premature);
591
};
592
593
static bool multi_conn_should_close(struct connectdata *conn,
594
                                    struct Curl_easy *data,
595
                                    bool premature)
596
136k
{
597
  /* if conn->bits.close is TRUE, it means that the connection should be
598
     closed in spite of everything else. */
599
136k
  if(conn->bits.close)
600
40.5k
    return TRUE;
601
602
  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
603
     forced us to close this connection. This is ignored for requests taking
604
     place in a NTLM/NEGOTIATE authentication handshake. */
605
95.9k
  if(data->set.reuse_forbid
606
#ifdef USE_NTLM
607
     && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
608
          conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
609
#endif
610
#ifdef USE_SPNEGO
611
     && !(conn->http_negotiate_state == GSS_AUTHRECV ||
612
          conn->proxy_negotiate_state == GSS_AUTHRECV)
613
#endif
614
95.9k
    )
615
145
    return TRUE;
616
617
  /* Unless this connection is for a "connect-only" transfer, it
618
   * needs to be closed if the protocol handler does not support reuse. */
619
95.8k
  if(!data->set.connect_only && conn->scheme &&
620
88.2k
     !(conn->scheme->flags & PROTOPT_CONN_REUSE))
621
30.1k
    return TRUE;
622
623
  /* if premature is TRUE, it means this connection was said to be DONE before
624
     the entire request operation is complete and thus we cannot know in what
625
     state it is for reusing, so we are forced to close it. In a perfect world
626
     we can add code that keep track of if we really must close it here or not,
627
     but currently we have no such detail knowledge. */
628
65.6k
  if(premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))
629
40.0k
    return TRUE;
630
631
25.6k
  return FALSE;
632
65.6k
}
633
634
static void multi_done_locked(struct connectdata *conn,
635
                              struct Curl_easy *data,
636
                              void *userdata)
637
136k
{
638
136k
  struct multi_done_ctx *mdctx = userdata;
639
640
136k
  Curl_detach_connection(data);
641
642
136k
  CURL_TRC_M(data, "multi_done_locked, in use=%u", conn->attached_xfers);
643
136k
  if(CONN_INUSE(conn)) {
644
    /* Stop if still used. */
645
0
    CURL_TRC_M(data, "Connection still in use %u, no more multi_done now!",
646
0
               conn->attached_xfers);
647
0
    return;
648
0
  }
649
650
136k
  data->state.done = TRUE; /* called now! */
651
136k
  data->state.recent_conn_id = conn->connection_id;
652
653
136k
  Curl_dnscache_prune(data);
654
655
136k
  if(multi_conn_should_close(conn, data, (bool)mdctx->premature)) {
656
110k
    CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s, "
657
110k
               "forbid=%d, close=%d, premature=%d, conn_multiplex=%d",
658
110k
               conn->connection_id, conn->destination,
659
110k
               data->set.reuse_forbid, conn->bits.close, mdctx->premature,
660
110k
               Curl_conn_is_multiplex(conn, FIRSTSOCKET));
661
110k
    connclose(conn, "disconnecting");
662
110k
    Curl_conn_terminate(data, conn, (bool)mdctx->premature);
663
110k
  }
664
25.6k
  else if(!Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) {
665
57
    CURL_TRC_M(data, "multi_done, conn #%" FMT_OFF_T " to %s was shutdown"
666
57
               " by server, not reusing", conn->connection_id,
667
57
               conn->destination);
668
57
    connclose(conn, "server shutdown");
669
57
    Curl_conn_terminate(data, conn, (bool)mdctx->premature);
670
57
  }
671
25.5k
  else {
672
    /* the connection is no longer in use by any transfer */
673
25.5k
    if(Curl_cpool_conn_now_idle(data, conn)) {
674
      /* connection kept in the cpool */
675
25.5k
      data->state.lastconnect_id = conn->connection_id;
676
25.5k
      infof(data, "Connection #%" FMT_OFF_T " to host %s left intact",
677
25.5k
            conn->connection_id, conn->destination);
678
25.5k
    }
679
0
    else {
680
      /* connection was removed from the cpool and destroyed. */
681
0
      data->state.lastconnect_id = -1;
682
0
    }
683
25.5k
  }
684
136k
}
685
686
static CURLcode multi_done(struct Curl_easy *data,
687
                           CURLcode status,  /* an error if this is called
688
                                                after an error was detected */
689
                           bool premature)
690
136k
{
691
136k
  CURLcode result;
692
136k
  struct connectdata *conn = data->conn;
693
694
136k
  CURL_TRC_M(data, "multi_done: status: %d prem: %d done: %d",
695
136k
             (int)status, (int)premature, data->state.done);
696
697
136k
  if(data->state.done)
698
    /* Stop if multi_done() has already been called */
699
390
    return CURLE_OK;
700
701
  /* Shut down any ongoing async resolver operation. */
702
136k
  Curl_resolv_shutdown_all(data);
703
704
  /* Cleanup possible redirect junk */
705
136k
  curlx_safefree(data->req.newurl);
706
136k
  curlx_safefree(data->req.location);
707
708
136k
  switch(status) {
709
20
  case CURLE_ABORTED_BY_CALLBACK:
710
216
  case CURLE_READ_ERROR:
711
300
  case CURLE_WRITE_ERROR:
712
    /* When we are aborted due to a callback return code it has to be counted
713
       as premature as there is trouble ahead if we do not. We have many
714
       callbacks and protocols work differently, we could potentially do this
715
       more fine-grained in the future. */
716
300
    premature = TRUE;
717
300
    FALLTHROUGH();
718
136k
  default:
719
136k
    break;
720
136k
  }
721
722
  /* this calls the protocol-specific function pointer previously set */
723
136k
  if(conn && conn->scheme->run->done && (data->mstate >= MSTATE_PROTOCONNECT))
724
71.4k
    result = conn->scheme->run->done(data, status, premature);
725
65.0k
  else
726
65.0k
    result = status;
727
728
136k
  if(data->mstate > MSTATE_CONNECTING &&
729
73.3k
     (result != CURLE_ABORTED_BY_CALLBACK)) {
730
    /* avoid this if
731
     * - the transfer has not connected
732
     * - we already aborted by callback to avoid this calling another callback
733
     */
734
73.3k
    int rc = Curl_pgrsDone(data);
735
73.3k
    if(!result && rc)
736
0
      result = CURLE_ABORTED_BY_CALLBACK;
737
73.3k
  }
738
739
  /* Make sure that transfer client writes are really done now. */
740
136k
  result = Curl_1st_fatal(result, Curl_xfer_write_done(data, premature));
741
742
  /* Inform connection filters that this transfer is done */
743
136k
  if(conn)
744
136k
    Curl_conn_ev_data_done(data, premature);
745
746
136k
  process_pending_handles(data->multi); /* connection / multiplex */
747
748
136k
  if(!result)
749
26.5k
    result = Curl_req_done(&data->req, data, premature);
750
751
136k
  if(conn) {
752
    /* Under the potential connection pool's share lock, decide what to
753
     * do with the transfer's connection. */
754
136k
    struct multi_done_ctx mdctx;
755
756
136k
    memset(&mdctx, 0, sizeof(mdctx));
757
136k
    mdctx.premature = premature;
758
136k
    Curl_cpool_do_locked(data, data->conn, multi_done_locked, &mdctx);
759
136k
  }
760
761
  /* flush the netrc cache */
762
136k
  Curl_netrc_cleanup(&data->state.netrc);
763
136k
  return result;
764
136k
}
765
766
static void close_connect_only(struct connectdata *conn,
767
                               struct Curl_easy *data,
768
                               void *userdata)
769
6.99k
{
770
6.99k
  (void)userdata;
771
6.99k
  (void)data;
772
6.99k
  if(conn->bits.connect_only)
773
8
    connclose(conn, "Removing connect-only easy handle");
774
6.99k
}
775
776
CURLMcode curl_multi_remove_handle(CURLM *m, CURL *curl)
777
191k
{
778
191k
  struct Curl_multi *multi = m;
779
191k
  struct Curl_easy *data = curl;
780
191k
  bool premature;
781
191k
  struct Curl_llist_node *e;
782
191k
  CURLMcode mresult;
783
191k
  uint32_t mid;
784
785
  /* First, make some basic checks that the CURLM handle is a good handle */
786
191k
  if(!GOOD_MULTI_HANDLE(multi))
787
0
    return CURLM_BAD_HANDLE;
788
789
  /* Verify that we got a somewhat good easy handle too */
790
191k
  if(!GOOD_EASY_HANDLE(data))
791
0
    return CURLM_BAD_EASY_HANDLE;
792
793
  /* Prevent users from trying to remove same easy handle more than once */
794
191k
  if(!data->multi)
795
0
    return CURLM_OK; /* it is already removed so let's say it is fine! */
796
797
  /* Prevent users from trying to remove an easy handle from the wrong multi */
798
191k
  if(data->multi != multi)
799
0
    return CURLM_BAD_EASY_HANDLE;
800
801
191k
  if(data->mid == UINT32_MAX) {
802
0
    DEBUGASSERT(0);
803
0
    return CURLM_INTERNAL_ERROR;
804
0
  }
805
191k
  if(Curl_uint32_tbl_get(&multi->xfers, data->mid) != data) {
806
0
    DEBUGASSERT(0);
807
0
    return CURLM_INTERNAL_ERROR;
808
0
  }
809
810
191k
  if(multi->in_callback)
811
0
    return CURLM_RECURSIVE_API_CALL;
812
813
191k
  premature = (data->mstate < MSTATE_COMPLETED);
814
815
  /* If the 'state' is not INIT or COMPLETED, we might need to do something
816
     nice to put the easy_handle in a good known state when this returns. */
817
191k
  if(data->conn &&
818
5.25k
     data->mstate > MSTATE_DO &&
819
1.70k
     data->mstate < MSTATE_COMPLETED) {
820
    /* Set connection owner so that the DONE function closes it. We can
821
       safely do this here since connection is killed. */
822
1.31k
    streamclose(data->conn, "Removed with partial response");
823
1.31k
  }
824
825
191k
  if(data->conn) {
826
    /* multi_done() clears the association between the easy handle and the
827
       connection.
828
829
       Note that this ignores the return code because there is
830
       nothing really useful to do with it anyway! */
831
5.25k
    (void)multi_done(data, data->result, premature);
832
5.25k
  }
833
834
  /* The timer must be shut down before data->multi is set to NULL, else the
835
     timenode will remain in the splay tree after curl_easy_cleanup is
836
     called. Do it after multi_done() in case that sets another time! */
837
191k
  Curl_expire_clear(data);
838
839
  /* If in `msgsent`, it was deducted from `multi->xfers_alive` already. */
840
191k
  if(!Curl_uint32_bset_contains(&multi->msgsent, data->mid))
841
6.22k
    --multi->xfers_alive;
842
843
191k
  Curl_wildcard_dtor(&data->wildcard);
844
845
191k
  data->mstate = MSTATE_COMPLETED;
846
847
  /* Remove the association between the connection and the handle */
848
191k
  Curl_detach_connection(data);
849
850
  /* Tell event handling that this transfer is definitely going away */
851
191k
  Curl_multi_ev_xfer_done(multi, data);
852
853
191k
  if(data->set.connect_only && !data->multi_easy) {
854
    /* This removes a handle that was part the multi interface that used
855
       CONNECT_ONLY, that connection is now left alive but since this handle
856
       has bits.close set nothing can use that transfer anymore and it is
857
       forbidden from reuse. This easy handle cannot find the connection
858
       anymore once removed from the multi handle
859
860
       Better close the connection here, at once.
861
    */
862
17.3k
    struct connectdata *c;
863
17.3k
    curl_socket_t s;
864
17.3k
    s = Curl_getconnectinfo(data, &c);
865
17.3k
    if((s != CURL_SOCKET_BAD) && c) {
866
3.84k
      Curl_conn_terminate(data, c, TRUE);
867
3.84k
    }
868
17.3k
  }
869
870
191k
  if(data->state.lastconnect_id != -1) {
871
    /* Mark any connect-only connection for closure */
872
13.4k
    Curl_cpool_do_by_id(data, data->state.lastconnect_id,
873
13.4k
                        close_connect_only, NULL);
874
13.4k
  }
875
876
#ifdef USE_LIBPSL
877
  /* Remove the PSL association. */
878
  if(data->psl == &multi->psl)
879
    data->psl = NULL;
880
#endif
881
882
  /* make sure there is no pending message in the queue sent from this easy
883
     handle */
884
191k
  for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) {
885
177k
    struct Curl_message *msg = Curl_node_elem(e);
886
887
177k
    if(msg->extmsg.easy_handle == data) {
888
177k
      Curl_node_remove(e);
889
      /* there can only be one from this specific handle */
890
177k
      break;
891
177k
    }
892
177k
  }
893
894
  /* clear the association to this multi handle */
895
191k
  mid = data->mid;
896
191k
  DEBUGASSERT(Curl_uint32_tbl_contains(&multi->xfers, mid));
897
191k
  Curl_uint32_tbl_remove(&multi->xfers, mid);
898
191k
  Curl_uint32_bset_remove(&multi->process, mid);
899
191k
  Curl_uint32_bset_remove(&multi->dirty, mid);
900
191k
  Curl_uint32_bset_remove(&multi->pending, mid);
901
191k
  Curl_uint32_bset_remove(&multi->msgsent, mid);
902
191k
  data->multi = NULL;
903
191k
  data->mid = UINT32_MAX;
904
191k
  data->master_mid = UINT32_MAX;
905
906
  /* NOTE NOTE NOTE
907
     We do not touch the easy handle here! */
908
191k
  process_pending_handles(multi);
909
910
191k
  mresult = Curl_update_timer(multi);
911
191k
  if(mresult)
912
0
    return mresult;
913
914
191k
  mresult = multi_assess_wakeup(multi);
915
191k
  if(mresult) {
916
0
    failf(data, "error enabling wakeup listening: %d", mresult);
917
0
    return mresult;
918
0
  }
919
920
191k
  CURL_TRC_M(data, "removed from multi, mid=%u, running=%u, total=%u",
921
191k
             mid, Curl_multi_xfers_running(multi),
922
191k
             Curl_uint32_tbl_count(&multi->xfers));
923
191k
  return CURLM_OK;
924
191k
}
925
926
/* Return TRUE if the application asked for multiplexing */
927
bool Curl_multiplex_wanted(const struct Curl_multi *multi)
928
48.2k
{
929
48.2k
  return multi && multi->multiplexing;
930
48.2k
}
931
932
/*
933
 * Curl_detach_connection() removes the given transfer from the connection.
934
 *
935
 * This is the only function that should clear data->conn. This will
936
 * occasionally be called with the data->conn pointer already cleared.
937
 */
938
void Curl_detach_connection(struct Curl_easy *data)
939
1.08M
{
940
1.08M
  struct connectdata *conn = data->conn;
941
1.08M
  if(conn) {
942
    /* this should never happen, prevent underflow */
943
299k
    DEBUGASSERT(conn->attached_xfers);
944
299k
    if(conn->attached_xfers) {
945
299k
      conn->attached_xfers--;
946
299k
      if(!conn->attached_xfers)
947
299k
        conn->attached_multi = NULL;
948
299k
    }
949
299k
  }
950
1.08M
  data->conn = NULL;
951
1.08M
}
952
953
/*
954
 * Curl_attach_connection() attaches this transfer to this connection.
955
 *
956
 * This is the only function that should assign data->conn
957
 */
958
void Curl_attach_connection(struct Curl_easy *data,
959
                            struct connectdata *conn)
960
299k
{
961
299k
  DEBUGASSERT(data);
962
299k
  DEBUGASSERT(!data->conn);
963
299k
  DEBUGASSERT(conn);
964
299k
  DEBUGASSERT(conn->attached_xfers < UINT32_MAX);
965
299k
  data->conn = conn;
966
299k
  conn->attached_xfers++;
967
  /* all attached transfers must be from the same multi */
968
299k
  if(!conn->attached_multi)
969
299k
    conn->attached_multi = data->multi;
970
299k
  DEBUGASSERT(conn->attached_multi == data->multi);
971
972
299k
  if(conn->scheme && conn->scheme->run->attach)
973
0
    conn->scheme->run->attach(data, conn);
974
299k
}
975
976
/* adjust pollset for rate limits/pauses */
977
static CURLcode multi_adjust_pollset(struct Curl_easy *data,
978
                                     struct easy_pollset *ps)
979
9.81M
{
980
9.81M
  CURLcode result = CURLE_OK;
981
982
9.81M
  if(ps->n) {
983
9.81M
    const struct curltime *pnow = Curl_pgrs_now(data);
984
9.81M
    bool send_blocked, recv_blocked;
985
986
9.81M
    recv_blocked = (Curl_rlimit_avail(&data->progress.dl.rlimit, pnow) <= 0);
987
9.81M
    send_blocked = (Curl_rlimit_avail(&data->progress.ul.rlimit, pnow) <= 0);
988
9.81M
    if(send_blocked || recv_blocked) {
989
325
      int i;
990
975
      for(i = 0; i <= SECONDARYSOCKET; ++i) {
991
650
        curl_socket_t sock = data->conn->sock[i];
992
650
        if(sock == CURL_SOCKET_BAD)
993
325
          continue;
994
325
        if(recv_blocked && Curl_pollset_want_recv(data, ps, sock)) {
995
325
          result = Curl_pollset_remove_in(data, ps, sock);
996
325
          if(result)
997
0
            break;
998
325
        }
999
325
        if(send_blocked && Curl_pollset_want_send(data, ps, sock)) {
1000
0
          result = Curl_pollset_remove_out(data, ps, sock);
1001
0
          if(result)
1002
0
            break;
1003
0
        }
1004
325
      }
1005
325
    }
1006
1007
    /* Not blocked and wanting to receive. If there is data pending
1008
     * in the connection filters, make transfer run again. */
1009
9.81M
    if(!recv_blocked &&
1010
9.81M
       ((Curl_pollset_want_recv(data, ps, data->conn->sock[FIRSTSOCKET]) &&
1011
6.57M
         Curl_conn_data_pending(data, FIRSTSOCKET)) ||
1012
9.81M
        (Curl_pollset_want_recv(data, ps, data->conn->sock[SECONDARYSOCKET]) &&
1013
2
         Curl_conn_data_pending(data, SECONDARYSOCKET)))) {
1014
0
      CURL_TRC_M(data, "pollset[] has POLLIN, but there is still "
1015
0
                 "buffered input -> mark as dirty");
1016
0
      Curl_multi_mark_dirty(data);
1017
0
    }
1018
9.81M
  }
1019
9.81M
  return result;
1020
9.81M
}
1021
1022
static CURLcode mstate_connecting_pollset(struct Curl_easy *data,
1023
                                          struct easy_pollset *ps)
1024
6.58M
{
1025
6.58M
  struct connectdata *conn = data->conn;
1026
6.58M
  curl_socket_t sockfd;
1027
6.58M
  CURLcode result = CURLE_OK;
1028
1029
6.58M
  if(Curl_xfer_recv_is_paused(data))
1030
0
    return CURLE_OK;
1031
  /* If a socket is set, receiving is default. If the socket
1032
   * has not been determined yet (eyeballing), always ask the
1033
   * connection filters for what to monitor. */
1034
6.58M
  sockfd = Curl_conn_get_first_socket(data);
1035
6.58M
  if(sockfd != CURL_SOCKET_BAD) {
1036
3.23M
    result = Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0);
1037
3.23M
    if(!result)
1038
3.23M
      result = multi_adjust_pollset(data, ps);
1039
3.23M
  }
1040
6.58M
  if(!result)
1041
6.58M
    result = Curl_conn_adjust_pollset(data, conn, ps);
1042
6.58M
  return result;
1043
6.58M
}
1044
1045
static CURLcode mstate_protocol_pollset(struct Curl_easy *data,
1046
                                        struct easy_pollset *ps)
1047
23.9k
{
1048
23.9k
  struct connectdata *conn = data->conn;
1049
23.9k
  CURLcode result = CURLE_OK;
1050
1051
23.9k
  if(conn->scheme->run->proto_pollset)
1052
20.5k
    result = conn->scheme->run->proto_pollset(data, ps);
1053
3.40k
  else {
1054
3.40k
    curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1055
3.40k
    if(sockfd != CURL_SOCKET_BAD) {
1056
      /* Default is to wait to something from the server */
1057
3.40k
      result = Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0);
1058
3.40k
    }
1059
3.40k
  }
1060
23.9k
  if(!result)
1061
23.9k
    result = multi_adjust_pollset(data, ps);
1062
23.9k
  if(!result)
1063
23.9k
    result = Curl_conn_adjust_pollset(data, conn, ps);
1064
23.9k
  return result;
1065
23.9k
}
1066
1067
static CURLcode mstate_do_pollset(struct Curl_easy *data,
1068
                                  struct easy_pollset *ps)
1069
18.9k
{
1070
18.9k
  struct connectdata *conn = data->conn;
1071
18.9k
  CURLcode result = CURLE_OK;
1072
1073
18.9k
  if(conn->scheme->run->doing_pollset)
1074
18.9k
    result = conn->scheme->run->doing_pollset(data, ps);
1075
0
  else if(CONN_SOCK_IDX_VALID(conn->send_idx)) {
1076
    /* Default is that we want to send something to the server */
1077
0
    result = Curl_pollset_add_out(data, ps, conn->sock[conn->send_idx]);
1078
0
  }
1079
18.9k
  if(!result)
1080
18.9k
    result = multi_adjust_pollset(data, ps);
1081
18.9k
  if(!result)
1082
18.9k
    result = Curl_conn_adjust_pollset(data, conn, ps);
1083
18.9k
  return result;
1084
18.9k
}
1085
1086
static CURLcode mstate_domore_pollset(struct Curl_easy *data,
1087
                                      struct easy_pollset *ps)
1088
154k
{
1089
154k
  struct connectdata *conn = data->conn;
1090
154k
  CURLcode result = CURLE_OK;
1091
1092
154k
  if(conn->scheme->run->domore_pollset)
1093
154k
    result = conn->scheme->run->domore_pollset(data, ps);
1094
0
  else if(CONN_SOCK_IDX_VALID(conn->send_idx)) {
1095
    /* Default is that we want to send something to the server */
1096
0
    result = Curl_pollset_add_out(data, ps, conn->sock[conn->send_idx]);
1097
0
  }
1098
154k
  if(!result)
1099
154k
    result = multi_adjust_pollset(data, ps);
1100
154k
  if(!result)
1101
154k
    result = Curl_conn_adjust_pollset(data, conn, ps);
1102
154k
  return result;
1103
154k
}
1104
1105
static CURLcode mstate_perform_pollset(struct Curl_easy *data,
1106
                                       struct easy_pollset *ps)
1107
6.38M
{
1108
6.38M
  struct connectdata *conn = data->conn;
1109
6.38M
  CURLcode result = CURLE_OK;
1110
1111
6.38M
  if(conn->scheme->run->perform_pollset)
1112
6.38M
    result = conn->scheme->run->perform_pollset(data, ps);
1113
2.88k
  else {
1114
    /* Default is to obey the request flags for send/recv */
1115
2.88k
    if(Curl_req_want_recv(data) && CONN_SOCK_IDX_VALID(conn->recv_idx)) {
1116
1.55k
      result = Curl_pollset_add_in(data, ps, conn->sock[conn->recv_idx]);
1117
1.55k
    }
1118
2.88k
    if(!result && Curl_req_want_send(data) &&
1119
1.32k
       CONN_SOCK_IDX_VALID(conn->send_idx)) {
1120
1.32k
      result = Curl_pollset_add_out(data, ps, conn->sock[conn->send_idx]);
1121
1.32k
    }
1122
2.88k
  }
1123
6.38M
  if(!result)
1124
6.38M
    result = multi_adjust_pollset(data, ps);
1125
6.38M
  if(!result)
1126
6.38M
    result = Curl_conn_adjust_pollset(data, conn, ps);
1127
6.38M
  return result;
1128
6.38M
}
1129
1130
/* Initializes `poll_set` with the current socket poll actions needed
1131
 * for transfer `data`. */
1132
CURLMcode Curl_multi_pollset(struct Curl_easy *data,
1133
                             struct easy_pollset *ps)
1134
23.6M
{
1135
23.6M
  CURLcode result = CURLE_OK;
1136
1137
23.6M
  Curl_pollset_reset(ps);
1138
23.6M
#ifdef ENABLE_WAKEUP
1139
  /* The admin handle always listens on the wakeup socket when there
1140
   * are transfers alive. */
1141
23.6M
  if(data->multi && (data == data->multi->admin) &&
1142
10.4M
     data->multi->xfers_alive) {
1143
10.4M
    result = Curl_pollset_add_in(data, ps, data->multi->wakeup_pair[0]);
1144
10.4M
  }
1145
23.6M
#endif
1146
  /* If the transfer has no connection, this is fine. Happens when
1147
     called via curl_multi_remove_handle() => Curl_multi_ev_assess() =>
1148
     Curl_multi_pollset(). */
1149
23.6M
  if(!result && data->conn) {
1150
13.1M
    switch(data->mstate) {
1151
0
    case MSTATE_INIT:
1152
0
    case MSTATE_PENDING:
1153
0
    case MSTATE_SETUP:
1154
0
    case MSTATE_CONNECT:
1155
      /* nothing to poll for yet */
1156
0
      break;
1157
1158
6.58M
    case MSTATE_CONNECTING:
1159
6.58M
      if(data->conn && !data->conn->bits.dns_resolved)
1160
2.01M
        result = Curl_resolv_pollset(data, ps);
1161
6.58M
      if(!result)
1162
6.58M
        result = mstate_connecting_pollset(data, ps);
1163
6.58M
      break;
1164
1165
0
    case MSTATE_PROTOCONNECT:
1166
23.9k
    case MSTATE_PROTOCONNECTING:
1167
23.9k
      result = mstate_protocol_pollset(data, ps);
1168
23.9k
      break;
1169
1170
0
    case MSTATE_DO:
1171
18.9k
    case MSTATE_DOING:
1172
18.9k
      result = mstate_do_pollset(data, ps);
1173
18.9k
      break;
1174
1175
154k
    case MSTATE_DOING_MORE:
1176
154k
      result = mstate_domore_pollset(data, ps);
1177
154k
      break;
1178
1179
0
    case MSTATE_DID: /* same as PERFORMING in regard to polling */
1180
6.38M
    case MSTATE_PERFORMING:
1181
6.38M
      result = mstate_perform_pollset(data, ps);
1182
6.38M
      break;
1183
1184
1.52k
    case MSTATE_RATELIMITING:
1185
      /* we need to let time pass, ignore socket(s) */
1186
1.52k
      break;
1187
1188
0
    case MSTATE_DONE:
1189
0
    case MSTATE_COMPLETED:
1190
0
    case MSTATE_MSGSENT:
1191
      /* nothing more to poll for */
1192
0
      break;
1193
1194
0
    default:
1195
0
      failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
1196
0
      DEBUGASSERT(0);
1197
0
      break;
1198
13.1M
    }
1199
13.1M
  }
1200
1201
23.6M
  if(result) {
1202
0
    if(result == CURLE_OUT_OF_MEMORY)
1203
0
      return CURLM_OUT_OF_MEMORY;
1204
0
    failf(data, "error determining pollset: %d", result);
1205
0
    return CURLM_INTERNAL_ERROR;
1206
0
  }
1207
1208
23.6M
#ifdef CURLVERBOSE
1209
23.6M
  if(CURL_TRC_M_is_verbose(data)) {
1210
0
    size_t timeout_count = Curl_llist_count(&data->state.timeoutlist);
1211
0
    switch(ps->n) {
1212
0
    case 0:
1213
0
      CURL_TRC_M(data, "pollset[], timeouts=%zu, paused %d/%d (r/w)",
1214
0
                 timeout_count,
1215
0
                 Curl_xfer_send_is_paused(data),
1216
0
                 Curl_xfer_recv_is_paused(data));
1217
0
      break;
1218
0
    case 1:
1219
0
      CURL_TRC_M(data, "pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
1220
0
                 ps->sockets[0],
1221
0
                 (ps->actions[0] & CURL_POLL_IN) ? "IN" : "",
1222
0
                 (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "",
1223
0
                 timeout_count);
1224
0
      break;
1225
0
    case 2:
1226
0
      CURL_TRC_M(data, "pollset[fd=%" FMT_SOCKET_T " %s%s, "
1227
0
                 "fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
1228
0
                 ps->sockets[0],
1229
0
                 (ps->actions[0] & CURL_POLL_IN) ? "IN" : "",
1230
0
                 (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "",
1231
0
                 ps->sockets[1],
1232
0
                 (ps->actions[1] & CURL_POLL_IN) ? "IN" : "",
1233
0
                 (ps->actions[1] & CURL_POLL_OUT) ? "OUT" : "",
1234
0
                 timeout_count);
1235
0
      break;
1236
0
    default:
1237
0
      CURL_TRC_M(data, "pollset[fds=%u], timeouts=%zu", ps->n, timeout_count);
1238
0
      break;
1239
0
    }
1240
0
    CURL_TRC_EASY_TIMERS(data);
1241
0
  }
1242
23.6M
#endif
1243
1244
23.6M
  return CURLM_OK;
1245
23.6M
}
1246
1247
CURLMcode curl_multi_fdset(CURLM *m,
1248
                           fd_set *read_fd_set, fd_set *write_fd_set,
1249
                           fd_set *exc_fd_set, int *max_fd)
1250
10.4M
{
1251
  /* Scan through all the easy handles to get the file descriptors set.
1252
     Some easy handles may not have connected to the remote host yet,
1253
     and then we must make sure that is done. */
1254
10.4M
  int this_max_fd = -1;
1255
10.4M
  struct Curl_multi *multi = m;
1256
10.4M
  struct easy_pollset ps;
1257
10.4M
  unsigned int i;
1258
10.4M
  uint32_t mid;
1259
10.4M
  (void)exc_fd_set;
1260
1261
10.4M
  if(!GOOD_MULTI_HANDLE(multi))
1262
0
    return CURLM_BAD_HANDLE;
1263
1264
10.4M
  if(multi->in_callback)
1265
0
    return CURLM_RECURSIVE_API_CALL;
1266
1267
10.4M
  Curl_pollset_init(&ps);
1268
10.4M
  if(Curl_uint32_bset_first(&multi->process, &mid)) {
1269
23.6M
    do {
1270
23.6M
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
1271
1272
23.6M
      if(!data) {
1273
0
        DEBUGASSERT(0);
1274
0
        continue;
1275
0
      }
1276
1277
23.6M
      Curl_multi_pollset(data, &ps);
1278
45.2M
      for(i = 0; i < ps.n; i++) {
1279
21.6M
        if(!FDSET_SOCK(ps.sockets[i]))
1280
          /* pretend it does not exist */
1281
0
          continue;
1282
21.6M
        if(ps.actions[i] & CURL_POLL_IN)
1283
21.6M
          FD_SET(ps.sockets[i], read_fd_set);
1284
21.6M
        if(ps.actions[i] & CURL_POLL_OUT)
1285
21.6M
          FD_SET(ps.sockets[i], write_fd_set);
1286
21.6M
        if((int)ps.sockets[i] > this_max_fd)
1287
21.6M
          this_max_fd = (int)ps.sockets[i];
1288
21.6M
      }
1289
23.6M
    } while(Curl_uint32_bset_next(&multi->process, mid, &mid));
1290
10.4M
  }
1291
1292
10.4M
  Curl_cshutdn_setfds(&multi->cshutdn, multi->admin,
1293
10.4M
                      read_fd_set, write_fd_set, &this_max_fd);
1294
1295
10.4M
  *max_fd = this_max_fd;
1296
10.4M
  Curl_pollset_cleanup(&ps);
1297
1298
10.4M
  return CURLM_OK;
1299
10.4M
}
1300
1301
CURLMcode curl_multi_waitfds(CURLM *m,
1302
                             struct curl_waitfd *ufds,
1303
                             unsigned int size,
1304
                             unsigned int *fd_count)
1305
0
{
1306
0
  struct Curl_waitfds cwfds;
1307
0
  CURLMcode mresult = CURLM_OK;
1308
0
  struct Curl_multi *multi = m;
1309
0
  struct easy_pollset ps;
1310
0
  unsigned int need = 0;
1311
0
  uint32_t mid;
1312
1313
0
  if(!ufds && (size || !fd_count))
1314
0
    return CURLM_BAD_FUNCTION_ARGUMENT;
1315
1316
0
  if(!GOOD_MULTI_HANDLE(multi))
1317
0
    return CURLM_BAD_HANDLE;
1318
1319
0
  if(multi->in_callback)
1320
0
    return CURLM_RECURSIVE_API_CALL;
1321
1322
0
  Curl_pollset_init(&ps);
1323
0
  Curl_waitfds_init(&cwfds, ufds, size);
1324
0
  if(Curl_uint32_bset_first(&multi->process, &mid)) {
1325
0
    do {
1326
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
1327
0
      if(!data) {
1328
0
        DEBUGASSERT(0);
1329
0
        Curl_uint32_bset_remove(&multi->process, mid);
1330
0
        Curl_uint32_bset_remove(&multi->dirty, mid);
1331
0
        continue;
1332
0
      }
1333
0
      Curl_multi_pollset(data, &ps);
1334
0
      need += Curl_waitfds_add_ps(&cwfds, &ps);
1335
0
    } while(Curl_uint32_bset_next(&multi->process, mid, &mid));
1336
0
  }
1337
1338
0
  need += Curl_cshutdn_add_waitfds(&multi->cshutdn, multi->admin, &cwfds);
1339
1340
0
  if(need != cwfds.n && ufds)
1341
0
    mresult = CURLM_OUT_OF_MEMORY;
1342
1343
0
  if(fd_count)
1344
0
    *fd_count = need;
1345
0
  Curl_pollset_cleanup(&ps);
1346
0
  return mresult;
1347
0
}
1348
1349
#ifdef USE_WINSOCK
1350
/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets cannot
1351
 * be reset this way because an empty datagram would be sent. #9203
1352
 *
1353
 * "On Windows the internal state of FD_WRITE as returned from
1354
 * WSAEnumNetworkEvents is only reset after successful send()."
1355
 */
1356
static void reset_socket_fdwrite(curl_socket_t s)
1357
{
1358
  int t;
1359
  int l = (int)sizeof(t);
1360
  if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM)
1361
    swrite(s, NULL, 0);
1362
}
1363
1364
static CURLMcode multi_winsock_select(struct Curl_multi *multi,
1365
                                      struct curl_pollfds *cpfds,
1366
                                      unsigned int curl_nfds,
1367
                                      struct curl_waitfd extra_fds[],
1368
                                      unsigned int extra_nfds,
1369
                                      int timeout_ms,
1370
                                      bool extrawait,
1371
                                      int *pnevents)
1372
{
1373
  CURLMcode mresult = CURLM_OK;
1374
  WSANETWORKEVENTS wsa_events;
1375
  int nevents = 0;
1376
  size_t i;
1377
1378
  DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
1379
1380
  /* Set the WSA events based on the collected pollds */
1381
  for(i = 0; i < cpfds->n; i++) {
1382
    long mask = 0;
1383
    if(cpfds->pfds[i].events & POLLIN)
1384
      mask |= FD_READ | FD_ACCEPT | FD_CLOSE;
1385
    if(cpfds->pfds[i].events & POLLPRI)
1386
      mask |= FD_OOB;
1387
    if(cpfds->pfds[i].events & POLLOUT) {
1388
      mask |= FD_WRITE | FD_CONNECT | FD_CLOSE;
1389
      reset_socket_fdwrite(cpfds->pfds[i].fd);
1390
    }
1391
    if(mask) {
1392
      if(WSAEventSelect(cpfds->pfds[i].fd, multi->wsa_event, mask) != 0) {
1393
        mresult = CURLM_OUT_OF_MEMORY;
1394
        goto out;
1395
      }
1396
    }
1397
  }
1398
1399
  if(cpfds->n || extrawait) {
1400
    int pollrc = 0;
1401
1402
    if(cpfds->n) {         /* pre-check with Winsock */
1403
      pollrc = Curl_poll(cpfds->pfds, cpfds->n, 0);
1404
      if(pollrc < 0) {
1405
        mresult = CURLM_UNRECOVERABLE_POLL;
1406
        goto out;
1407
      }
1408
      nevents = pollrc;
1409
    }
1410
1411
    if(!nevents) {
1412
      /* now wait... if not ready during the pre-check (pollrc == 0) */
1413
      WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, (DWORD)timeout_ms,
1414
                               FALSE);
1415
    }
1416
1417
    /* With Winsock, we have to run the following section unconditionally
1418
       to call WSAEventSelect(fd, event, 0) on all the sockets */
1419
    /* copy revents results from the poll to the curl_multi_wait poll
1420
       struct, the bit values of the actual underlying poll() implementation
1421
       may not be the same as the ones in the public libcurl API! */
1422
    for(i = 0; i < extra_nfds; i++) {
1423
      unsigned short mask = 0;
1424
      curl_socket_t s = extra_fds[i].fd;
1425
1426
      wsa_events.lNetworkEvents = 0;
1427
      if(WSAEnumNetworkEvents(s, NULL, &wsa_events) == 0) {
1428
        if(wsa_events.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
1429
          mask |= CURL_WAIT_POLLIN;
1430
        if(wsa_events.lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE))
1431
          mask |= CURL_WAIT_POLLOUT;
1432
        if(wsa_events.lNetworkEvents & FD_OOB)
1433
          mask |= CURL_WAIT_POLLPRI;
1434
        if(!pollrc && wsa_events.lNetworkEvents)
1435
          nevents++;
1436
      }
1437
      WSAEventSelect(s, multi->wsa_event, 0);
1438
      if(!pollrc) {
1439
        extra_fds[i].revents = (short)mask;
1440
        continue;
1441
      }
1442
      else {
1443
        unsigned r = (unsigned)cpfds->pfds[curl_nfds + i].revents;
1444
        if(r & POLLIN)
1445
          mask |= CURL_WAIT_POLLIN;
1446
        if(r & POLLOUT)
1447
          mask |= CURL_WAIT_POLLOUT;
1448
        if(r & POLLPRI)
1449
          mask |= CURL_WAIT_POLLPRI;
1450
        extra_fds[i].revents = (short)mask;
1451
      }
1452
    }
1453
1454
    /* Count up all our own sockets that had activity,
1455
       and remove them from the event. */
1456
    for(i = 0; i < curl_nfds; ++i) {
1457
      wsa_events.lNetworkEvents = 0;
1458
      if(WSAEnumNetworkEvents(cpfds->pfds[i].fd, NULL, &wsa_events) == 0) {
1459
        if(!pollrc && wsa_events.lNetworkEvents)
1460
          nevents++;
1461
      }
1462
      WSAEventSelect(cpfds->pfds[i].fd, multi->wsa_event, 0);
1463
    }
1464
    WSAResetEvent(multi->wsa_event);
1465
  }
1466
1467
out:
1468
  *pnevents = nevents;
1469
  return mresult;
1470
}
1471
1472
#else /* USE_WINSOCK */
1473
1474
static CURLMcode multi_posix_poll(struct Curl_multi *multi,
1475
                                  struct curl_pollfds *cpfds,
1476
                                  unsigned int curl_nfds,
1477
                                  struct curl_waitfd extra_fds[],
1478
                                  unsigned int extra_nfds,
1479
                                  int timeout_ms,
1480
                                  bool extrawait,
1481
                                  int *pnevents)
1482
0
{
1483
0
  CURLMcode mresult = CURLM_OK;
1484
0
  int nevents = 0;
1485
0
  size_t i;
1486
1487
0
  (void)multi;
1488
0
  if(cpfds->n) {
1489
0
    int pollrc = Curl_poll(cpfds->pfds, cpfds->n, timeout_ms); /* wait... */
1490
0
    if(pollrc < 0) {
1491
0
      mresult = CURLM_UNRECOVERABLE_POLL;
1492
0
      goto out;
1493
0
    }
1494
0
    nevents = pollrc;
1495
1496
    /* copy revents results from the poll to the curl_multi_wait poll
1497
       struct, the bit values of the actual underlying poll() implementation
1498
       may not be the same as the ones in the public libcurl API! */
1499
0
    for(i = 0; i < extra_nfds; i++) {
1500
0
      unsigned r = (unsigned)cpfds->pfds[curl_nfds + i].revents;
1501
0
      unsigned short mask = 0;
1502
0
      if(r & POLLIN)
1503
0
        mask |= CURL_WAIT_POLLIN;
1504
0
      if(r & POLLOUT)
1505
0
        mask |= CURL_WAIT_POLLOUT;
1506
0
      if(r & POLLPRI)
1507
0
        mask |= CURL_WAIT_POLLPRI;
1508
0
      extra_fds[i].revents = (short)mask;
1509
0
    }
1510
0
  }
1511
0
  else if(extrawait) {
1512
    /* No fds to poll, but asked to obey timeout_ms anyway. We cannot
1513
     * use Curl_poll() as it, on some platforms, returns immediately
1514
     * without fds. */
1515
0
    curlx_wait_ms(timeout_ms);
1516
0
  }
1517
1518
0
out:
1519
0
  *pnevents = nevents;
1520
0
  return mresult;
1521
0
}
1522
1523
#endif /* !USE_WINSOCK */
1524
1525
0
#define NUM_POLLS_ON_STACK 10
1526
1527
static CURLMcode multi_wait(struct Curl_multi *multi,
1528
                            struct curl_waitfd extra_fds[],
1529
                            unsigned int extra_nfds,
1530
                            int timeout_ms,
1531
                            int *ret,
1532
                            bool extrawait)  /* when no socket, wait */
1533
0
{
1534
0
  size_t i;
1535
0
  struct curltime expire_time;
1536
0
  long timeout_internal;
1537
0
  int nevents = 0;
1538
0
  struct easy_pollset ps;
1539
0
  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
1540
0
  struct curl_pollfds cpfds;
1541
0
  unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
1542
0
  struct Curl_easy *data = NULL;
1543
0
  CURLMcode mresult = CURLM_OK;
1544
0
  uint32_t mid;
1545
0
#ifdef ENABLE_WAKEUP
1546
0
  int wakeup_idx = -1;
1547
0
#endif
1548
1549
0
  if(!GOOD_MULTI_HANDLE(multi))
1550
0
    return CURLM_BAD_HANDLE;
1551
1552
0
  if(multi->in_callback)
1553
0
    return CURLM_RECURSIVE_API_CALL;
1554
1555
0
  if(timeout_ms < 0)
1556
0
    return CURLM_BAD_FUNCTION_ARGUMENT;
1557
1558
0
  Curl_pollset_init(&ps);
1559
0
  Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
1560
1561
  /* Add the curl handles to our pollfds first */
1562
0
  if(Curl_uint32_bset_first(&multi->process, &mid)) {
1563
0
    do {
1564
0
      data = Curl_multi_get_easy(multi, mid);
1565
0
      if(!data) {
1566
0
        DEBUGASSERT(0);
1567
0
        Curl_uint32_bset_remove(&multi->process, mid);
1568
0
        Curl_uint32_bset_remove(&multi->dirty, mid);
1569
0
        continue;
1570
0
      }
1571
0
      Curl_multi_pollset(data, &ps);
1572
0
      if(Curl_pollfds_add_ps(&cpfds, &ps)) {
1573
0
        mresult = CURLM_OUT_OF_MEMORY;
1574
0
        goto out;
1575
0
      }
1576
0
    } while(Curl_uint32_bset_next(&multi->process, mid, &mid));
1577
0
  }
1578
1579
0
  if(Curl_cshutdn_add_pollfds(&multi->cshutdn, multi->admin, &cpfds)) {
1580
0
    mresult = CURLM_OUT_OF_MEMORY;
1581
0
    goto out;
1582
0
  }
1583
1584
0
#ifdef ENABLE_WAKEUP
1585
  /* If `extrawait` is TRUE *or* we have `extra_fds`to poll *or* we
1586
   * have transfer sockets to poll, we obey `timeout_ms`.
1587
   * Then we need to also monitor the multi's wakeup
1588
   * socket to catch calls to `curl_multi_wakeup()` during the wait. */
1589
0
  if(extrawait || cpfds.n || extra_nfds) {
1590
0
    wakeup_idx = cpfds.n;
1591
0
    if(Curl_pollfds_add_sock(&cpfds, multi->wakeup_pair[0], POLLIN)) {
1592
0
      mresult = CURLM_OUT_OF_MEMORY;
1593
0
      goto out;
1594
0
    }
1595
0
  }
1596
0
#endif
1597
1598
0
  curl_nfds = cpfds.n; /* what curl internally uses in cpfds */
1599
  /* Add external file descriptions from poll-like struct curl_waitfd */
1600
0
  for(i = 0; i < extra_nfds; i++) {
1601
0
    unsigned short events = 0;
1602
0
    if(extra_fds[i].events & CURL_WAIT_POLLIN)
1603
0
      events |= POLLIN;
1604
0
    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
1605
0
      events |= POLLPRI;
1606
0
    if(extra_fds[i].events & CURL_WAIT_POLLOUT)
1607
0
      events |= POLLOUT;
1608
0
    if(Curl_pollfds_add_sock(&cpfds, extra_fds[i].fd, events)) {
1609
0
      mresult = CURLM_OUT_OF_MEMORY;
1610
0
      goto out;
1611
0
    }
1612
0
  }
1613
1614
  /* We check the internal timeout *AFTER* we collected all sockets to
1615
   * poll. Collecting the sockets may install new timers by protocols
1616
   * and connection filters.
1617
   * Use the shorter one of the internal and the caller requested timeout.
1618
   * If we are called with `!extrawait` and multi_timeout() reports no
1619
   * timeouts exist, do not wait. */
1620
0
  multi_timeout(multi, &expire_time, &timeout_internal);
1621
0
  if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
1622
0
    timeout_ms = (int)timeout_internal;
1623
1624
0
  if(data)
1625
0
    CURL_TRC_M(data, "multi_wait(fds=%u, timeout=%d) tinternal=%ld",
1626
0
               cpfds.n, timeout_ms, timeout_internal);
1627
1628
#ifdef USE_WINSOCK
1629
  mresult = multi_winsock_select(multi, &cpfds, curl_nfds,
1630
                                 extra_fds, extra_nfds,
1631
                                 timeout_ms, extrawait, &nevents);
1632
#else
1633
0
  mresult = multi_posix_poll(multi, &cpfds, curl_nfds,
1634
0
                             extra_fds, extra_nfds,
1635
0
                             timeout_ms, extrawait, &nevents);
1636
0
#endif
1637
1638
0
#ifdef ENABLE_WAKEUP
1639
0
    if(nevents && (wakeup_idx >= 0)) {
1640
0
      if(cpfds.pfds[wakeup_idx].revents & POLLIN) {
1641
0
        (void)Curl_wakeup_consume(multi->wakeup_pair, TRUE);
1642
        /* do not count the wakeup socket into the returned value */
1643
0
        nevents--;
1644
0
      }
1645
0
    }
1646
0
#endif
1647
1648
0
out:
1649
0
  Curl_pollset_cleanup(&ps);
1650
0
  Curl_pollfds_cleanup(&cpfds);
1651
0
  if(ret)
1652
0
    *ret = nevents;
1653
0
  return mresult;
1654
0
}
1655
1656
CURLMcode curl_multi_wait(CURLM *m,
1657
                          struct curl_waitfd extra_fds[],
1658
                          unsigned int extra_nfds,
1659
                          int timeout_ms,
1660
                          int *ret)
1661
0
{
1662
0
  return multi_wait(m, extra_fds, extra_nfds, timeout_ms, ret, FALSE);
1663
0
}
1664
1665
CURLMcode curl_multi_poll(CURLM *m,
1666
                          struct curl_waitfd extra_fds[],
1667
                          unsigned int extra_nfds,
1668
                          int timeout_ms,
1669
                          int *ret)
1670
0
{
1671
0
  return multi_wait(m, extra_fds, extra_nfds, timeout_ms, ret, TRUE);
1672
0
}
1673
1674
CURLMcode curl_multi_wakeup(CURLM *m)
1675
8.19k
{
1676
  /* this function is usually called from another thread,
1677
     it has to be careful only to access parts of the
1678
     Curl_multi struct that are constant */
1679
8.19k
  struct Curl_multi *multi = m;
1680
8.19k
  CURLMcode mresult = CURLM_WAKEUP_FAILURE;
1681
1682
  /* GOOD_MULTI_HANDLE can be safely called */
1683
8.19k
  if(!GOOD_MULTI_HANDLE(multi))
1684
0
    return CURLM_BAD_HANDLE;
1685
1686
8.19k
#ifdef ENABLE_WAKEUP
1687
  /* the wakeup_pair variable is only written during init and cleanup,
1688
     making it safe to access from another thread after the init part
1689
     and before cleanup */
1690
8.19k
  if(!Curl_wakeup_signal(multi->wakeup_pair))
1691
8.19k
    mresult = CURLM_OK;
1692
8.19k
#endif
1693
#ifdef USE_WINSOCK
1694
  if(WSASetEvent(multi->wsa_event))
1695
    mresult = CURLM_OK;
1696
#endif
1697
8.19k
  return mresult;
1698
8.19k
}
1699
1700
/*
1701
 * multi_ischanged() is called
1702
 *
1703
 * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND
1704
 * => CONNECT action.
1705
 *
1706
 * Set 'clear' to TRUE to have it also clear the state variable.
1707
 */
1708
static bool multi_ischanged(struct Curl_multi *multi, bool clear)
1709
44.6M
{
1710
44.6M
  bool retval = FALSE;
1711
44.6M
  DEBUGASSERT(multi);
1712
44.6M
  if(multi) {
1713
44.6M
    retval = (bool)multi->recheckstate;
1714
44.6M
    if(clear)
1715
24.7M
      multi->recheckstate = FALSE;
1716
44.6M
  }
1717
44.6M
  return retval;
1718
44.6M
}
1719
1720
/*
1721
 * Curl_multi_connchanged() is called to tell that there is a connection in
1722
 * this multi handle that has changed state (multiplexing become possible, the
1723
 * number of allowed streams changed or similar), and a subsequent use of this
1724
 * multi handle should move CONNECT_PEND handles back to CONNECT to have them
1725
 * retry.
1726
 */
1727
void Curl_multi_connchanged(struct Curl_multi *multi)
1728
157k
{
1729
157k
  multi->recheckstate = TRUE;
1730
157k
}
1731
1732
CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
1733
                                 struct Curl_easy *data,
1734
                                 struct connectdata *conn)
1735
0
{
1736
0
  CURLMcode mresult;
1737
1738
0
  if(multi->in_callback)
1739
0
    return CURLM_RECURSIVE_API_CALL;
1740
1741
0
  mresult = curl_multi_add_handle(multi, data);
1742
0
  if(!mresult) {
1743
0
    CURLcode result;
1744
1745
    /* pass in NULL for 'conn' here since we do not want to init the
1746
       connection, only this transfer */
1747
0
    result = Curl_init_do(data, NULL);
1748
0
    if(result) {
1749
0
      curl_multi_remove_handle(multi, data);
1750
0
      return CURLM_INTERNAL_ERROR;
1751
0
    }
1752
1753
    /* take this handle to the perform state right away */
1754
0
    multistate(data, MSTATE_PERFORMING);
1755
0
    Curl_attach_connection(data, conn);
1756
0
    CURL_REQ_SET_RECV(data);
1757
0
  }
1758
0
  return mresult;
1759
0
}
1760
1761
static CURLcode multi_do(struct Curl_easy *data, bool *done)
1762
67.7k
{
1763
67.7k
  CURLcode result = CURLE_OK;
1764
67.7k
  struct connectdata *conn = data->conn;
1765
1766
67.7k
  DEBUGASSERT(conn);
1767
67.7k
  DEBUGASSERT(conn->scheme);
1768
1769
67.7k
  if(conn->scheme->run->do_it)
1770
67.7k
    result = conn->scheme->run->do_it(data, done);
1771
1772
67.7k
  return result;
1773
67.7k
}
1774
1775
/*
1776
 * multi_do_more() is called during the DO_MORE multi state. It is a second
1777
 * stage DO state which (wrongly) was introduced to support FTP's second
1778
 * connection.
1779
 *
1780
 * 'complete' can return DOMORE_INCOMPLETE, DOMORE_DONE or DOMORE_GOBACK
1781
 * (to DOING state when there is more work to do)
1782
 */
1783
1784
static CURLcode multi_do_more(struct Curl_easy *data, domore *complete)
1785
155k
{
1786
155k
  CURLcode result = CURLE_OK;
1787
155k
  struct connectdata *conn = data->conn;
1788
1789
155k
  *complete = DOMORE_INCOMPLETE;
1790
1791
155k
  if(conn->scheme->run->do_more)
1792
155k
    result = conn->scheme->run->do_more(data, complete);
1793
1794
155k
  return result;
1795
155k
}
1796
1797
/*
1798
 * Check whether a timeout occurred, and handle it if it did
1799
 */
1800
static bool multi_handle_timeout(struct Curl_easy *data,
1801
                                 bool *stream_error,
1802
                                 CURLcode *result)
1803
20.3M
{
1804
20.3M
  timediff_t timeout_ms;
1805
1806
20.3M
  timeout_ms = Curl_timeleft_ms(data);
1807
20.3M
  if(timeout_ms < 0) {
1808
    /* Handle timed out */
1809
1.12k
    struct curltime since;
1810
1.12k
    if(Curl_is_connecting(data))
1811
490
      since = data->progress.t_startsingle;
1812
636
    else
1813
636
      since = data->progress.t_startop;
1814
1.12k
    if(data->mstate == MSTATE_CONNECTING)
1815
469
      failf(data, "%s timed out after %" FMT_TIMEDIFF_T " milliseconds",
1816
469
            data->conn->bits.dns_resolved ? "Connection" : "Resolving",
1817
469
            curlx_ptimediff_ms(Curl_pgrs_now(data), &since));
1818
657
    else {
1819
657
      struct SingleRequest *k = &data->req;
1820
657
      if(k->size != -1) {
1821
16
        failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
1822
16
              " milliseconds with %" FMT_OFF_T " out of %"
1823
16
              FMT_OFF_T " bytes received",
1824
16
              curlx_ptimediff_ms(Curl_pgrs_now(data), &since),
1825
16
              k->bytecount, k->size);
1826
16
      }
1827
641
      else {
1828
641
        failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
1829
641
              " milliseconds with %" FMT_OFF_T " bytes received",
1830
641
              curlx_ptimediff_ms(Curl_pgrs_now(data), &since),
1831
641
              k->bytecount);
1832
641
      }
1833
657
    }
1834
1.12k
    *result = CURLE_OPERATION_TIMEDOUT;
1835
1.12k
    if(data->conn) {
1836
      /* Force connection closed if the connection has indeed been used */
1837
1.11k
      if(data->mstate > MSTATE_DO) {
1838
636
        streamclose(data->conn, "Disconnect due to timeout");
1839
636
        *stream_error = TRUE;
1840
636
      }
1841
1.11k
      (void)multi_done(data, *result, TRUE);
1842
1.11k
    }
1843
1.12k
    return TRUE;
1844
1.12k
  }
1845
1846
20.3M
  return FALSE;
1847
20.3M
}
1848
1849
/*
1850
 * We are doing protocol-specific connecting and this is being called over and
1851
 * over from the multi interface until the connection phase is done on
1852
 * protocol layer.
1853
 */
1854
1855
static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
1856
29.8k
{
1857
29.8k
  CURLcode result = CURLE_OK;
1858
29.8k
  struct connectdata *conn = data->conn;
1859
1860
29.8k
  if(conn && conn->scheme->run->connecting) {
1861
29.8k
    *done = FALSE;
1862
29.8k
    result = conn->scheme->run->connecting(data, done);
1863
29.8k
  }
1864
0
  else
1865
0
    *done = TRUE;
1866
1867
29.8k
  return result;
1868
29.8k
}
1869
1870
/*
1871
 * We are DOING this is being called over and over from the multi interface
1872
 * until the DOING phase is done on protocol layer.
1873
 */
1874
1875
static CURLcode protocol_doing(struct Curl_easy *data, bool *done)
1876
22.5k
{
1877
22.5k
  CURLcode result = CURLE_OK;
1878
22.5k
  struct connectdata *conn = data->conn;
1879
1880
22.5k
  if(conn && conn->scheme->run->doing) {
1881
22.5k
    *done = FALSE;
1882
22.5k
    result = conn->scheme->run->doing(data, done);
1883
22.5k
  }
1884
0
  else
1885
0
    *done = TRUE;
1886
1887
22.5k
  return result;
1888
22.5k
}
1889
1890
/*
1891
 * We have discovered that the TCP connection has been successful, we can now
1892
 * proceed with some action.
1893
 *
1894
 */
1895
static CURLcode protocol_connect(struct Curl_easy *data, bool *protocol_done)
1896
59.7k
{
1897
59.7k
  struct connectdata *conn = data->conn;
1898
59.7k
  CURLcode result = CURLE_OK;
1899
1900
59.7k
  DEBUGASSERT(conn);
1901
59.7k
  DEBUGASSERT(protocol_done);
1902
59.7k
  DEBUGASSERT(Curl_conn_is_connected(conn, FIRSTSOCKET));
1903
1904
59.7k
  *protocol_done = FALSE;
1905
59.7k
  if(!conn->bits.protoconnstart) {
1906
59.7k
    if(conn->scheme->run->connect_it) {
1907
      /* Call the protocol-specific connect function */
1908
20.2k
      result = conn->scheme->run->connect_it(data, protocol_done);
1909
20.2k
      if(result)
1910
2.53k
        return result;
1911
20.2k
    }
1912
57.1k
    conn->bits.protoconnstart = TRUE;
1913
57.1k
  }
1914
1915
  /* Unless this protocol does not have any protocol-connect callback, as
1916
     then we know we are done. */
1917
57.1k
  if(!conn->scheme->run->connecting)
1918
47.7k
    *protocol_done = TRUE;
1919
57.1k
  return CURLE_OK;
1920
59.7k
}
1921
1922
static void set_in_callback(struct Curl_multi *multi, bool value)
1923
0
{
1924
0
  multi->in_callback = value;
1925
0
}
1926
1927
/*
1928
 * posttransfer() is called immediately after a transfer ends
1929
 */
1930
static void multi_posttransfer(struct Curl_easy *data)
1931
151k
{
1932
#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(MSG_NOSIGNAL)
1933
  /* restore the signal handler for SIGPIPE before we get back */
1934
  if(!data->set.no_signal)
1935
    signal(SIGPIPE, data->state.prev_signal);
1936
#else
1937
151k
  (void)data;
1938
151k
#endif
1939
151k
}
1940
1941
/*
1942
 * multi_follow() handles the URL redirect magic. Pass in the 'newurl' string
1943
 * as given by the remote server and set up the new URL to request.
1944
 *
1945
 * This function DOES NOT FREE the given URL.
1946
 */
1947
static CURLcode multi_follow(struct Curl_easy *data,
1948
                             const struct Curl_scheme *handler,
1949
                             const char *newurl, /* the Location: string */
1950
                             followtype type) /* see transfer.h */
1951
18.6k
{
1952
18.6k
  if(handler && handler->run->follow)
1953
18.6k
    return handler->run->follow(data, newurl, type);
1954
1955
0
  if(type == FOLLOW_RETRY)
1956
    /* Retries are generic and do not require protocol-specific redirect
1957
       handling. */
1958
0
    return CURLE_OK;
1959
1960
0
  return CURLE_TOO_MANY_REDIRECTS;
1961
0
}
1962
1963
static CURLcode mspeed_check(struct Curl_easy *data)
1964
12.8M
{
1965
12.8M
  if(Curl_rlimit_active(&data->progress.dl.rlimit) ||
1966
7.19M
     Curl_rlimit_active(&data->progress.ul.rlimit)) {
1967
    /* check if our send/recv limits require idle waits */
1968
6.74M
    const struct curltime *pnow = Curl_pgrs_now(data);
1969
6.74M
    timediff_t recv_ms, send_ms;
1970
1971
6.74M
    send_ms = Curl_rlimit_wait_ms(&data->progress.ul.rlimit, pnow);
1972
6.74M
    recv_ms = Curl_rlimit_wait_ms(&data->progress.dl.rlimit, pnow);
1973
1974
6.74M
    if(send_ms || recv_ms) {
1975
1.59k
      if(data->mstate != MSTATE_RATELIMITING) {
1976
607
        multistate(data, MSTATE_RATELIMITING);
1977
607
      }
1978
1.59k
      Curl_expire(data, CURLMAX(send_ms, recv_ms), EXPIRE_TOOFAST);
1979
1.59k
      Curl_multi_clear_dirty(data);
1980
1.59k
      CURL_TRC_M(data, "[RLIMIT] waiting %" FMT_TIMEDIFF_T "ms",
1981
1.59k
                 CURLMAX(send_ms, recv_ms));
1982
1.59k
      return CURLE_AGAIN;
1983
1.59k
    }
1984
6.74M
    else {
1985
      /* when will the rate limits increase next? The transfer needs
1986
       * to run again at that time or it may stall. */
1987
6.74M
      send_ms = Curl_rlimit_next_step_ms(&data->progress.ul.rlimit, pnow);
1988
6.74M
      recv_ms = Curl_rlimit_next_step_ms(&data->progress.dl.rlimit, pnow);
1989
6.74M
      if(send_ms || recv_ms) {
1990
6.74M
        timediff_t next_ms = CURLMIN(send_ms, recv_ms);
1991
6.74M
        if(!next_ms)
1992
4.74M
          next_ms = CURLMAX(send_ms, recv_ms);
1993
6.74M
        Curl_expire(data, next_ms, EXPIRE_TOOFAST);
1994
6.74M
        CURL_TRC_M(data, "[RLIMIT] next token update in %" FMT_TIMEDIFF_T "ms",
1995
6.74M
                   next_ms);
1996
6.74M
      }
1997
6.74M
    }
1998
6.74M
  }
1999
2000
12.8M
  if(data->mstate != MSTATE_PERFORMING) {
2001
28
    CURL_TRC_M(data, "[RLIMIT] wait over, continue");
2002
28
    multistate(data, MSTATE_PERFORMING);
2003
28
  }
2004
12.8M
  return CURLE_OK;
2005
12.8M
}
2006
2007
static CURLMcode multistate_performing(struct Curl_easy *data,
2008
                                       bool *stream_errorp,
2009
                                       CURLcode *resultp)
2010
6.45M
{
2011
6.45M
  char *newurl = NULL;
2012
6.45M
  bool retry = FALSE;
2013
6.45M
  CURLMcode mresult = CURLM_OK;
2014
6.45M
  CURLcode result = *resultp = CURLE_OK;
2015
6.45M
  *stream_errorp = FALSE;
2016
2017
6.45M
  if(mspeed_check(data) == CURLE_AGAIN)
2018
181
    return CURLM_OK;
2019
2020
  /* read/write data if it is ready to do so */
2021
6.45M
  result = Curl_sendrecv(data);
2022
2023
6.45M
  if(data->req.done || (result == CURLE_RECV_ERROR)) {
2024
    /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
2025
     * condition and the server closed the reused connection exactly when we
2026
     * wanted to use it, so figure out if that is indeed the case.
2027
     */
2028
36.3k
    CURLcode ret = Curl_retry_request(data, &newurl);
2029
36.3k
    if(!ret)
2030
36.3k
      retry = !!newurl;
2031
0
    else if(!result)
2032
0
      result = ret;
2033
2034
36.3k
    if(retry) {
2035
      /* if we are to retry, set the result to OK and consider the
2036
         request as done */
2037
2.10k
      result = CURLE_OK;
2038
2.10k
      data->req.done = TRUE;
2039
2.10k
    }
2040
36.3k
  }
2041
6.41M
#ifndef CURL_DISABLE_HTTP
2042
6.41M
  else if((result == CURLE_HTTP2_STREAM) &&
2043
2.05k
          Curl_h2_http_1_1_error(data)) {
2044
139
    CURLcode ret = Curl_retry_request(data, &newurl);
2045
2046
139
    if(!ret) {
2047
139
      infof(data, "Downgrades to HTTP/1.1");
2048
139
      streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
2049
139
      data->state.http_neg.wanted = CURL_HTTP_V1x;
2050
139
      data->state.http_neg.allowed = CURL_HTTP_V1x;
2051
      /* clear the error message bit too as we ignore the one we got */
2052
139
      data->state.errorbuf = FALSE;
2053
139
      if(!newurl)
2054
        /* typically for HTTP_1_1_REQUIRED error on first flight */
2055
139
        newurl = Curl_bufref_dup(&data->state.url);
2056
139
      if(!newurl) {
2057
0
        result = CURLE_OUT_OF_MEMORY;
2058
0
      }
2059
139
      else {
2060
        /* if we are to retry, set the result to OK and consider the request
2061
          as done */
2062
139
        retry = TRUE;
2063
139
        result = CURLE_OK;
2064
139
        data->req.done = TRUE;
2065
139
      }
2066
139
    }
2067
0
    else
2068
0
      result = ret;
2069
139
  }
2070
6.45M
#endif
2071
2072
6.45M
  if(result) {
2073
    /*
2074
     * The transfer phase returned error, we mark the connection to get closed
2075
     * to prevent being reused. This is because we cannot possibly know if the
2076
     * connection is in a good shape or not now. Unless it is a protocol which
2077
     * uses two "channels" like FTP, as then the error happened in the data
2078
     * connection.
2079
     */
2080
2081
25.2k
    if(!(data->conn->scheme->flags & PROTOPT_DUAL) &&
2082
25.2k
       result != CURLE_HTTP2_STREAM)
2083
23.3k
      streamclose(data->conn, "Transfer returned error");
2084
2085
25.2k
    multi_posttransfer(data);
2086
25.2k
    multi_done(data, result, TRUE);
2087
25.2k
  }
2088
6.42M
  else if(data->req.done && !Curl_cwriter_is_paused(data)) {
2089
35.4k
    const struct Curl_scheme *handler = data->conn->scheme;
2090
2091
    /* call this even if the readwrite function returned error */
2092
35.4k
    multi_posttransfer(data);
2093
2094
    /* When we follow redirects or is set to retry the connection, we must to
2095
       go back to the CONNECT state */
2096
35.4k
    if(data->req.newurl || retry) {
2097
17.9k
      followtype follow = FOLLOW_NONE;
2098
17.9k
      if(!retry) {
2099
        /* if the URL is a follow-location and not a retried request then
2100
           figure out the URL here */
2101
15.7k
        curlx_free(newurl);
2102
15.7k
        newurl = data->req.newurl;
2103
15.7k
        data->req.newurl = NULL;
2104
15.7k
        follow = FOLLOW_REDIR;
2105
15.7k
      }
2106
2.24k
      else
2107
2.24k
        follow = FOLLOW_RETRY;
2108
17.9k
      (void)multi_done(data, CURLE_OK, FALSE);
2109
      /* multi_done() might return CURLE_GOT_NOTHING */
2110
17.9k
      result = multi_follow(data, handler, newurl, follow);
2111
17.9k
      if(!result) {
2112
17.7k
        multistate(data, MSTATE_SETUP);
2113
17.7k
        mresult = CURLM_CALL_MULTI_PERFORM;
2114
17.7k
      }
2115
17.9k
    }
2116
17.4k
    else {
2117
      /* after the transfer is done, go DONE */
2118
2119
      /* but first check to see if we got a location info even though we are
2120
         not following redirects */
2121
17.4k
      if(data->req.location) {
2122
698
        curlx_free(newurl);
2123
698
        newurl = data->req.location;
2124
698
        data->req.location = NULL;
2125
698
        result = multi_follow(data, handler, newurl, FOLLOW_FAKE);
2126
698
        if(result) {
2127
1
          *stream_errorp = TRUE;
2128
1
          result = multi_done(data, result, TRUE);
2129
1
        }
2130
698
      }
2131
2132
17.4k
      if(!result) {
2133
17.4k
        multistate(data, MSTATE_DONE);
2134
17.4k
        mresult = CURLM_CALL_MULTI_PERFORM;
2135
17.4k
      }
2136
17.4k
    }
2137
35.4k
  }
2138
6.39M
  else { /* not errored, not done */
2139
6.39M
    mspeed_check(data);
2140
6.39M
  }
2141
6.45M
  curlx_free(newurl);
2142
6.45M
  *resultp = result;
2143
6.45M
  return mresult;
2144
6.45M
}
2145
2146
static CURLMcode multistate_do(struct Curl_easy *data,
2147
                               bool *stream_errorp,
2148
                               CURLcode *resultp)
2149
67.8k
{
2150
67.8k
  CURLMcode mresult = CURLM_OK;
2151
67.8k
  CURLcode result = CURLE_OK;
2152
67.8k
  if(data->set.fprereq) {
2153
0
    int prereq_rc;
2154
2155
    /* call the prerequest callback function */
2156
0
    Curl_set_in_callback(data, TRUE);
2157
0
    prereq_rc = data->set.fprereq(data->set.prereq_userp,
2158
0
                                  data->info.primary.remote_ip,
2159
0
                                  data->info.primary.local_ip,
2160
0
                                  data->info.primary.remote_port,
2161
0
                                  data->info.primary.local_port);
2162
0
    Curl_set_in_callback(data, FALSE);
2163
0
    if(prereq_rc != CURL_PREREQFUNC_OK) {
2164
0
      failf(data, "operation aborted by pre-request callback");
2165
      /* failure in pre-request callback - do not do any other processing */
2166
0
      result = CURLE_ABORTED_BY_CALLBACK;
2167
0
      multi_posttransfer(data);
2168
0
      multi_done(data, result, FALSE);
2169
0
      *stream_errorp = TRUE;
2170
0
      goto end;
2171
0
    }
2172
0
  }
2173
2174
67.8k
  if(data->set.connect_only && !data->set.connect_only_ws) {
2175
99
    multistate(data, MSTATE_DONE);
2176
99
    mresult = CURLM_CALL_MULTI_PERFORM;
2177
99
  }
2178
67.7k
  else {
2179
67.7k
    bool dophase_done = FALSE;
2180
    /* Perform the protocol's DO action */
2181
67.7k
    result = multi_do(data, &dophase_done);
2182
2183
    /* When multi_do() returns failure, data->conn might be NULL! */
2184
2185
67.7k
    if(!result) {
2186
65.9k
      if(!dophase_done) {
2187
3.74k
#ifndef CURL_DISABLE_FTP
2188
        /* some steps needed for wildcard matching */
2189
3.74k
        if(data->state.wildcardmatch) {
2190
440
          struct WildcardData *wc = data->wildcard;
2191
440
          if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
2192
            /* skip some states if it is important */
2193
7
            multi_done(data, CURLE_OK, FALSE);
2194
2195
            /* if there is no connection left, skip the DONE state */
2196
7
            multistate(data, data->conn ? MSTATE_DONE : MSTATE_COMPLETED);
2197
7
            mresult = CURLM_CALL_MULTI_PERFORM;
2198
7
            goto end;
2199
7
          }
2200
440
        }
2201
3.73k
#endif
2202
        /* DO was not completed in one function call, we must continue
2203
           DOING... */
2204
3.73k
        multistate(data, MSTATE_DOING);
2205
3.73k
        mresult = CURLM_CALL_MULTI_PERFORM;
2206
3.73k
      }
2207
2208
      /* after DO, go DO_DONE... or DO_MORE */
2209
62.2k
      else if(data->conn->bits.do_more) {
2210
        /* we are supposed to do more, but we need to sit down, relax and wait
2211
           a little while first */
2212
2
        multistate(data, MSTATE_DOING_MORE);
2213
2
        mresult = CURLM_CALL_MULTI_PERFORM;
2214
2
      }
2215
62.2k
      else {
2216
        /* we are done with the DO, now DID */
2217
62.2k
        multistate(data, MSTATE_DID);
2218
62.2k
        mresult = CURLM_CALL_MULTI_PERFORM;
2219
62.2k
      }
2220
65.9k
    }
2221
1.75k
    else if((result == CURLE_SEND_ERROR) &&
2222
93
            data->conn->bits.reuse) {
2223
      /*
2224
       * In this situation, a connection that we were trying to use may have
2225
       * unexpectedly died. If possible, send the connection back to the
2226
       * CONNECT phase so we can try again.
2227
       */
2228
1
      const struct Curl_scheme *handler = data->conn->scheme;
2229
1
      char *newurl = NULL;
2230
1
      followtype follow = FOLLOW_NONE;
2231
1
      CURLcode drc;
2232
2233
1
      drc = Curl_retry_request(data, &newurl);
2234
1
      if(drc) {
2235
        /* a failure here pretty much implies an out of memory */
2236
0
        result = drc;
2237
0
        *stream_errorp = TRUE;
2238
0
      }
2239
2240
1
      multi_posttransfer(data);
2241
1
      drc = multi_done(data, result, FALSE);
2242
2243
      /* When set to retry the connection, we must go back to the CONNECT
2244
       * state */
2245
1
      if(newurl) {
2246
1
        if(!drc || (drc == CURLE_SEND_ERROR)) {
2247
1
          follow = FOLLOW_RETRY;
2248
1
          drc = multi_follow(data, handler, newurl, follow);
2249
1
          if(!drc) {
2250
1
            multistate(data, MSTATE_SETUP);
2251
1
            mresult = CURLM_CALL_MULTI_PERFORM;
2252
1
            result = CURLE_OK;
2253
1
          }
2254
0
          else {
2255
            /* Follow failed */
2256
0
            result = drc;
2257
0
          }
2258
1
        }
2259
0
        else {
2260
          /* done did not return OK or SEND_ERROR */
2261
0
          result = drc;
2262
0
        }
2263
1
      }
2264
0
      else {
2265
        /* Have error handler disconnect conn if we cannot retry */
2266
0
        *stream_errorp = TRUE;
2267
0
      }
2268
1
      curlx_free(newurl);
2269
1
    }
2270
1.75k
    else {
2271
      /* failure detected */
2272
1.75k
      multi_posttransfer(data);
2273
1.75k
      if(data->conn)
2274
1.75k
        multi_done(data, result, FALSE);
2275
1.75k
      *stream_errorp = TRUE;
2276
1.75k
    }
2277
67.7k
  }
2278
67.8k
end:
2279
67.8k
  *resultp = result;
2280
67.8k
  return mresult;
2281
67.8k
}
2282
2283
static CURLMcode multistate_ratelimiting(struct Curl_easy *data,
2284
                                         CURLcode *resultp)
2285
1.01k
{
2286
1.01k
  CURLcode result = CURLE_OK;
2287
1.01k
  CURLMcode mresult = CURLM_OK;
2288
1.01k
  DEBUGASSERT(data->conn);
2289
  /* if both rates are within spec, resume transfer */
2290
1.01k
  result = Curl_pgrsCheck(data);
2291
2292
1.01k
  if(result) {
2293
0
    if(!(data->conn->scheme->flags & PROTOPT_DUAL) &&
2294
0
       result != CURLE_HTTP2_STREAM)
2295
0
      streamclose(data->conn, "Transfer returned error");
2296
2297
0
    multi_posttransfer(data);
2298
0
    multi_done(data, result, TRUE);
2299
0
  }
2300
1.01k
  else {
2301
1.01k
    if(!mspeed_check(data))
2302
28
      mresult = CURLM_CALL_MULTI_PERFORM;
2303
1.01k
  }
2304
1.01k
  *resultp = result;
2305
1.01k
  return mresult;
2306
1.01k
}
2307
2308
static CURLMcode multistate_connect(struct Curl_multi *multi,
2309
                                    struct Curl_easy *data,
2310
                                    CURLcode *resultp)
2311
161k
{
2312
  /* Connect. We want to get a connection identifier filled in. This state can
2313
     be entered from SETUP and from PENDING. */
2314
161k
  bool connected;
2315
161k
  CURLMcode mresult = CURLM_OK;
2316
161k
  CURLcode result = Curl_connect(data, &connected);
2317
161k
  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
2318
    /* There was no connection available. We will go to the pending state and
2319
       wait for an available connection. */
2320
2.89k
    multistate(data, MSTATE_PENDING);
2321
    /* move from process to pending set */
2322
2.89k
    Curl_uint32_bset_remove(&multi->process, data->mid);
2323
2.89k
    Curl_uint32_bset_remove(&multi->dirty, data->mid);
2324
2.89k
    Curl_uint32_bset_add(&multi->pending, data->mid);
2325
2.89k
    *resultp = CURLE_OK;
2326
2.89k
    return mresult;
2327
2.89k
  }
2328
158k
  else
2329
158k
    process_pending_handles(data->multi);
2330
2331
158k
  if(!result) {
2332
    /* after the connect has been sent off, go WAITCONNECT unless the
2333
       protocol connect is already done and we can go directly to WAITDO or
2334
       DO! */
2335
136k
    mresult = CURLM_CALL_MULTI_PERFORM;
2336
2337
136k
    if(connected) {
2338
1.14k
      if(!data->conn->bits.reuse &&
2339
1.14k
         Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
2340
        /* new connection, can multiplex, wake pending handles */
2341
0
        process_pending_handles(data->multi);
2342
0
      }
2343
1.14k
      multistate(data, MSTATE_PROTOCONNECT);
2344
1.14k
    }
2345
135k
    else {
2346
135k
      multistate(data, MSTATE_CONNECTING);
2347
135k
    }
2348
136k
  }
2349
158k
  *resultp = result;
2350
158k
  return mresult;
2351
161k
}
2352
2353
/* returns the possibly updated result */
2354
static CURLcode is_finished(struct Curl_multi *multi,
2355
                            struct Curl_easy *data,
2356
                            bool stream_error,
2357
                            CURLcode result)
2358
14.1M
{
2359
14.1M
  if(data->mstate < MSTATE_COMPLETED) {
2360
14.0M
    if(result) {
2361
      /*
2362
       * If an error was returned, and we are not in completed state now,
2363
       * then we go to completed and consider this transfer aborted.
2364
       */
2365
2366
      /* No attempt to disconnect connections must be made before this -
2367
         connection detach and termination happens only here */
2368
2369
      /* Check if we can move pending requests to send pipe */
2370
167k
      process_pending_handles(multi); /* connection */
2371
2372
167k
      if(data->conn) {
2373
0
        if(stream_error) {
2374
          /* Do not attempt to send data over a connection that timed out */
2375
0
          bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
2376
0
          struct connectdata *conn = data->conn;
2377
2378
          /* This is where we make sure that the conn pointer is reset.
2379
             We do not have to do this in every case block above where a
2380
             failure is detected */
2381
0
          Curl_detach_connection(data);
2382
0
          Curl_conn_terminate(data, conn, dead_connection);
2383
0
        }
2384
0
      }
2385
167k
      else if(data->mstate == MSTATE_CONNECT) {
2386
        /* Curl_connect() failed */
2387
22.0k
        multi_posttransfer(data);
2388
22.0k
        Curl_pgrsUpdate_nometer(data);
2389
22.0k
      }
2390
2391
167k
      multistate(data, MSTATE_COMPLETED);
2392
167k
      return result;
2393
167k
    }
2394
    /* if there is still a connection to use, call the progress function */
2395
13.9M
    else if(data->conn && Curl_conn_is_connected(data->conn, FIRSTSOCKET)) {
2396
6.90M
      result = Curl_pgrsUpdate(data);
2397
6.90M
      if(result) {
2398
        /* aborted due to progress callback return code must close the
2399
           connection */
2400
0
        streamclose(data->conn, "Aborted by callback");
2401
2402
        /* if not yet in DONE state, go there, otherwise COMPLETED */
2403
0
        multistate(data, (data->mstate < MSTATE_DONE) ?
2404
0
                   MSTATE_DONE : MSTATE_COMPLETED);
2405
0
        return result;
2406
0
      }
2407
6.90M
    }
2408
14.0M
  }
2409
13.9M
  return result;
2410
14.1M
}
2411
2412
static void handle_completed(struct Curl_multi *multi,
2413
                             struct Curl_easy *data,
2414
                             CURLcode result)
2415
184k
{
2416
184k
  if(data->master_mid != UINT32_MAX) {
2417
    /* A sub transfer, not for msgsent to application */
2418
6.95k
    struct Curl_easy *mdata;
2419
2420
6.95k
    CURL_TRC_M(data, "sub xfer done for master %u", data->master_mid);
2421
6.95k
    mdata = Curl_multi_get_easy(multi, data->master_mid);
2422
6.95k
    if(mdata) {
2423
6.95k
      if(mdata->sub_xfer_done)
2424
6.95k
        mdata->sub_xfer_done(mdata, data, result);
2425
0
      else
2426
0
        CURL_TRC_M(data, "master easy %u without sub_xfer_done callback.",
2427
6.95k
                   data->master_mid);
2428
6.95k
    }
2429
0
    else {
2430
0
      CURL_TRC_M(data, "master easy %u already gone.", data->master_mid);
2431
0
    }
2432
6.95k
  }
2433
177k
  else {
2434
    /* now fill in the Curl_message with this info */
2435
177k
    struct Curl_message *msg = &data->msg;
2436
2437
177k
    msg->extmsg.msg = CURLMSG_DONE;
2438
177k
    msg->extmsg.easy_handle = data;
2439
177k
    msg->extmsg.data.result = result;
2440
2441
177k
    multi_addmsg(multi, msg);
2442
177k
    DEBUGASSERT(!data->conn);
2443
177k
  }
2444
184k
  multistate(data, MSTATE_MSGSENT);
2445
2446
  /* remove from the other sets, add to msgsent */
2447
184k
  Curl_uint32_bset_remove(&multi->process, data->mid);
2448
184k
  Curl_uint32_bset_remove(&multi->dirty, data->mid);
2449
184k
  Curl_uint32_bset_remove(&multi->pending, data->mid);
2450
184k
  Curl_uint32_bset_add(&multi->msgsent, data->mid);
2451
184k
  --multi->xfers_alive;
2452
184k
  if(!multi->xfers_alive)
2453
177k
    multi_assess_wakeup(multi);
2454
184k
}
2455
2456
static CURLMcode multistate_init(struct Curl_easy *data, CURLcode *result)
2457
191k
{
2458
191k
  *result = Curl_pretransfer(data);
2459
191k
  if(*result)
2460
49.1k
    return CURLM_OK;
2461
2462
  /* after init, go SETUP */
2463
142k
  multistate(data, MSTATE_SETUP);
2464
142k
  Curl_pgrsTime(data, TIMER_STARTOP);
2465
142k
  return CURLM_CALL_MULTI_PERFORM;
2466
191k
}
2467
2468
static CURLMcode multistate_setup(struct Curl_easy *data)
2469
159k
{
2470
159k
  Curl_pgrsTime(data, TIMER_STARTSINGLE);
2471
159k
  if(data->set.timeout)
2472
159k
    Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
2473
159k
  if(data->set.connecttimeout)
2474
    /* Since a connection might go to pending and back to CONNECT several
2475
       times before it actually takes off, we need to set the timeout once
2476
       in SETUP before we enter CONNECT the first time. */
2477
14.6k
    Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
2478
2479
159k
  multistate(data, MSTATE_CONNECT);
2480
159k
  return CURLM_CALL_MULTI_PERFORM;
2481
159k
}
2482
2483
static CURLMcode multistate_connecting(struct Curl_easy *data,
2484
                                       bool *stream_error,
2485
                                       CURLcode *result)
2486
6.71M
{
2487
6.71M
  bool connected;
2488
2489
6.71M
  if(!data->conn) {
2490
0
    DEBUGASSERT(0);
2491
0
    *result = CURLE_FAILED_INIT;
2492
0
    return CURLM_OK;
2493
0
  }
2494
6.71M
  if(!Curl_xfer_recv_is_paused(data)) {
2495
6.71M
    *result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
2496
6.71M
    if(connected && !(*result)) {
2497
72.2k
      if(!data->conn->bits.reuse &&
2498
58.5k
         Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
2499
        /* new connection, can multiplex, wake pending handles */
2500
0
        process_pending_handles(data->multi);
2501
0
      }
2502
72.2k
      multistate(data, MSTATE_PROTOCONNECT);
2503
72.2k
      return CURLM_CALL_MULTI_PERFORM;
2504
72.2k
    }
2505
6.64M
    else if(*result) {
2506
      /* failure detected */
2507
59.3k
      CURL_TRC_M(data, "connect failed -> %d", *result);
2508
59.3k
      multi_posttransfer(data);
2509
59.3k
      multi_done(data, *result, TRUE);
2510
59.3k
      *stream_error = TRUE;
2511
59.3k
      return CURLM_OK;
2512
59.3k
    }
2513
6.71M
  }
2514
6.58M
  return CURLM_OK;
2515
6.71M
}
2516
2517
static CURLMcode multistate_protoconnect(struct Curl_easy *data,
2518
                                         bool *stream_error,
2519
                                         CURLcode *result)
2520
73.3k
{
2521
73.3k
  bool protocol_connected = FALSE;
2522
2523
73.3k
  if(!(*result) && data->conn->bits.reuse) {
2524
    /* ftp seems to hang when protoconnect on reused connection since we
2525
     * handle PROTOCONNECT in general inside the filters, it seems wrong to
2526
     * restart this on a reused connection.
2527
     */
2528
13.6k
    multistate(data, MSTATE_DO);
2529
13.6k
    return CURLM_CALL_MULTI_PERFORM;
2530
13.6k
  }
2531
59.7k
  if(!(*result))
2532
59.7k
    *result = protocol_connect(data, &protocol_connected);
2533
59.7k
  if(!(*result) && !protocol_connected) {
2534
    /* switch to waiting state */
2535
6.13k
    multistate(data, MSTATE_PROTOCONNECTING);
2536
6.13k
    return CURLM_CALL_MULTI_PERFORM;
2537
6.13k
  }
2538
53.5k
  else if(!(*result)) {
2539
    /* protocol connect has completed, go WAITDO or DO */
2540
51.0k
    multistate(data, MSTATE_DO);
2541
51.0k
    return CURLM_CALL_MULTI_PERFORM;
2542
51.0k
  }
2543
2544
  /* failure detected */
2545
2.53k
  multi_posttransfer(data);
2546
2.53k
  multi_done(data, *result, TRUE);
2547
2.53k
  *stream_error = TRUE;
2548
2.53k
  return CURLM_OK;
2549
59.7k
}
2550
2551
static CURLMcode multistate_protoconnecting(struct Curl_easy *data,
2552
                                            bool *stream_error,
2553
                                            CURLcode *result)
2554
29.8k
{
2555
29.8k
  bool protocol_connected = FALSE;
2556
2557
  /* protocol-specific connect phase */
2558
29.8k
  *result = protocol_connecting(data, &protocol_connected);
2559
29.8k
  if(!(*result) && protocol_connected) {
2560
    /* after the connect has completed, go WAITDO or DO */
2561
3.08k
    multistate(data, MSTATE_DO);
2562
3.08k
    return CURLM_CALL_MULTI_PERFORM;
2563
3.08k
  }
2564
26.7k
  else if(*result) {
2565
    /* failure detected */
2566
2.82k
    multi_posttransfer(data);
2567
2.82k
    multi_done(data, *result, TRUE);
2568
2.82k
    *stream_error = TRUE;
2569
2.82k
  }
2570
26.7k
  return CURLM_OK;
2571
29.8k
}
2572
2573
static CURLMcode multistate_doing(struct Curl_easy *data,
2574
                                  bool *stream_error,
2575
                                  CURLcode *result)
2576
22.5k
{
2577
22.5k
  bool dophase_done = FALSE;
2578
2579
  /* we continue DOING until the DO phase is complete */
2580
22.5k
  DEBUGASSERT(data->conn);
2581
22.5k
  *result = protocol_doing(data, &dophase_done);
2582
22.5k
  if(!(*result)) {
2583
20.2k
    if(dophase_done) {
2584
      /* after DO, go DO_DONE or DO_MORE */
2585
1.36k
      multistate(data, data->conn->bits.do_more ?
2586
1.36k
                 MSTATE_DOING_MORE : MSTATE_DID);
2587
1.36k
      return CURLM_CALL_MULTI_PERFORM;
2588
1.36k
    } /* dophase_done */
2589
20.2k
  }
2590
2.23k
  else {
2591
    /* failure detected */
2592
2.23k
    multi_posttransfer(data);
2593
2.23k
    multi_done(data, *result, FALSE);
2594
2.23k
    *stream_error = TRUE;
2595
2.23k
  }
2596
21.1k
  return CURLM_OK;
2597
22.5k
}
2598
2599
static CURLMcode multistate_doing_more(struct Curl_easy *data,
2600
                                       bool *stream_error,
2601
                                       CURLcode *result)
2602
155k
{
2603
155k
  domore control;
2604
2605
  /*
2606
   * When we are connected, DOING MORE and then go DID
2607
   */
2608
155k
  DEBUGASSERT(data->conn);
2609
155k
  *result = multi_do_more(data, &control);
2610
2611
155k
  if(!(*result)) {
2612
154k
    if(control != DOMORE_INCOMPLETE) {
2613
      /* if DONE, advance to DO_DONE
2614
         if GOBACK, go back to DOING */
2615
678
      multistate(data, control == DOMORE_DONE ? MSTATE_DID : MSTATE_DOING);
2616
678
      return CURLM_CALL_MULTI_PERFORM;
2617
678
    }
2618
    /* else
2619
       stay in DO_MORE */
2620
154k
  }
2621
271
  else {
2622
    /* failure detected */
2623
271
    multi_posttransfer(data);
2624
271
    multi_done(data, *result, FALSE);
2625
271
    *stream_error = TRUE;
2626
271
  }
2627
154k
  return CURLM_OK;
2628
155k
}
2629
2630
static CURLMcode multistate_did(struct Curl_multi *multi,
2631
                                struct Curl_easy *data)
2632
63.2k
{
2633
63.2k
  DEBUGASSERT(data->conn);
2634
63.2k
  if(data->conn->bits.multiplex)
2635
    /* Check if we can move pending requests to send pipe */
2636
18.8k
    process_pending_handles(multi); /* multiplexed */
2637
2638
  /* Only perform the transfer if there is a good socket to work with.
2639
     Having both BAD is a signal to skip immediately to DONE */
2640
63.2k
  if(CONN_SOCK_IDX_VALID(data->conn->recv_idx) ||
2641
1.89k
     CONN_SOCK_IDX_VALID(data->conn->send_idx))
2642
62.4k
    multistate(data, MSTATE_PERFORMING);
2643
840
  else {
2644
840
#ifndef CURL_DISABLE_FTP
2645
840
    if(data->state.wildcardmatch &&
2646
85
       ((data->conn->scheme->flags & PROTOPT_WILDCARD) == 0)) {
2647
0
      data->wildcard->state = CURLWC_DONE;
2648
0
    }
2649
840
#endif
2650
840
    multistate(data, MSTATE_DONE);
2651
840
  }
2652
63.2k
  return CURLM_CALL_MULTI_PERFORM;
2653
63.2k
}
2654
2655
static CURLMcode multistate_done(struct Curl_easy *data, CURLcode *presult)
2656
18.3k
{
2657
18.3k
  if(data->conn) {
2658
18.3k
    CURLcode result;
2659
2660
    /* post-transfer command */
2661
18.3k
    result = multi_done(data, *presult, FALSE);
2662
2663
    /* allow a previously set error code take precedence */
2664
18.3k
    if(!(*presult))
2665
18.3k
      *presult = result;
2666
18.3k
  }
2667
2668
18.3k
#ifndef CURL_DISABLE_FTP
2669
18.3k
  if(data->state.wildcardmatch) {
2670
583
    if(data->wildcard->state != CURLWC_DONE) {
2671
      /* if a wildcard is set and we are not ending -> lets start again
2672
         with MSTATE_INIT */
2673
583
      multistate(data, MSTATE_INIT);
2674
583
      return CURLM_CALL_MULTI_PERFORM;
2675
583
    }
2676
583
  }
2677
17.8k
#endif
2678
  /* after we have DONE what we are supposed to do, go COMPLETED, and
2679
     it does not matter what the multi_done() returned! */
2680
17.8k
  multistate(data, MSTATE_COMPLETED);
2681
17.8k
  return CURLM_CALL_MULTI_PERFORM;
2682
18.3k
}
2683
2684
static CURLMcode multi_runsingle(struct Curl_multi *multi,
2685
                                 struct Curl_easy *data,
2686
                                 struct Curl_sigpipe_ctx *sigpipe_ctx)
2687
24.0M
{
2688
24.0M
  CURLMcode mresult;
2689
24.0M
  CURLcode result = CURLE_OK;
2690
2691
24.0M
  if(!GOOD_EASY_HANDLE(data))
2692
0
    return CURLM_BAD_EASY_HANDLE;
2693
2694
24.0M
  if(multi->dead) {
2695
    /* a multi-level callback returned error before, meaning every individual
2696
     transfer now has failed */
2697
0
    result = CURLE_ABORTED_BY_CALLBACK;
2698
0
    multi_posttransfer(data);
2699
0
    multi_done(data, result, FALSE);
2700
0
    multistate(data, MSTATE_COMPLETED);
2701
0
  }
2702
2703
24.0M
  multi_warn_debug(multi, data);
2704
2705
  /* transfer runs now, clear the dirty bit. This may be set
2706
   * again during processing, triggering a re-run later. */
2707
24.0M
  Curl_uint32_bset_remove(&multi->dirty, data->mid);
2708
2709
24.0M
  if(data == multi->admin) {
2710
10.6M
#ifdef ENABLE_WAKEUP
2711
    /* Consume any pending wakeup signals before processing.
2712
     * This is necessary for event based processing. See #21547 */
2713
10.6M
    (void)Curl_wakeup_consume(multi->wakeup_pair, TRUE);
2714
10.6M
#endif
2715
10.6M
#ifdef USE_RESOLV_THREADED
2716
10.6M
    Curl_async_thrdd_multi_process(multi);
2717
10.6M
#endif
2718
10.6M
    Curl_cshutdn_perform(&multi->cshutdn, multi->admin, sigpipe_ctx);
2719
10.6M
    return CURLM_OK;
2720
10.6M
  }
2721
2722
13.3M
  sigpipe_apply(data, sigpipe_ctx);
2723
14.1M
  do {
2724
    /* A "stream" here is a logical stream if the protocol can handle that
2725
       (HTTP/2), or the full connection for older protocols */
2726
14.1M
    bool stream_error = FALSE;
2727
14.1M
    mresult = CURLM_OK;
2728
2729
14.1M
    if(multi_ischanged(multi, TRUE)) {
2730
28.2k
      CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
2731
28.2k
      process_pending_handles(multi); /* multiplexed */
2732
28.2k
    }
2733
2734
14.1M
    if(data->mstate > MSTATE_CONNECT &&
2735
13.6M
       data->mstate < MSTATE_COMPLETED) {
2736
      /* Make sure we set the connection's current owner */
2737
13.6M
      DEBUGASSERT(data->conn);
2738
13.6M
      if(!data->conn)
2739
0
        return CURLM_INTERNAL_ERROR;
2740
13.6M
    }
2741
2742
    /* Wait for the connect state as only then is the start time stored, but
2743
       we must not check already completed handles */
2744
14.1M
    if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
2745
13.7M
       multi_handle_timeout(data, &stream_error, &result))
2746
      /* Skip the statemachine and go directly to error handling section. */
2747
1.10k
      goto statemachine_end;
2748
2749
14.1M
    switch(data->mstate) {
2750
191k
    case MSTATE_INIT:
2751
      /* Transitional state. init this transfer. A handle never comes back to
2752
         this state. */
2753
191k
      mresult = multistate_init(data, &result);
2754
191k
      break;
2755
2756
159k
    case MSTATE_SETUP:
2757
      /* Transitional state. Setup things for a new transfer. The handle
2758
         can come back to this state on a redirect. */
2759
159k
      mresult = multistate_setup(data);
2760
159k
      break;
2761
2762
161k
    case MSTATE_CONNECT:
2763
161k
      mresult = multistate_connect(multi, data, &result);
2764
161k
      break;
2765
2766
6.71M
    case MSTATE_CONNECTING:
2767
      /* awaiting a completion of an asynch TCP connect */
2768
6.71M
      mresult = multistate_connecting(data, &stream_error, &result);
2769
6.71M
      break;
2770
2771
73.3k
    case MSTATE_PROTOCONNECT:
2772
73.3k
      mresult = multistate_protoconnect(data, &stream_error, &result);
2773
73.3k
      break;
2774
2775
29.8k
    case MSTATE_PROTOCONNECTING:
2776
      /* protocol-specific connect phase */
2777
29.8k
      mresult = multistate_protoconnecting(data, &stream_error, &result);
2778
29.8k
      break;
2779
2780
67.8k
    case MSTATE_DO:
2781
67.8k
      mresult = multistate_do(data, &stream_error, &result);
2782
67.8k
      break;
2783
2784
22.5k
    case MSTATE_DOING:
2785
      /* we continue DOING until the DO phase is complete */
2786
22.5k
      mresult = multistate_doing(data, &stream_error, &result);
2787
22.5k
      break;
2788
2789
155k
    case MSTATE_DOING_MORE:
2790
      /*
2791
       * When we are connected, DOING MORE and then go DID
2792
       */
2793
155k
      mresult = multistate_doing_more(data, &stream_error, &result);
2794
155k
      break;
2795
2796
63.2k
    case MSTATE_DID:
2797
63.2k
      mresult = multistate_did(multi, data);
2798
63.2k
      break;
2799
2800
1.01k
    case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
2801
1.01k
      mresult = multistate_ratelimiting(data, &result);
2802
1.01k
      break;
2803
2804
6.45M
    case MSTATE_PERFORMING:
2805
6.45M
      mresult = multistate_performing(data, &stream_error, &result);
2806
6.45M
      break;
2807
2808
18.3k
    case MSTATE_DONE:
2809
18.3k
      mresult = multistate_done(data, &result);
2810
18.3k
      break;
2811
2812
0
    case MSTATE_COMPLETED:
2813
0
      break;
2814
2815
0
    case MSTATE_PENDING:
2816
0
    case MSTATE_MSGSENT:
2817
      /* handles in these states should NOT be in this list */
2818
0
      break;
2819
2820
0
    default:
2821
0
      return CURLM_INTERNAL_ERROR;
2822
14.1M
    }
2823
2824
14.1M
    if(data->mstate >= MSTATE_CONNECT &&
2825
13.9M
       data->mstate < MSTATE_DO &&
2826
7.06M
       mresult != CURLM_CALL_MULTI_PERFORM &&
2827
6.69M
       !multi_ischanged(multi, FALSE)) {
2828
      /* We now handle stream timeouts if and only if this will be the last
2829
       * loop iteration. We only check this on the last iteration to ensure
2830
       * that if we know we have additional work to do immediately
2831
       * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
2832
       * declaring the connection timed out as we may almost have a completed
2833
       * connection. */
2834
6.62M
      multi_handle_timeout(data, &stream_error, &result);
2835
6.62M
    }
2836
2837
14.1M
statemachine_end:
2838
2839
14.1M
    result = is_finished(multi, data, stream_error, result);
2840
14.1M
    if(result)
2841
175k
      mresult = CURLM_CALL_MULTI_PERFORM;
2842
2843
14.1M
    if(MSTATE_COMPLETED == data->mstate) {
2844
184k
      handle_completed(multi, data, result);
2845
184k
      return CURLM_OK;
2846
184k
    }
2847
14.1M
  } while((mresult == CURLM_CALL_MULTI_PERFORM) ||
2848
13.1M
          multi_ischanged(multi, FALSE));
2849
2850
13.1M
  data->result = result;
2851
13.1M
  return mresult;
2852
13.3M
}
2853
2854
static CURLMcode multi_perform(struct Curl_multi *multi,
2855
                               int *running_handles)
2856
10.6M
{
2857
10.6M
  CURLMcode returncode = CURLM_OK;
2858
10.6M
  struct curltime start = *multi_now(multi);
2859
10.6M
  uint32_t mid;
2860
10.6M
  struct Curl_sigpipe_ctx sigpipe_ctx;
2861
2862
10.6M
  if(multi->in_callback)
2863
0
    return CURLM_RECURSIVE_API_CALL;
2864
2865
10.6M
  if(multi->in_ntfy_callback)
2866
0
    return CURLM_RECURSIVE_API_CALL;
2867
2868
10.6M
  sigpipe_init(&sigpipe_ctx);
2869
2870
10.6M
  if(Curl_uint32_bset_first(&multi->process, &mid)) {
2871
10.6M
    CURL_TRC_M(multi->admin, "multi_perform(running=%u)",
2872
10.6M
               Curl_multi_xfers_running(multi));
2873
24.0M
    do {
2874
24.0M
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
2875
24.0M
      CURLMcode mresult;
2876
24.0M
      if(!data) {
2877
0
        DEBUGASSERT(0);
2878
0
        Curl_uint32_bset_remove(&multi->process, mid);
2879
0
        Curl_uint32_bset_remove(&multi->dirty, mid);
2880
0
        continue;
2881
0
      }
2882
24.0M
      mresult = multi_runsingle(multi, data, &sigpipe_ctx);
2883
24.0M
      if(mresult)
2884
0
        returncode = mresult;
2885
24.0M
    } while(Curl_uint32_bset_next(&multi->process, mid, &mid));
2886
10.6M
  }
2887
10.6M
  sigpipe_restore(&sigpipe_ctx);
2888
2889
10.6M
  if(multi_ischanged(multi, TRUE))
2890
103k
    process_pending_handles(multi);
2891
2892
10.6M
  if(!returncode && CURL_MNTFY_HAS_ENTRIES(multi))
2893
0
    returncode = Curl_mntfy_dispatch_all(multi);
2894
2895
  /*
2896
   * Remove all expired timers from the splay since handles are dealt
2897
   * with unconditionally by this function and curl_multi_timeout() requires
2898
   * that already passed/handled expire times are removed from the splay.
2899
   *
2900
   * It is important that the 'now' value is set at the entry of this function
2901
   * and not for the current time as it may have ticked a little while since
2902
   * then and then we risk this loop to remove timers that actually have not
2903
   * been handled!
2904
   */
2905
10.6M
  if(multi->timetree) {
2906
10.4M
    struct Curl_tree *t = NULL;
2907
10.4M
    do {
2908
10.4M
      multi->timetree = Curl_splaygetbest(&start, multi->timetree, &t);
2909
10.4M
      if(t) {
2910
        /* the removed may have another timeout in queue */
2911
1.53k
        struct Curl_easy *data = Curl_splayget(t);
2912
1.53k
        (void)add_next_timeout(&start, multi, data);
2913
1.53k
        if(data->mstate == MSTATE_PENDING) {
2914
0
          bool stream_unused;
2915
0
          CURLcode result_unused;
2916
0
          if(multi_handle_timeout(data, &stream_unused, &result_unused)) {
2917
0
            infof(data, "PENDING handle timeout");
2918
0
            move_pending_to_connect(multi, data);
2919
0
          }
2920
0
        }
2921
1.53k
      }
2922
10.4M
    } while(t);
2923
10.4M
  }
2924
2925
10.6M
  if(running_handles) {
2926
10.6M
    unsigned int running = Curl_multi_xfers_running(multi);
2927
10.6M
    *running_handles = (running < INT_MAX) ? (int)running : INT_MAX;
2928
10.6M
  }
2929
2930
10.6M
  if(CURLM_OK >= returncode)
2931
10.6M
    returncode = Curl_update_timer(multi);
2932
2933
10.6M
  return returncode;
2934
10.6M
}
2935
2936
CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
2937
10.6M
{
2938
10.6M
  struct Curl_multi *multi = m;
2939
2940
10.6M
  if(!GOOD_MULTI_HANDLE(multi))
2941
0
    return CURLM_BAD_HANDLE;
2942
2943
10.6M
  return multi_perform(multi, running_handles);
2944
10.6M
}
2945
2946
CURLMcode curl_multi_cleanup(CURLM *m)
2947
181k
{
2948
181k
  struct Curl_multi *multi = m;
2949
181k
  if(GOOD_MULTI_HANDLE(multi)) {
2950
181k
    void *entry;
2951
181k
    uint32_t mid;
2952
181k
    if(multi->in_callback)
2953
0
      return CURLM_RECURSIVE_API_CALL;
2954
181k
    if(multi->in_ntfy_callback)
2955
0
      return CURLM_RECURSIVE_API_CALL;
2956
2957
    /* First remove all remaining easy handles,
2958
     * close internal ones. admin handle is special */
2959
181k
    if(Curl_uint32_tbl_first(&multi->xfers, &mid, &entry)) {
2960
181k
      do {
2961
181k
        struct Curl_easy *data = entry;
2962
181k
        if(!GOOD_EASY_HANDLE(data))
2963
0
          return CURLM_BAD_HANDLE;
2964
2965
181k
#ifdef DEBUGBUILD
2966
181k
        if(mid != data->mid) {
2967
0
          CURL_TRC_M(data, "multi_cleanup: still present with mid=%u, "
2968
0
                     "but unexpected data->mid=%u\n", mid, data->mid);
2969
0
          DEBUGASSERT(0);
2970
0
        }
2971
181k
#endif
2972
2973
181k
        if(data == multi->admin)
2974
181k
          continue;
2975
2976
0
        if(!data->state.done && data->conn)
2977
          /* if DONE was never called for this handle */
2978
0
          (void)multi_done(data, CURLE_OK, TRUE);
2979
2980
0
        data->multi = NULL; /* clear the association */
2981
0
        Curl_uint32_tbl_remove(&multi->xfers, mid);
2982
0
        data->mid = UINT32_MAX;
2983
2984
#ifdef USE_LIBPSL
2985
        if(data->psl == &multi->psl)
2986
          data->psl = NULL;
2987
#endif
2988
0
        if(data->state.internal)
2989
0
          Curl_close(&data);
2990
181k
      } while(Curl_uint32_tbl_next(&multi->xfers, mid, &mid, &entry));
2991
181k
    }
2992
2993
181k
#ifdef USE_RESOLV_THREADED
2994
181k
    Curl_async_thrdd_multi_destroy(multi, !multi->quick_exit);
2995
181k
#endif
2996
181k
    Curl_cpool_destroy(&multi->cpool);
2997
181k
    Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
2998
181k
    if(multi->admin) {
2999
181k
      CURL_TRC_M(multi->admin, "multi_cleanup, closing admin handle, done");
3000
181k
      multi->admin->multi = NULL;
3001
181k
      Curl_uint32_tbl_remove(&multi->xfers, multi->admin->mid);
3002
181k
      Curl_close(&multi->admin);
3003
181k
    }
3004
3005
181k
    multi->magic = 0; /* not good anymore */
3006
3007
181k
    Curl_multi_ev_cleanup(multi);
3008
181k
    Curl_hash_destroy(&multi->proto_hash);
3009
181k
    Curl_dnscache_destroy(&multi->dnscache);
3010
181k
    Curl_psl_destroy(&multi->psl);
3011
181k
#ifdef USE_SSL
3012
181k
    Curl_ssl_scache_destroy(multi->ssl_scache);
3013
181k
#endif
3014
3015
#ifdef USE_WINSOCK
3016
    WSACloseEvent(multi->wsa_event);
3017
#endif
3018
181k
#ifdef ENABLE_WAKEUP
3019
181k
  Curl_wakeup_destroy(multi->wakeup_pair);
3020
181k
#endif
3021
3022
181k
    multi_xfer_bufs_free(multi);
3023
181k
    Curl_mntfy_cleanup(multi);
3024
181k
#ifdef DEBUGBUILD
3025
181k
    if(Curl_uint32_tbl_count(&multi->xfers)) {
3026
0
      multi_xfer_tbl_dump(multi);
3027
0
      DEBUGASSERT(0);
3028
0
    }
3029
181k
#endif
3030
181k
    Curl_uint32_bset_destroy(&multi->process);
3031
181k
    Curl_uint32_bset_destroy(&multi->dirty);
3032
181k
    Curl_uint32_bset_destroy(&multi->pending);
3033
181k
    Curl_uint32_bset_destroy(&multi->msgsent);
3034
181k
    Curl_uint32_tbl_destroy(&multi->xfers);
3035
181k
    curlx_free(multi);
3036
3037
181k
    return CURLM_OK;
3038
181k
  }
3039
0
  return CURLM_BAD_HANDLE;
3040
181k
}
3041
3042
/*
3043
 * curl_multi_info_read()
3044
 *
3045
 * This function is the primary way for a multi/multi_socket application to
3046
 * figure out if a transfer has ended. We MUST make this function as fast as
3047
 * possible as it will be polled frequently and we MUST NOT scan any lists in
3048
 * here to figure out things. We must scale fine to thousands of handles and
3049
 * beyond. The current design is fully O(1).
3050
 */
3051
3052
CURLMsg *curl_multi_info_read(CURLM *m, int *msgs_in_queue)
3053
0
{
3054
0
  struct Curl_message *msg;
3055
0
  struct Curl_multi *multi = m;
3056
3057
0
  *msgs_in_queue = 0; /* default to none */
3058
3059
0
  if(GOOD_MULTI_HANDLE(multi) &&
3060
0
     !multi->in_callback &&
3061
0
     Curl_llist_count(&multi->msglist)) {
3062
    /* there is one or more messages in the list */
3063
0
    struct Curl_llist_node *e;
3064
3065
    /* extract the head of the list to return */
3066
0
    e = Curl_llist_head(&multi->msglist);
3067
3068
0
    msg = Curl_node_elem(e);
3069
3070
    /* remove the extracted entry */
3071
0
    Curl_node_remove(e);
3072
3073
0
    *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
3074
3075
0
    return &msg->extmsg;
3076
0
  }
3077
0
  return NULL;
3078
0
}
3079
3080
void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s)
3081
112k
{
3082
112k
  if(data) {
3083
112k
    struct Curl_multi *multi = data->multi;
3084
112k
    if(multi) {
3085
112k
      CURL_TRC_M(data, "Curl_multi_will_close fd=%" FMT_SOCKET_T, s);
3086
112k
      Curl_multi_ev_socket_done(multi, data, s);
3087
112k
    }
3088
112k
  }
3089
112k
}
3090
3091
/*
3092
 * add_next_timeout()
3093
 *
3094
 * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
3095
 * when it has been removed from the splay tree because the timeout has
3096
 * expired. This function is then to advance in the list to pick the next
3097
 * timeout to use (skip the already expired ones) and add this node back to
3098
 * the splay tree again.
3099
 *
3100
 * The splay tree only has each sessionhandle as a single node and the nearest
3101
 * timeout is used to sort it on.
3102
 */
3103
static CURLMcode add_next_timeout(const struct curltime *pnow,
3104
                                  struct Curl_multi *multi,
3105
                                  struct Curl_easy *d)
3106
1.53k
{
3107
1.53k
  struct curltime *tv = &d->state.expiretime;
3108
1.53k
  struct Curl_llist *list = &d->state.timeoutlist;
3109
1.53k
  struct Curl_llist_node *e;
3110
3111
  /* move over the timeout list for this specific handle and remove all
3112
     timeouts that are now passed tense and store the next pending
3113
     timeout in *tv */
3114
2.14k
  for(e = Curl_llist_head(list); e;) {
3115
2.14k
    struct Curl_llist_node *n = Curl_node_next(e);
3116
2.14k
    struct time_node *node = Curl_node_elem(e);
3117
2.14k
    timediff_t diff = curlx_ptimediff_us(&node->time, pnow);
3118
2.14k
    if(diff <= 0)
3119
      /* remove outdated entry */
3120
609
      Curl_node_remove(e);
3121
1.53k
    else
3122
      /* the list is sorted so get out on the first mismatch */
3123
1.53k
      break;
3124
609
    e = n;
3125
609
  }
3126
1.53k
  e = Curl_llist_head(list);
3127
1.53k
  if(!e) {
3128
    /* clear the expire times within the handles that we remove from the
3129
       splay tree */
3130
0
    tv->tv_sec = 0;
3131
0
    tv->tv_usec = 0;
3132
0
  }
3133
1.53k
  else {
3134
1.53k
    struct time_node *node = Curl_node_elem(e);
3135
    /* copy the first entry to 'tv' */
3136
1.53k
    memcpy(tv, &node->time, sizeof(*tv));
3137
3138
    /* Insert this node again into the splay. Keep the timer in the list in
3139
       case we need to recompute future timers. */
3140
1.53k
    multi->timetree = Curl_splayinsert(tv, multi->timetree,
3141
1.53k
                                       &d->state.timenode);
3142
1.53k
  }
3143
1.53k
  return CURLM_OK;
3144
1.53k
}
3145
3146
static void multi_mark_expired_as_dirty(struct Curl_multi *multi,
3147
                                        const struct curltime *ts)
3148
0
{
3149
0
  struct Curl_easy *data = NULL;
3150
0
  struct Curl_tree *t = NULL;
3151
3152
  /*
3153
   * The loop following here will go on as long as there are expire-times left
3154
   * to process (compared to `ts`) in the splay and 'data' will be
3155
   * re-assigned for every expired handle we deal with.
3156
   */
3157
0
  while(1) {
3158
    /* Check if there is one (more) expired timer to deal with! This function
3159
       extracts a matching node if there is one */
3160
0
    multi->timetree = Curl_splaygetbest(ts, multi->timetree, &t);
3161
0
    if(!t)
3162
0
      return;
3163
3164
0
    data = Curl_splayget(t); /* assign this for next loop */
3165
0
    if(!data)
3166
0
      continue;
3167
0
#ifdef CURLVERBOSE
3168
0
    if(CURL_TRC_TIMER_is_verbose(data)) {
3169
0
      struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
3170
0
      if(e) {
3171
0
        struct time_node *n = Curl_node_elem(e);
3172
0
        CURL_TRC_TIMER(data, n->eid, "has expired");
3173
0
      }
3174
0
    }
3175
0
#endif
3176
0
    (void)add_next_timeout(ts, multi, data);
3177
0
    Curl_multi_mark_dirty(data);
3178
0
  }
3179
0
}
3180
3181
static CURLMcode multi_run_dirty(struct Curl_multi *multi,
3182
                                 struct Curl_sigpipe_ctx *sigpipe_ctx,
3183
                                 uint32_t *pnum)
3184
0
{
3185
0
  CURLMcode mresult = CURLM_OK;
3186
0
  uint32_t mid;
3187
3188
0
  *pnum = 0;
3189
0
  if(Curl_uint32_bset_first(&multi->dirty, &mid)) {
3190
0
    do {
3191
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3192
0
      if(data) {
3193
0
        CURL_TRC_M(data, "multi_run_dirty");
3194
3195
0
        if(!Curl_uint32_bset_contains(&multi->process, mid)) {
3196
          /* We are no longer processing this transfer */
3197
0
          Curl_uint32_bset_remove(&multi->dirty, mid);
3198
0
          continue;
3199
0
        }
3200
3201
0
        (*pnum)++;
3202
        /* runsingle() clears the dirty mid */
3203
0
        mresult = multi_runsingle(multi, data, sigpipe_ctx);
3204
3205
0
        if(CURLM_OK >= mresult) {
3206
          /* reassess event handling of data */
3207
0
          mresult = Curl_multi_ev_assess_xfer(multi, data);
3208
0
          if(mresult)
3209
0
            goto out;
3210
0
        }
3211
0
      }
3212
0
      else {
3213
0
        CURL_TRC_M(multi->admin, "multi_run_dirty, %u no longer found", mid);
3214
0
        Curl_uint32_bset_remove(&multi->dirty, mid);
3215
0
      }
3216
0
    } while(Curl_uint32_bset_next(&multi->dirty, mid, &mid));
3217
0
  }
3218
3219
0
out:
3220
0
  return mresult;
3221
0
}
3222
3223
static CURLMcode multi_socket(struct Curl_multi *multi,
3224
                              bool checkall,
3225
                              curl_socket_t s,
3226
                              int ev_bitmask,
3227
                              int *running_handles)
3228
0
{
3229
0
  CURLMcode mresult = CURLM_OK;
3230
0
  struct Curl_sigpipe_ctx pipe_ctx;
3231
0
  uint32_t run_xfers;
3232
3233
0
  (void)ev_bitmask;
3234
0
  sigpipe_init(&pipe_ctx);
3235
3236
0
  if(checkall) {
3237
    /* *perform() deals with running_handles on its own */
3238
0
    mresult = multi_perform(multi, running_handles);
3239
3240
0
    if(mresult != CURLM_BAD_HANDLE) {
3241
      /* Reassess event status of all active transfers */
3242
0
      mresult = Curl_multi_ev_assess_xfer_bset(multi, &multi->process);
3243
0
    }
3244
0
    goto out;
3245
0
  }
3246
3247
0
  if(s != CURL_SOCKET_TIMEOUT) {
3248
    /* Mark all transfers of that socket as dirty */
3249
0
    Curl_multi_ev_dirty_xfers(multi, s);
3250
0
  }
3251
0
  else {
3252
    /* Asked to run due to time-out. Clear the 'last_expire_ts' variable to
3253
       force Curl_update_timer() to trigger a callback to the app again even
3254
       if the same timeout is still the one to run after this call. That
3255
       handles the case when the application asks libcurl to run the timeout
3256
       prematurely. */
3257
0
    memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts));
3258
3259
    /* Applications may set `socket_cb` *after* having added transfers
3260
     * first. *Then* kick off processing with a
3261
     * curl_multi_socket_action(TIMEOUT) afterwards. Make sure our
3262
     * admin handle registers its pollset with the callbacks present. */
3263
0
    mresult = multi_assess_wakeup(multi);
3264
0
    if(mresult)
3265
0
      goto out;
3266
0
  }
3267
3268
0
  multi_mark_expired_as_dirty(multi, multi_now(multi));
3269
0
  mresult = multi_run_dirty(multi, &pipe_ctx, &run_xfers);
3270
0
  if(mresult)
3271
0
    goto out;
3272
3273
0
  if(run_xfers) {
3274
    /* Running transfers takes time. With a new timestamp, we might catch
3275
     * other expires which are due now. Instead of telling the application
3276
     * to set a 0 timeout and call us again, we run them here.
3277
     * Do that only once or it might be unfair to transfers on other
3278
     * sockets. */
3279
0
    multi_mark_expired_as_dirty(multi, &multi->now);
3280
0
    mresult = multi_run_dirty(multi, &pipe_ctx, &run_xfers);
3281
0
  }
3282
3283
0
out:
3284
0
  sigpipe_restore(&pipe_ctx);
3285
3286
0
  if(multi_ischanged(multi, TRUE))
3287
0
    process_pending_handles(multi);
3288
3289
0
  if(!mresult && CURL_MNTFY_HAS_ENTRIES(multi))
3290
0
    mresult = Curl_mntfy_dispatch_all(multi);
3291
3292
0
  if(running_handles) {
3293
0
    unsigned int running = Curl_multi_xfers_running(multi);
3294
0
    *running_handles = (running < INT_MAX) ? (int)running : INT_MAX;
3295
0
  }
3296
3297
0
  if(CURLM_OK >= mresult)
3298
0
    mresult = Curl_update_timer(multi);
3299
0
  return mresult;
3300
0
}
3301
3302
#undef curl_multi_setopt
3303
CURLMcode curl_multi_setopt(CURLM *m, CURLMoption option, ...)
3304
0
{
3305
0
  CURLMcode mresult = CURLM_OK;
3306
0
  va_list param;
3307
0
  unsigned long uarg;
3308
0
  struct Curl_multi *multi = m;
3309
3310
0
  if(!GOOD_MULTI_HANDLE(multi))
3311
0
    return CURLM_BAD_HANDLE;
3312
3313
0
  if(multi->in_callback)
3314
0
    return CURLM_RECURSIVE_API_CALL;
3315
3316
0
  va_start(param, option);
3317
3318
0
  switch(option) {
3319
0
  case CURLMOPT_SOCKETFUNCTION:
3320
0
    multi->socket_cb = va_arg(param, curl_socket_callback);
3321
0
    break;
3322
0
  case CURLMOPT_SOCKETDATA:
3323
0
    multi->socket_userp = va_arg(param, void *);
3324
0
    break;
3325
0
  case CURLMOPT_PUSHFUNCTION:
3326
0
    multi->push_cb = va_arg(param, curl_push_callback);
3327
0
    break;
3328
0
  case CURLMOPT_PUSHDATA:
3329
0
    multi->push_userp = va_arg(param, void *);
3330
0
    break;
3331
0
  case CURLMOPT_PIPELINING:
3332
0
    multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX ? 1 : 0;
3333
0
    break;
3334
0
  case CURLMOPT_TIMERFUNCTION:
3335
0
    multi->timer_cb = va_arg(param, curl_multi_timer_callback);
3336
0
    break;
3337
0
  case CURLMOPT_TIMERDATA:
3338
0
    multi->timer_userp = va_arg(param, void *);
3339
0
    break;
3340
0
  case CURLMOPT_MAXCONNECTS:
3341
0
    uarg = va_arg(param, unsigned long);
3342
0
    if(uarg <= UINT_MAX)
3343
0
      multi->maxconnects = (unsigned int)uarg;
3344
0
    break;
3345
0
  case CURLMOPT_MAX_HOST_CONNECTIONS:
3346
0
    if(!curlx_sltouz(va_arg(param, long), &multi->max_host_connections))
3347
0
      mresult = CURLM_BAD_FUNCTION_ARGUMENT;
3348
0
    break;
3349
0
  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
3350
0
    if(!curlx_sltouz(va_arg(param, long), &multi->max_total_connections))
3351
0
      mresult = CURLM_BAD_FUNCTION_ARGUMENT;
3352
0
    break;
3353
    /* options formerly used for pipelining */
3354
0
  case CURLMOPT_MAX_PIPELINE_LENGTH:
3355
0
    break;
3356
0
  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
3357
0
    break;
3358
0
  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
3359
0
    break;
3360
0
  case CURLMOPT_PIPELINING_SITE_BL:
3361
0
    break;
3362
0
  case CURLMOPT_PIPELINING_SERVER_BL:
3363
0
    break;
3364
0
  case CURLMOPT_MAX_CONCURRENT_STREAMS: {
3365
0
    long streams = va_arg(param, long);
3366
0
    if((streams < 1) || (streams > INT_MAX))
3367
0
      streams = 100;
3368
0
    multi->max_concurrent_streams = (unsigned int)streams;
3369
0
    break;
3370
0
  }
3371
0
  case CURLMOPT_NETWORK_CHANGED: {
3372
0
    long val = va_arg(param, long);
3373
0
    if(val & CURLMNWC_CLEAR_ALL)
3374
      /* In the beginning, all values available to set were 1 by mistake. We
3375
         converted this to mean "all", thus setting all the bits
3376
         automatically */
3377
0
      val = CURLMNWC_CLEAR_DNS | CURLMNWC_CLEAR_CONNS;
3378
0
    if(val & CURLMNWC_CLEAR_DNS) {
3379
0
      Curl_dnscache_clear(multi->admin);
3380
0
    }
3381
0
    if(val & CURLMNWC_CLEAR_CONNS) {
3382
0
      Curl_cpool_nw_changed(multi->admin);
3383
0
    }
3384
0
    break;
3385
0
  }
3386
0
  case CURLMOPT_NOTIFYFUNCTION:
3387
0
    multi->ntfy.ntfy_cb = va_arg(param, curl_notify_callback);
3388
0
    break;
3389
0
  case CURLMOPT_NOTIFYDATA:
3390
0
    multi->ntfy.ntfy_cb_data = va_arg(param, void *);
3391
0
    break;
3392
0
  case CURLMOPT_RESOLVE_THREADS_MAX:
3393
0
#ifdef USE_RESOLV_THREADED
3394
0
    uarg = va_arg(param, long);
3395
0
    if((uarg <= 0) || (uarg > UINT32_MAX))
3396
0
      mresult = CURLM_BAD_FUNCTION_ARGUMENT;
3397
0
    else {
3398
0
      CURLcode result = Curl_async_thrdd_multi_set_props(
3399
0
        multi, 0, (uint32_t)uarg, 2000);
3400
0
      switch(result) {
3401
0
      case CURLE_OK:
3402
0
        mresult = CURLM_OK;
3403
0
        break;
3404
0
      case CURLE_BAD_FUNCTION_ARGUMENT:
3405
0
        mresult = CURLM_BAD_FUNCTION_ARGUMENT;
3406
0
        break;
3407
0
      case CURLE_OUT_OF_MEMORY:
3408
0
        mresult = CURLM_OUT_OF_MEMORY;
3409
0
        break;
3410
0
      default:
3411
0
        mresult = CURLM_INTERNAL_ERROR;
3412
0
        break;
3413
0
      }
3414
0
    }
3415
0
#endif
3416
0
    break;
3417
0
  case CURLMOPT_QUICK_EXIT:
3418
0
    multi->quick_exit = va_arg(param, long) ? 1 : 0;
3419
0
    break;
3420
0
  default:
3421
0
    mresult = CURLM_UNKNOWN_OPTION;
3422
0
    break;
3423
0
  }
3424
0
  va_end(param);
3425
0
  return mresult;
3426
0
}
3427
3428
/* we define curl_multi_socket() in the public multi.h header */
3429
#undef curl_multi_socket
3430
3431
CURLMcode curl_multi_socket(CURLM *m, curl_socket_t s, int *running_handles)
3432
0
{
3433
0
  struct Curl_multi *multi = m;
3434
0
  if(multi->in_callback)
3435
0
    return CURLM_RECURSIVE_API_CALL;
3436
0
  if(multi->in_ntfy_callback)
3437
0
    return CURLM_RECURSIVE_API_CALL;
3438
0
  return multi_socket(multi, FALSE, s, 0, running_handles);
3439
0
}
3440
3441
CURLMcode curl_multi_socket_action(CURLM *m, curl_socket_t s,
3442
                                   int ev_bitmask, int *running_handles)
3443
0
{
3444
0
  struct Curl_multi *multi = m;
3445
0
  if(multi->in_callback)
3446
0
    return CURLM_RECURSIVE_API_CALL;
3447
0
  if(multi->in_ntfy_callback)
3448
0
    return CURLM_RECURSIVE_API_CALL;
3449
0
  return multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
3450
0
}
3451
3452
CURLMcode curl_multi_socket_all(CURLM *m, int *running_handles)
3453
0
{
3454
0
  struct Curl_multi *multi = m;
3455
0
  if(multi->in_callback)
3456
0
    return CURLM_RECURSIVE_API_CALL;
3457
0
  if(multi->in_ntfy_callback)
3458
0
    return CURLM_RECURSIVE_API_CALL;
3459
0
  return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
3460
0
}
3461
3462
static bool multi_has_dirties(struct Curl_multi *multi)
3463
0
{
3464
0
  uint32_t mid;
3465
0
  if(Curl_uint32_bset_first(&multi->dirty, &mid)) {
3466
0
    do {
3467
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3468
0
      if(data) {
3469
0
        if(Curl_uint32_bset_contains(&multi->process, mid))
3470
0
          return TRUE;
3471
        /* We are no longer processing this transfer */
3472
0
        Curl_uint32_bset_remove(&multi->dirty, mid);
3473
0
      }
3474
0
      else {
3475
0
        CURL_TRC_M(multi->admin, "dirty transfer %u no longer found", mid);
3476
0
        Curl_uint32_bset_remove(&multi->dirty, mid);
3477
0
      }
3478
0
    } while(Curl_uint32_bset_next(&multi->dirty, mid, &mid));
3479
0
  }
3480
0
  return FALSE;
3481
0
}
3482
3483
static void multi_timeout(struct Curl_multi *multi,
3484
                          struct curltime *expire_time,
3485
                          long *timeout_ms)
3486
0
{
3487
0
  static const struct curltime tv_zero = { 0, 0 };
3488
0
  VERBOSE(struct Curl_easy *data = NULL);
3489
3490
0
  if(multi->dead) {
3491
0
    *timeout_ms = 0;
3492
0
    return;
3493
0
  }
3494
3495
0
  if(multi_has_dirties(multi)) {
3496
0
    *expire_time = *multi_now(multi);
3497
0
    *timeout_ms = 0;
3498
0
    return;
3499
0
  }
3500
0
  else if(multi->timetree) {
3501
0
    const struct curltime *pnow = multi_now(multi);
3502
    /* splay the lowest to the bottom */
3503
0
    multi->timetree = Curl_splay(&tv_zero, multi->timetree);
3504
    /* this will not return NULL from a non-empty tree, but some compilers
3505
     * are not convinced of that. Analyzers are hard. */
3506
0
    *expire_time = multi->timetree ? multi->timetree->key : tv_zero;
3507
3508
    /* 'multi->timetree' will be non-NULL here but the compilers sometimes
3509
       yell at us if we assume so */
3510
0
    if(multi->timetree &&
3511
0
       curlx_ptimediff_us(&multi->timetree->key, pnow) > 0) {
3512
      /* some time left before expiration */
3513
0
      timediff_t diff_ms =
3514
0
        curlx_timediff_ceil_ms(multi->timetree->key, *pnow);
3515
0
      VERBOSE(data = Curl_splayget(multi->timetree));
3516
      /* this should be safe even on 32-bit archs, as we do not use that
3517
         overly long timeouts */
3518
0
      *timeout_ms = (long)diff_ms;
3519
0
    }
3520
0
    else {
3521
0
      if(multi->timetree)
3522
0
        VERBOSE(data = Curl_splayget(multi->timetree));
3523
      /* 0 means immediately */
3524
0
      *timeout_ms = 0;
3525
0
    }
3526
0
  }
3527
0
  else {
3528
0
    *expire_time = tv_zero;
3529
0
    *timeout_ms = -1;
3530
0
  }
3531
3532
0
#ifdef CURLVERBOSE
3533
0
  if(CURL_TRC_TIMER_is_verbose(data)) {
3534
0
    struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
3535
0
    if(e) {
3536
0
      struct time_node *n = Curl_node_elem(e);
3537
0
      CURL_TRC_TIMER(data, n->eid, "gives multi timeout in %ldms",
3538
0
                     *timeout_ms);
3539
0
    }
3540
0
  }
3541
0
#endif
3542
0
}
3543
3544
CURLMcode curl_multi_timeout(CURLM *m,
3545
                             long *timeout_ms)
3546
0
{
3547
0
  struct curltime expire_time;
3548
0
  struct Curl_multi *multi = m;
3549
3550
  /* First, make some basic checks that the CURLM handle is a good handle */
3551
0
  if(!GOOD_MULTI_HANDLE(multi))
3552
0
    return CURLM_BAD_HANDLE;
3553
3554
0
  if(multi->in_callback)
3555
0
    return CURLM_RECURSIVE_API_CALL;
3556
3557
0
  multi_timeout(multi, &expire_time, timeout_ms);
3558
0
  return CURLM_OK;
3559
0
}
3560
3561
/*
3562
 * Tell the application it should update its timers, if it subscribes to the
3563
 * update timer callback.
3564
 */
3565
CURLMcode Curl_update_timer(struct Curl_multi *multi)
3566
11.0M
{
3567
11.0M
  struct curltime expire_ts;
3568
11.0M
  long timeout_ms;
3569
11.0M
  int rc;
3570
11.0M
  bool set_value = FALSE;
3571
3572
11.0M
  if(!multi->timer_cb || multi->dead)
3573
11.0M
    return CURLM_OK;
3574
0
  multi_timeout(multi, &expire_ts, &timeout_ms);
3575
3576
0
  if(timeout_ms < 0 && multi->last_timeout_ms < 0) {
3577
    /* nothing to do */
3578
0
  }
3579
0
  else if(timeout_ms < 0) {
3580
    /* there is no timeout now but there was one previously */
3581
0
    CURL_TRC_M(multi->admin, "[TIMER] clear");
3582
0
    timeout_ms = -1; /* normalize */
3583
0
    set_value = TRUE;
3584
0
  }
3585
0
  else if(multi->last_timeout_ms < 0) {
3586
0
    CURL_TRC_M(multi->admin, "[TIMER] set %ldms, none before", timeout_ms);
3587
0
    set_value = TRUE;
3588
0
  }
3589
0
  else if(curlx_ptimediff_us(&multi->last_expire_ts, &expire_ts)) {
3590
    /* We had a timeout before and have one now, the absolute timestamp
3591
     * differs. The relative timeout_ms may be the same, but the starting
3592
     * point differs. Let the application restart its timer. */
3593
0
    CURL_TRC_M(multi->admin, "[TIMER] set %ldms, replace previous",
3594
0
               timeout_ms);
3595
0
    set_value = TRUE;
3596
0
  }
3597
0
  else {
3598
    /* We have same expire time as previously. Our relative 'timeout_ms'
3599
     * may be different now, but the application has the timer running
3600
     * and we do not to tell it to start this again. */
3601
0
  }
3602
3603
0
  if(set_value) {
3604
0
    multi->last_expire_ts = expire_ts;
3605
0
    multi->last_timeout_ms = timeout_ms;
3606
0
    set_in_callback(multi, TRUE);
3607
0
    rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
3608
0
    set_in_callback(multi, FALSE);
3609
0
    if(rc == -1) {
3610
0
      multi->dead = TRUE;
3611
0
      return CURLM_ABORTED_BY_CALLBACK;
3612
0
    }
3613
0
  }
3614
0
  return CURLM_OK;
3615
0
}
3616
3617
/*
3618
 * multi_deltimeout()
3619
 *
3620
 * Remove a given timestamp from the list of timeouts.
3621
 */
3622
static void multi_deltimeout(struct Curl_easy *data, expire_id eid)
3623
10.4M
{
3624
10.4M
  struct Curl_llist_node *e;
3625
10.4M
  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3626
  /* find and remove the specific node from the list */
3627
20.7M
  for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
3628
20.4M
    struct time_node *n = Curl_node_elem(e);
3629
20.4M
    if(n->eid == eid) {
3630
10.1M
      Curl_node_remove(e);
3631
10.1M
      return;
3632
10.1M
    }
3633
20.4M
  }
3634
10.4M
}
3635
3636
/*
3637
 * multi_addtimeout()
3638
 *
3639
 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
3640
 * of list is always the timeout nearest in time.
3641
 *
3642
 */
3643
static CURLMcode multi_addtimeout(struct Curl_easy *data,
3644
                                  struct curltime *stamp,
3645
                                  expire_id eid)
3646
10.3M
{
3647
10.3M
  struct Curl_llist_node *e;
3648
10.3M
  struct time_node *node;
3649
10.3M
  struct Curl_llist_node *prev = NULL;
3650
10.3M
  size_t n;
3651
10.3M
  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3652
3653
10.3M
  node = &data->state.expires[eid];
3654
3655
  /* copy the timestamp and id */
3656
10.3M
  memcpy(&node->time, stamp, sizeof(*stamp));
3657
10.3M
  node->eid = eid; /* also marks it as in use */
3658
3659
10.3M
  n = Curl_llist_count(timeoutlist);
3660
10.3M
  if(n) {
3661
    /* find the correct spot in the list */
3662
20.3M
    for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
3663
12.4M
      struct time_node *check = Curl_node_elem(e);
3664
12.4M
      timediff_t diff = curlx_ptimediff_ms(&check->time, &node->time);
3665
12.4M
      if(diff > 0)
3666
2.32M
        break;
3667
10.1M
      prev = e;
3668
10.1M
    }
3669
10.2M
  }
3670
  /* else
3671
     this is the first timeout on the list */
3672
3673
10.3M
  Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
3674
10.3M
  CURL_TRC_TIMER(data, eid, "set for %" FMT_TIMEDIFF_T "ns",
3675
10.3M
                 curlx_ptimediff_us(&node->time, Curl_pgrs_now(data)));
3676
10.3M
  return CURLM_OK;
3677
10.3M
}
3678
3679
void Curl_expire_ex(struct Curl_easy *data,
3680
                    timediff_t milli, expire_id id)
3681
10.3M
{
3682
10.3M
  struct Curl_multi *multi = data->multi;
3683
10.3M
  struct curltime *curr_expire = &data->state.expiretime;
3684
10.3M
  struct curltime set;
3685
3686
  /* this is only interesting while there is still an associated multi struct
3687
     remaining! */
3688
10.3M
  if(!multi)
3689
0
    return;
3690
3691
10.3M
  DEBUGASSERT(id < EXPIRE_LAST);
3692
3693
10.3M
  set = *Curl_pgrs_now(data);
3694
10.3M
  set.tv_sec += (time_t)(milli / 1000); /* may be a 64 to 32-bit conversion */
3695
10.3M
  set.tv_usec += (int)(milli % 1000) * 1000;
3696
3697
10.3M
  if(set.tv_usec >= 1000000) {
3698
6.47M
    set.tv_sec++;
3699
6.47M
    set.tv_usec -= 1000000;
3700
6.47M
  }
3701
3702
  /* Remove any timer with the same id */
3703
10.3M
  multi_deltimeout(data, id);
3704
3705
  /* Add it to the timer list. It must stay in the list until it has expired
3706
     in case we need to recompute the minimum timer later. */
3707
10.3M
  multi_addtimeout(data, &set, id);
3708
3709
10.3M
  if(curr_expire->tv_sec || curr_expire->tv_usec) {
3710
    /* This means that the struct is added as a node in the splay tree.
3711
       Compare if the new time is earlier, and only remove-old/add-new if it
3712
       is. */
3713
10.2M
    timediff_t diff = curlx_ptimediff_ms(&set, curr_expire);
3714
10.2M
    int rc;
3715
3716
10.2M
    if(diff > 0) {
3717
      /* The current splay tree entry is sooner than this new expiry time.
3718
         We do not need to update our splay tree entry. */
3719
6.76M
      return;
3720
6.76M
    }
3721
3722
    /* Since this is an updated time, we must remove the previous entry from
3723
       the splay tree first and then re-add the new value */
3724
3.45M
    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3725
3.45M
                          &multi->timetree);
3726
3.45M
    if(rc)
3727
0
      infof(data, "Internal error removing splay node = %d", rc);
3728
3.45M
  }
3729
3730
  /* Indicate that we are in the splay tree and insert the new timer expiry
3731
     value since it is our local minimum. */
3732
3.59M
  *curr_expire = set;
3733
3.59M
  Curl_splayset(&data->state.timenode, data);
3734
3.59M
  multi->timetree = Curl_splayinsert(curr_expire, multi->timetree,
3735
3.59M
                                     &data->state.timenode);
3736
3.59M
}
3737
3738
/*
3739
 * Curl_expire()
3740
 *
3741
 * given a number of milliseconds from now to use to set the 'act before
3742
 * this'-time for the transfer, to be extracted by curl_multi_timeout()
3743
 *
3744
 * The timeout will be added to a queue of timeouts if it defines a moment in
3745
 * time that is later than the current head of queue.
3746
 *
3747
 * Expire replaces a former timeout using the same id if already set.
3748
 */
3749
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
3750
10.3M
{
3751
10.3M
  Curl_expire_ex(data, milli, id);
3752
10.3M
}
3753
3754
/*
3755
 * Curl_expire_done()
3756
 *
3757
 * Removes the expire timer. Marks it as done.
3758
 *
3759
 */
3760
void Curl_expire_done(struct Curl_easy *data, expire_id id)
3761
114k
{
3762
  /* remove the timer, if there */
3763
114k
  multi_deltimeout(data, id);
3764
114k
  CURL_TRC_TIMER(data, id, "cleared");
3765
114k
}
3766
3767
/*
3768
 * Curl_expire_clear()
3769
 *
3770
 * Clear ALL timeout values for this handle.
3771
 */
3772
void Curl_expire_clear(struct Curl_easy *data)
3773
791k
{
3774
791k
  struct Curl_multi *multi = data->multi;
3775
791k
  struct curltime *nowp = &data->state.expiretime;
3776
3777
  /* this is only interesting while there is still an associated multi struct
3778
     remaining! */
3779
791k
  if(!multi)
3780
415k
    return;
3781
3782
376k
  if(nowp->tv_sec || nowp->tv_usec) {
3783
    /* Since this is an cleared time, we must remove the previous entry from
3784
       the splay tree */
3785
142k
    struct Curl_llist *list = &data->state.timeoutlist;
3786
142k
    int rc;
3787
3788
142k
    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3789
142k
                          &multi->timetree);
3790
142k
    if(rc)
3791
0
      infof(data, "Internal error clearing splay node = %d", rc);
3792
3793
    /* clear the timeout list too */
3794
142k
    Curl_llist_destroy(list, NULL);
3795
3796
142k
    if(data->id >= 0)
3797
142k
      CURL_TRC_M(data, "[TIMEOUT] all cleared");
3798
142k
    nowp->tv_sec = 0;
3799
142k
    nowp->tv_usec = 0;
3800
142k
  }
3801
376k
}
3802
3803
CURLMcode curl_multi_assign(CURLM *m, curl_socket_t sockfd,
3804
                            void *sockp)
3805
0
{
3806
0
  struct Curl_multi *multi = m;
3807
0
  if(!GOOD_MULTI_HANDLE(multi))
3808
0
    return CURLM_BAD_HANDLE;
3809
3810
0
  return Curl_multi_ev_assign(multi, sockfd, sockp);
3811
0
}
3812
3813
static void move_pending_to_connect(struct Curl_multi *multi,
3814
                                    struct Curl_easy *data)
3815
2.89k
{
3816
2.89k
  DEBUGASSERT(data->mstate == MSTATE_PENDING);
3817
3818
  /* Remove this node from the pending set, add into process set */
3819
2.89k
  Curl_uint32_bset_remove(&multi->pending, data->mid);
3820
2.89k
  Curl_uint32_bset_add(&multi->process, data->mid);
3821
3822
2.89k
  multistate(data, MSTATE_CONNECT);
3823
2.89k
  Curl_multi_mark_dirty(data); /* make it run */
3824
2.89k
}
3825
3826
/* process_pending_handles() moves a handle from PENDING back into the process
3827
   list and change state to CONNECT.
3828
3829
   We do not move all transfers because that can be a significant amount.
3830
   Since this is tried every now and then doing too many too often becomes a
3831
   performance problem.
3832
3833
   When there is a change for connection limits like max host connections etc,
3834
   this likely only allows one new transfer. When there is a pipewait change,
3835
   it can potentially allow hundreds of new transfers.
3836
3837
   We could consider an improvement where we store the queue reason and allow
3838
   more pipewait rechecks than others.
3839
*/
3840
static void process_pending_handles(struct Curl_multi *multi)
3841
804k
{
3842
804k
  uint32_t mid = multi->last_pending_mid;
3843
3844
804k
  if(mid) {
3845
2.89k
    while(Curl_uint32_bset_next(&multi->pending, mid, &mid)) {
3846
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3847
0
      if(data) {
3848
0
        move_pending_to_connect(multi, data);
3849
0
        multi->last_pending_mid = mid;
3850
0
        return;
3851
0
      }
3852
      /* transfer no longer known, should not happen */
3853
0
      Curl_uint32_bset_remove(&multi->pending, mid);
3854
0
      DEBUGASSERT(0);
3855
0
    }
3856
    /* found no pending transfers with `mid` larger than `last_pending_mid`.
3857
     * Start at the beginning of the pending set again. */
3858
2.89k
    multi->last_pending_mid = 0;
3859
2.89k
  }
3860
3861
804k
  if(Curl_uint32_bset_first(&multi->pending, &mid)) {
3862
2.89k
    do {
3863
2.89k
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3864
2.89k
      if(data) {
3865
2.89k
        move_pending_to_connect(multi, data);
3866
2.89k
        multi->last_pending_mid = mid;
3867
2.89k
        return;
3868
2.89k
      }
3869
      /* transfer no longer known, should not happen */
3870
0
      Curl_uint32_bset_remove(&multi->pending, mid);
3871
0
      DEBUGASSERT(0);
3872
0
    } while(Curl_uint32_bset_next(&multi->pending, mid, &mid));
3873
2.89k
  }
3874
804k
}
3875
3876
void Curl_set_in_callback(struct Curl_easy *data, bool value)
3877
4.26M
{
3878
4.26M
  if(data && data->multi)
3879
4.26M
    data->multi->in_callback = value;
3880
4.26M
}
3881
3882
bool Curl_is_in_callback(struct Curl_easy *data)
3883
10.5k
{
3884
10.5k
  return data && data->multi && data->multi->in_callback;
3885
10.5k
}
3886
3887
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
3888
19.6k
{
3889
19.6k
  DEBUGASSERT(multi);
3890
19.6k
  return multi->max_concurrent_streams;
3891
19.6k
}
3892
3893
CURL **curl_multi_get_handles(CURLM *m)
3894
0
{
3895
0
  struct Curl_multi *multi = m;
3896
0
  void *entry;
3897
0
  size_t count = Curl_uint32_tbl_count(&multi->xfers);
3898
0
  CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1));
3899
0
  if(a) {
3900
0
    unsigned int i = 0;
3901
0
    uint32_t mid;
3902
3903
0
    if(Curl_uint32_tbl_first(&multi->xfers, &mid, &entry)) {
3904
0
      do {
3905
0
        struct Curl_easy *data = entry;
3906
0
        DEBUGASSERT(i < count);
3907
0
        if(!data->state.internal)
3908
0
          a[i++] = data;
3909
0
      } while(Curl_uint32_tbl_next(&multi->xfers, mid, &mid, &entry));
3910
0
    }
3911
0
    a[i] = NULL; /* last entry is a NULL */
3912
0
  }
3913
0
  return a;
3914
0
}
3915
3916
CURLMcode curl_multi_get_offt(CURLM *m,
3917
                              CURLMinfo_offt info,
3918
                              curl_off_t *pvalue)
3919
0
{
3920
0
  struct Curl_multi *multi = m;
3921
0
  uint32_t n;
3922
3923
0
  if(!GOOD_MULTI_HANDLE(multi))
3924
0
    return CURLM_BAD_HANDLE;
3925
0
  if(!pvalue)
3926
0
    return CURLM_BAD_FUNCTION_ARGUMENT;
3927
3928
0
  switch(info) {
3929
0
  case CURLMINFO_XFERS_CURRENT:
3930
0
    n = Curl_uint32_tbl_count(&multi->xfers);
3931
0
    if(n && multi->admin)
3932
0
      --n;
3933
0
    *pvalue = (curl_off_t)n;
3934
0
    return CURLM_OK;
3935
0
  case CURLMINFO_XFERS_RUNNING:
3936
0
    n = Curl_uint32_bset_count(&multi->process);
3937
0
    if(n && Curl_uint32_bset_contains(&multi->process, multi->admin->mid))
3938
0
      --n;
3939
0
    *pvalue = (curl_off_t)n;
3940
0
    return CURLM_OK;
3941
0
  case CURLMINFO_XFERS_PENDING:
3942
0
    *pvalue = (curl_off_t)Curl_uint32_bset_count(&multi->pending);
3943
0
    return CURLM_OK;
3944
0
  case CURLMINFO_XFERS_DONE:
3945
0
    *pvalue = (curl_off_t)Curl_uint32_bset_count(&multi->msgsent);
3946
0
    return CURLM_OK;
3947
0
  case CURLMINFO_XFERS_ADDED:
3948
0
    *pvalue = multi->xfers_total_ever;
3949
0
    return CURLM_OK;
3950
0
  default:
3951
0
    *pvalue = -1;
3952
0
    return CURLM_UNKNOWN_OPTION;
3953
0
  }
3954
0
}
3955
3956
CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
3957
                                    char **pbuf, size_t *pbuflen)
3958
6.43M
{
3959
6.43M
  DEBUGASSERT(data);
3960
6.43M
  DEBUGASSERT(data->multi);
3961
6.43M
  *pbuf = NULL;
3962
6.43M
  *pbuflen = 0;
3963
6.43M
  if(!data->multi) {
3964
0
    failf(data, "transfer has no multi handle");
3965
0
    return CURLE_FAILED_INIT;
3966
0
  }
3967
6.43M
  if(!data->set.buffer_size) {
3968
0
    failf(data, "transfer buffer size is 0");
3969
0
    return CURLE_FAILED_INIT;
3970
0
  }
3971
6.43M
  if(data->multi->xfer_buf_borrowed) {
3972
0
    failf(data, "attempt to borrow xfer_buf when already borrowed");
3973
0
    return CURLE_AGAIN;
3974
0
  }
3975
3976
6.43M
  if(data->multi->xfer_buf &&
3977
6.39M
     data->set.buffer_size > data->multi->xfer_buf_len) {
3978
    /* not large enough, get a new one */
3979
0
    curlx_safefree(data->multi->xfer_buf);
3980
0
    data->multi->xfer_buf_len = 0;
3981
0
  }
3982
3983
6.43M
  if(!data->multi->xfer_buf) {
3984
45.3k
    data->multi->xfer_buf = curlx_malloc(curlx_uitouz(data->set.buffer_size));
3985
45.3k
    if(!data->multi->xfer_buf) {
3986
0
      failf(data, "could not allocate xfer_buf of %u bytes",
3987
0
            data->set.buffer_size);
3988
0
      return CURLE_OUT_OF_MEMORY;
3989
0
    }
3990
45.3k
    data->multi->xfer_buf_len = data->set.buffer_size;
3991
45.3k
  }
3992
3993
6.43M
  data->multi->xfer_buf_borrowed = TRUE;
3994
6.43M
  *pbuf = data->multi->xfer_buf;
3995
6.43M
  *pbuflen = data->multi->xfer_buf_len;
3996
6.43M
  return CURLE_OK;
3997
6.43M
}
3998
3999
void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
4000
6.43M
{
4001
6.43M
  (void)buf;
4002
6.43M
  DEBUGASSERT(data);
4003
6.43M
  DEBUGASSERT(data->multi);
4004
6.43M
  DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
4005
6.43M
  data->multi->xfer_buf_borrowed = FALSE;
4006
6.43M
}
4007
4008
CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
4009
                                      char **pbuf, size_t *pbuflen)
4010
25
{
4011
25
  DEBUGASSERT(data);
4012
25
  DEBUGASSERT(data->multi);
4013
25
  *pbuf = NULL;
4014
25
  *pbuflen = 0;
4015
25
  if(!data->multi) {
4016
0
    failf(data, "transfer has no multi handle");
4017
0
    return CURLE_FAILED_INIT;
4018
0
  }
4019
25
  if(!data->set.upload_buffer_size) {
4020
0
    failf(data, "transfer upload buffer size is 0");
4021
0
    return CURLE_FAILED_INIT;
4022
0
  }
4023
25
  if(data->multi->xfer_ulbuf_borrowed) {
4024
0
    failf(data, "attempt to borrow xfer_ulbuf when already borrowed");
4025
0
    return CURLE_AGAIN;
4026
0
  }
4027
4028
25
  if(data->multi->xfer_ulbuf &&
4029
0
     data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
4030
    /* not large enough, get a new one */
4031
0
    curlx_safefree(data->multi->xfer_ulbuf);
4032
0
    data->multi->xfer_ulbuf_len = 0;
4033
0
  }
4034
4035
25
  if(!data->multi->xfer_ulbuf) {
4036
25
    data->multi->xfer_ulbuf =
4037
25
      curlx_malloc(curlx_uitouz(data->set.upload_buffer_size));
4038
25
    if(!data->multi->xfer_ulbuf) {
4039
0
      failf(data, "could not allocate xfer_ulbuf of %u bytes",
4040
0
            data->set.upload_buffer_size);
4041
0
      return CURLE_OUT_OF_MEMORY;
4042
0
    }
4043
25
    data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
4044
25
  }
4045
4046
25
  data->multi->xfer_ulbuf_borrowed = TRUE;
4047
25
  *pbuf = data->multi->xfer_ulbuf;
4048
25
  *pbuflen = data->multi->xfer_ulbuf_len;
4049
25
  return CURLE_OK;
4050
25
}
4051
4052
void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf)
4053
25
{
4054
25
  (void)buf;
4055
25
  DEBUGASSERT(data);
4056
25
  DEBUGASSERT(data->multi);
4057
25
  DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
4058
25
  data->multi->xfer_ulbuf_borrowed = FALSE;
4059
25
}
4060
4061
CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
4062
                                        size_t blen, char **pbuf)
4063
0
{
4064
0
  DEBUGASSERT(data);
4065
0
  DEBUGASSERT(data->multi);
4066
0
  *pbuf = NULL;
4067
0
  if(!data->multi) {
4068
0
    failf(data, "transfer has no multi handle");
4069
0
    return CURLE_FAILED_INIT;
4070
0
  }
4071
0
  if(data->multi->xfer_sockbuf_borrowed) {
4072
0
    failf(data, "attempt to borrow xfer_sockbuf when already borrowed");
4073
0
    return CURLE_AGAIN;
4074
0
  }
4075
4076
0
  if(data->multi->xfer_sockbuf && blen > data->multi->xfer_sockbuf_len) {
4077
    /* not large enough, get a new one */
4078
0
    curlx_safefree(data->multi->xfer_sockbuf);
4079
0
    data->multi->xfer_sockbuf_len = 0;
4080
0
  }
4081
4082
0
  if(!data->multi->xfer_sockbuf) {
4083
0
    data->multi->xfer_sockbuf = curlx_malloc(blen);
4084
0
    if(!data->multi->xfer_sockbuf) {
4085
0
      failf(data, "could not allocate xfer_sockbuf of %zu bytes", blen);
4086
0
      return CURLE_OUT_OF_MEMORY;
4087
0
    }
4088
0
    data->multi->xfer_sockbuf_len = blen;
4089
0
  }
4090
4091
0
  data->multi->xfer_sockbuf_borrowed = TRUE;
4092
0
  *pbuf = data->multi->xfer_sockbuf;
4093
0
  return CURLE_OK;
4094
0
}
4095
4096
void Curl_multi_xfer_sockbuf_release(struct Curl_easy *data, char *buf)
4097
0
{
4098
0
  (void)buf;
4099
0
  DEBUGASSERT(data);
4100
0
  DEBUGASSERT(data->multi);
4101
0
  DEBUGASSERT(!buf || data->multi->xfer_sockbuf == buf);
4102
0
  data->multi->xfer_sockbuf_borrowed = FALSE;
4103
0
}
4104
4105
static void multi_xfer_bufs_free(struct Curl_multi *multi)
4106
181k
{
4107
181k
  DEBUGASSERT(multi);
4108
181k
  curlx_safefree(multi->xfer_buf);
4109
181k
  multi->xfer_buf_len = 0;
4110
181k
  multi->xfer_buf_borrowed = FALSE;
4111
181k
  curlx_safefree(multi->xfer_ulbuf);
4112
181k
  multi->xfer_ulbuf_len = 0;
4113
181k
  multi->xfer_ulbuf_borrowed = FALSE;
4114
181k
  curlx_safefree(multi->xfer_sockbuf);
4115
181k
  multi->xfer_sockbuf_len = 0;
4116
181k
  multi->xfer_sockbuf_borrowed = FALSE;
4117
181k
}
4118
4119
struct Curl_easy *Curl_multi_get_easy(struct Curl_multi *multi,
4120
                                      uint32_t mid)
4121
47.6M
{
4122
47.6M
  struct Curl_easy *data = Curl_uint32_tbl_get(&multi->xfers, mid);
4123
47.6M
  if(GOOD_EASY_HANDLE(data))
4124
47.6M
    return data;
4125
0
  CURL_TRC_M(multi->admin, "invalid easy handle in xfer table for mid=%u",
4126
0
             mid);
4127
0
  Curl_uint32_tbl_remove(&multi->xfers, mid);
4128
0
  return NULL;
4129
47.6M
}
4130
4131
unsigned int Curl_multi_xfers_running(struct Curl_multi *multi)
4132
10.6M
{
4133
10.6M
  DEBUGASSERT(multi);
4134
10.6M
  if(!multi)
4135
0
    return 0;
4136
10.6M
  return multi->xfers_alive;
4137
10.6M
}
4138
4139
void Curl_multi_mark_dirty(struct Curl_easy *data)
4140
429k
{
4141
429k
  if(data->multi && data->mid != UINT32_MAX)
4142
429k
    Curl_uint32_bset_add(&data->multi->dirty, data->mid);
4143
429k
}
4144
4145
void Curl_multi_clear_dirty(struct Curl_easy *data)
4146
1.59k
{
4147
1.59k
  if(data->multi && data->mid != UINT32_MAX)
4148
1.59k
    Curl_uint32_bset_remove(&data->multi->dirty, data->mid);
4149
1.59k
}
4150
4151
CURLMcode curl_multi_notify_enable(CURLM *m, unsigned int notification)
4152
0
{
4153
0
  struct Curl_multi *multi = m;
4154
4155
0
  if(!GOOD_MULTI_HANDLE(multi))
4156
0
    return CURLM_BAD_HANDLE;
4157
0
  return Curl_mntfy_enable(multi, notification);
4158
0
}
4159
4160
CURLMcode curl_multi_notify_disable(CURLM *m, unsigned int notification)
4161
0
{
4162
0
  struct Curl_multi *multi = m;
4163
4164
0
  if(!GOOD_MULTI_HANDLE(multi))
4165
0
    return CURLM_BAD_HANDLE;
4166
0
  return Curl_mntfy_disable(multi, notification);
4167
0
}
4168
4169
#ifdef DEBUGBUILD
4170
static void multi_xfer_dump(struct Curl_multi *multi, uint32_t mid,
4171
                            void *entry)
4172
0
{
4173
0
  struct Curl_easy *data = entry;
4174
4175
0
  (void)multi;
4176
0
  if(!data) {
4177
0
    curl_mfprintf(stderr, "mid=%u, entry=NULL, bug in xfer table?\n", mid);
4178
0
  }
4179
0
  else {
4180
0
    curl_mfprintf(stderr, "mid=%u, magic=%s, p=%p, id=%" FMT_OFF_T
4181
0
                  ", url=%s\n",
4182
0
                  mid,
4183
0
                  (data->magic == CURLEASY_MAGIC_NUMBER) ? "GOOD" : "BAD!",
4184
0
                  (void *)data, data->id, Curl_bufref_ptr(&data->state.url));
4185
0
  }
4186
0
}
4187
4188
static void multi_xfer_tbl_dump(struct Curl_multi *multi)
4189
0
{
4190
0
  uint32_t mid;
4191
0
  void *entry;
4192
0
  curl_mfprintf(stderr, "=== multi xfer table (count=%u, capacity=%u\n",
4193
0
                Curl_uint32_tbl_count(&multi->xfers),
4194
0
                Curl_uint32_tbl_capacity(&multi->xfers));
4195
0
  if(Curl_uint32_tbl_first(&multi->xfers, &mid, &entry)) {
4196
0
    multi_xfer_dump(multi, mid, entry);
4197
0
    while(Curl_uint32_tbl_next(&multi->xfers, mid, &mid, &entry))
4198
0
      multi_xfer_dump(multi, mid, entry);
4199
0
  }
4200
0
  curl_mfprintf(stderr, "===\n");
4201
  fflush(stderr);
4202
0
}
4203
#endif /* DEBUGBUILD */