Coverage Report

Created: 2026-11-12 08:28

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