Coverage Report

Created: 2026-10-22 06:49

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