Coverage Report

Created: 2026-09-01 06:58

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