Coverage Report

Created: 2026-10-15 06:19

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