Coverage Report

Created: 2026-09-14 07:05

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