Coverage Report

Created: 2026-09-04 07:15

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