Coverage Report

Created: 2026-09-04 07:16

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
35.6k
#define CURL_XFER_TABLE_SIZE 128
53
54
/* CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
55
   to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
56
   curl handle takes 6K memory, therefore this 3K are not significant. */
57
#ifndef CURL_SOCKET_HASH_TABLE_SIZE
58
17.8k
#define CURL_SOCKET_HASH_TABLE_SIZE 911
59
#endif
60
61
#ifndef CURL_CONNECTION_HASH_SIZE
62
17.8k
#define CURL_CONNECTION_HASH_SIZE 97
63
#endif
64
65
#ifndef CURL_DNS_HASH_SIZE
66
17.8k
#define CURL_DNS_HASH_SIZE 71
67
#endif
68
69
#ifndef CURL_TLS_SESSION_SIZE
70
17.8k
#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
83.2k
{
89
83.2k
  curlx_pnow(&multi->now);
90
83.2k
  return &multi->now;
91
83.2k
}
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
39.9k
{
100
39.9k
  (void)from_state;
101
39.9k
  Curl_init_CONNECT(data);
102
39.9k
}
103
104
static void mstate_enter_did(struct Curl_easy *data,
105
                             CURLMstate from_state)
106
37.7k
{
107
37.7k
  (void)from_state;
108
37.7k
  data->req.chunk = FALSE;
109
37.7k
  Curl_pgrsTime(data, TIMER_PRETRANSFER);
110
37.7k
  if(!CURL_REQ_WANT_SEND(data))
111
34.0k
    Curl_pgrsTime(data, TIMER_POSTRANSFER);
112
37.7k
}
113
114
static void mstate_enter_done(struct Curl_easy *data,
115
                              CURLMstate from_state)
116
10.1k
{
117
10.1k
  (void)from_state;
118
10.1k
  CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE);
119
10.1k
}
120
121
static void mstate_enter_completed(struct Curl_easy *data,
122
                                   CURLMstate from_state)
123
17.6k
{
124
  /* we sometimes directly jump to COMPLETED, trigger things
125
   * we then missed. */
126
17.6k
  if(from_state < MSTATE_DID) {
127
2.27k
    Curl_pgrsTime(data, TIMER_PRETRANSFER);
128
2.27k
    Curl_pgrsTime(data, TIMER_POSTRANSFER);
129
2.27k
    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
130
2.27k
  }
131
17.6k
  Curl_pgrsCompleted(data);
132
17.6k
  if(from_state < MSTATE_DONE)
133
7.51k
    CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE);
134
  /* changing to COMPLETED means it is in process and needs to go */
135
17.6k
  DEBUGASSERT(Curl_uint32_bset_contains(&data->multi->process, data->mid));
136
17.6k
  Curl_uint32_bset_remove(&data->multi->process, data->mid);
137
17.6k
  Curl_uint32_bset_remove(&data->multi->pending, data->mid); /* to be sure */
138
139
17.6k
  if(Curl_uint32_bset_empty(&data->multi->process)) {
140
    /* free the transfer buffer when we have no more active transfers */
141
0
    multi_xfer_bufs_free(data->multi);
142
0
  }
143
  /* Important: reset the conn pointer so that we do not point to memory
144
     that could be freed anytime */
145
17.6k
  Curl_detach_connection(data);
146
17.6k
  Curl_expire_clear_all(data); /* stop all timers */
147
17.6k
}
148
149
/* always use this function to change state, to make debugging easier */
150
static void mstate(struct Curl_easy *data, CURLMstate state
151
#ifdef DEBUGBUILD
152
                   , int lineno
153
#endif
154
)
155
335k
{
156
335k
  CURLMstate oldstate = data->mstate;
157
335k
  static const mstate_enter_func state_enter[MSTATE_LAST] = {
158
335k
    NULL,                      /* INIT */
159
335k
    NULL,                      /* PENDING */
160
335k
    NULL,                      /* SETUP */
161
335k
    mstate_enter_connect,      /* CONNECT */
162
335k
    NULL,                      /* CONNECTING */
163
335k
    NULL,                      /* PROTOCONNECT */
164
335k
    NULL,                      /* PROTOCONNECTING */
165
335k
    NULL,                      /* DO */
166
335k
    NULL,                      /* DOING */
167
335k
    NULL,                      /* DOING_MORE */
168
335k
    mstate_enter_did,          /* DID */
169
335k
    NULL,                      /* PERFORMING */
170
335k
    NULL,                      /* RATELIMITING */
171
335k
    mstate_enter_done,         /* DONE */
172
335k
    mstate_enter_completed,    /* COMPLETED */
173
    NULL                       /* MSGSENT */
174
335k
  };
175
176
335k
  if(oldstate == state)
177
    /* do not bother when the new state is the same as the old state */
178
17.8k
    return;
179
180
317k
#ifdef DEBUGBUILD
181
317k
  NOVERBOSE((void)lineno);
182
317k
  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
317k
  data->mstate = state;
189
317k
  if(state_enter[state])
190
105k
    state_enter[state](data, oldstate);
191
317k
}
192
193
#ifndef DEBUGBUILD
194
#define multistate(x, y) mstate(x, y)
195
#else
196
335k
#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
17.6k
{
217
17.6k
  if(Curl_uint32_bset_empty(&multi->msgsent))
218
17.6k
    CURLM_NTFY(multi->admin, CURLMNOTIFY_INFO_READ);
219
17.6k
  Curl_uint32_bset_add(&multi->msgsent, data->mid);
220
17.6k
}
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
17.8k
{
230
17.8k
  struct Curl_multi *multi = curlx_calloc(1, sizeof(struct Curl_multi));
231
232
17.8k
  if(!multi)
233
0
    return NULL;
234
235
17.8k
  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
17.8k
  multi->admin = curl_easy_init();
242
17.8k
  if(!multi->admin) {
243
0
    curlx_free(multi);
244
0
    return NULL;
245
0
  }
246
17.8k
  multi->admin->multi = multi;
247
17.8k
  multi->admin->state.internal = TRUE;
248
249
  /* Now we can use curlx_* things safely */
250
17.8k
  curlx_pnow(&multi->now);
251
17.8k
  Curl_timeouts_init(&multi->timeouts, &multi->now);
252
17.8k
  multi_timeouts_init(multi->admin);
253
254
17.8k
  Curl_dnscache_init(&multi->dnscache, dnssize);
255
17.8k
  Curl_mntfy_init(multi);
256
17.8k
  Curl_multi_ev_init(multi, ev_hashsize);
257
17.8k
  Curl_uint32_tbl_init(&multi->xfers, NULL);
258
17.8k
  Curl_uint32_bset_init(&multi->process);
259
17.8k
  Curl_uint32_bset_init(&multi->dirty);
260
17.8k
  Curl_uint32_bset_init(&multi->pending);
261
17.8k
  Curl_uint32_bset_init(&multi->msgsent);
262
17.8k
  Curl_hash_init(&multi->proto_hash, 23,
263
17.8k
                 Curl_hash_str, curlx_str_key_compare, ph_freeentry);
264
265
17.8k
  multi->multiplexing = TRUE;
266
17.8k
  multi->max_concurrent_streams = 100;
267
17.8k
  multi->last_timeout_ms = -1;
268
17.8k
#ifdef ENABLE_WAKEUP
269
17.8k
  multi->wakeup_pair[0] = CURL_SOCKET_BAD;
270
17.8k
  multi->wakeup_pair[1] = CURL_SOCKET_BAD;
271
17.8k
#endif
272
17.8k
#ifdef ENABLE_INTERNAL_WAKEUP
273
17.8k
  multi->wakeup_internal[0] = CURL_SOCKET_BAD;
274
17.8k
  multi->wakeup_internal[1] = CURL_SOCKET_BAD;
275
17.8k
#endif
276
277
17.8k
  if(Curl_uint32_bset_resize(&multi->process, xfer_table_size) ||
278
17.8k
     Curl_uint32_bset_resize(&multi->pending, xfer_table_size) ||
279
17.8k
     Curl_uint32_bset_resize(&multi->dirty, xfer_table_size) ||
280
17.8k
     Curl_uint32_bset_resize(&multi->msgsent, xfer_table_size) ||
281
17.8k
     Curl_uint32_tbl_resize(&multi->xfers, xfer_table_size))
282
0
    goto error;
283
284
17.8k
#ifdef DEBUGBUILD
285
17.8k
  if(getenv("CURL_DEBUG"))
286
0
    multi->admin->set.verbose = TRUE;
287
17.8k
#endif
288
17.8k
  Curl_uint32_tbl_add(&multi->xfers, multi->admin, &multi->admin->mid);
289
17.8k
  Curl_uint32_bset_add(&multi->process, multi->admin->mid);
290
291
17.8k
  if(Curl_cshutdn_init(&multi->cshutdn, multi))
292
0
    goto error;
293
294
17.8k
  Curl_cpool_init(&multi->cpool, NULL, chashsize);
295
296
17.8k
#ifdef USE_SSL
297
17.8k
  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
17.8k
#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
17.8k
  if(Curl_wakeup_init(multi->wakeup_pair, TRUE) < 0)
312
0
    goto error;
313
17.8k
#endif
314
17.8k
#ifdef ENABLE_INTERNAL_WAKEUP
315
17.8k
  if(Curl_wakeup_init(multi->wakeup_internal, TRUE) < 0)
316
0
    goto error;
317
17.8k
#endif
318
319
17.8k
  if(Curl_probeipv6(multi))
320
0
    goto error;
321
322
17.8k
#ifdef USE_RESOLV_THREADED
323
17.8k
  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
17.8k
  else { /* real multi handle */
328
17.8k
    if(Curl_async_thrdd_multi_init(multi, 0, 20, 2000))
329
0
      goto error;
330
17.8k
  }
331
17.8k
#endif
332
333
17.8k
  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
17.8k
}
370
371
CURLM *curl_multi_init(void)
372
17.8k
{
373
17.8k
  return Curl_multi_handle(CURL_XFER_TABLE_SIZE,
374
17.8k
                           CURL_SOCKET_HASH_TABLE_SIZE,
375
17.8k
                           CURL_CONNECTION_HASH_SIZE,
376
17.8k
                           CURL_DNS_HASH_SIZE,
377
17.8k
                           CURL_TLS_SESSION_SIZE);
378
17.8k
}
379
380
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
381
static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
382
184k
{
383
184k
  if(!multi->warned) {
384
17.8k
    infof(data, "!!! WARNING !!!");
385
17.8k
    infof(data, "This is a debug build of libcurl, "
386
17.8k
                "do not use in production.");
387
17.8k
    multi->warned = TRUE;
388
17.8k
  }
389
184k
}
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
424k
{
396
424k
  return data->mstate < MSTATE_DO;
397
424k
}
398
399
static CURLMcode multi_assess_wakeup(struct Curl_multi *multi)
400
71.0k
{
401
71.0k
#ifdef ENABLE_INTERNAL_WAKEUP
402
71.0k
  if(multi->socket_cb)
403
0
    return Curl_multi_ev_assess_xfer(multi, multi->admin);
404
#else
405
  (void)multi;
406
#endif
407
71.0k
  return CURLM_OK;
408
71.0k
}
409
410
static CURLMcode multi_xfers_add(struct Curl_multi *multi,
411
                                 struct Curl_easy *data)
412
17.8k
{
413
17.8k
  uint32_t capacity = Curl_uint32_tbl_capacity(&multi->xfers);
414
17.8k
  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
17.8k
  const uint32_t max_capacity = UINT_MAX - 1;
419
420
17.8k
  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
17.8k
    uint32_t used = Curl_uint32_tbl_count(&multi->xfers);
425
17.8k
    uint32_t unused = capacity - used;
426
17.8k
    uint32_t min_unused = CURLMAX(capacity >> 3, 4);
427
17.8k
    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
17.8k
  }
439
440
17.8k
  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
17.8k
  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
17.8k
  return CURLM_OK;
462
17.8k
}
463
464
CURLMcode Curl_multi_add_handle(struct Curl_multi *multi,
465
                                struct Curl_easy *data)
466
17.8k
{
467
17.8k
  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
17.8k
  if(data->multi)
472
0
    return CURLM_ADDED_ALREADY;
473
474
17.8k
  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
17.8k
  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
17.8k
  if(multi_xfers_add(multi, data))
498
0
    return CURLM_OUT_OF_MEMORY;
499
500
  /* Initialize timeouts for this handle */
501
17.8k
  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
17.8k
  if(data->set.errorbuffer)
510
0
    data->set.errorbuffer[0] = 0;
511
512
17.8k
  data->state.os_errno = 0;
513
514
  /* make the Curl_easy refer back to this multi handle - before
515
     Curl_expire() is called. */
516
17.8k
  data->multi = multi;
517
518
  /* set the easy handle */
519
17.8k
  multistate(data, MSTATE_INIT);
520
  /* not yet passed INIT state */
521
17.8k
  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
17.8k
  Curl_uint32_bset_add(&multi->process, data->mid);
533
17.8k
  ++multi->xfers_alive;
534
17.8k
  ++multi->xfers_total_ever;
535
536
17.8k
  Curl_cpool_xfer_init(data);
537
17.8k
  multi_warn_debug(multi, data);
538
539
  /* Make sure the new handle will run */
540
17.8k
  Curl_multi_mark_dirty(data);
541
542
  /* Necessary in event based processing, where dirty handles trigger
543
   * a timeout callback invocation. */
544
17.8k
  mresult = Curl_update_timer(multi);
545
17.8k
  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
17.8k
  multi->admin->set.timeout = data->set.timeout;
557
17.8k
  multi->admin->set.server_response_timeout =
558
17.8k
    data->set.server_response_timeout;
559
17.8k
  multi->admin->set.no_signal = data->set.no_signal;
560
561
17.8k
  CURL_TRC_M(data, "added to multi, mid=%u, running=%u, total=%u",
562
17.8k
             data->mid, Curl_multi_xfers_running(multi),
563
17.8k
             Curl_uint32_tbl_count(&multi->xfers));
564
17.8k
  return CURLM_OK;
565
17.8k
}
566
567
CURLMcode curl_multi_add_handle(CURLM *m, CURL *curl)
568
17.8k
{
569
17.8k
  struct Curl_mapi_guard guard;
570
17.8k
  CURLMcode mresult;
571
572
17.8k
  if(CURL_MAPI_ENTER(&guard, m, multi_add_handle, &mresult)) {
573
17.8k
    struct Curl_easy *data = curl;
574
    /* Verify that we got a somewhat good easy handle too */
575
17.8k
    if(!GOOD_EASY_HANDLE(data))
576
0
      mresult = CURLM_BAD_EASY_HANDLE;
577
17.8k
    else
578
17.8k
      mresult = Curl_multi_add_handle(m, data);
579
17.8k
  }
580
17.8k
  CURL_MAPI_LEAVE(&guard);
581
17.8k
  return mresult;
582
17.8k
}
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
39.9k
{
592
  /* if conn->bits.close is TRUE, it means that the connection should be
593
     closed in spite of everything else. */
594
39.9k
  if(conn->bits.close)
595
21.8k
    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
18.0k
  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
18.0k
    )
610
38
    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
18.0k
  if(!data->set.connect_only && conn->scheme &&
615
17.9k
     !(conn->scheme->flags & PROTOPT_CONN_REUSE))
616
0
    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
18.0k
  if(premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))
624
1.96k
    return TRUE;
625
626
16.0k
  return FALSE;
627
18.0k
}
628
629
static void multi_done_locked(struct connectdata *conn,
630
                              struct Curl_easy *data,
631
                              void *userdata)
632
39.9k
{
633
39.9k
  struct multi_done_ctx *mdctx = userdata;
634
635
39.9k
  Curl_detach_connection(data);
636
637
39.9k
  CURL_TRC_M(data, "multi_done_locked, in use=%u", conn->attached_xfers);
638
39.9k
  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
39.9k
  data->state.done = TRUE; /* called now! */
646
647
39.9k
  Curl_dnscache_prune(data);
648
649
39.9k
  if(multi_conn_should_close(conn, data, (bool)mdctx->premature)) {
650
23.8k
    CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s:%u, "
651
23.8k
               "forbid=%d, close=%d, premature=%d, conn_multiplex=%d",
652
23.8k
               conn->connection_id, conn->origin->user_hostname,
653
23.8k
               conn->origin->port,
654
23.8k
               data->set.reuse_forbid, conn->bits.close, mdctx->premature,
655
23.8k
               Curl_conn_is_multiplex(conn, FIRSTSOCKET));
656
23.8k
    connclose(conn);
657
23.8k
    Curl_conn_close(data, conn, (bool)mdctx->premature);
658
23.8k
  }
659
16.0k
  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
16.0k
  else {
667
    /* the connection is no longer in use by any transfer */
668
16.0k
    if(Curl_cpool_conn_now_idle(data, conn)) {
669
      /* connection kept in the cpool */
670
16.0k
      infof(data, "Connection #%" FMT_OFF_T " to host %s:%u left intact",
671
16.0k
            conn->connection_id, conn->origin->user_hostname,
672
16.0k
            conn->origin->port);
673
16.0k
    }
674
0
    else {
675
      /* connection was removed from the cpool and destroyed. */
676
0
      data->state.lastconnect_id = -1;
677
0
    }
678
16.0k
  }
679
39.9k
}
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
39.9k
{
686
39.9k
  CURLcode result;
687
39.9k
  struct connectdata *conn = data->conn;
688
689
39.9k
  CURL_TRC_M(data, "multi_done: status: %d prem: %d done: %d",
690
39.9k
             (int)status, (int)premature, data->state.done);
691
692
39.9k
  if(data->state.done)
693
    /* Stop if multi_done() has already been called */
694
0
    return CURLE_OK;
695
696
  /* Shut down any ongoing async resolver operation. */
697
39.9k
  Curl_resolv_shutdown_all(data);
698
699
  /* Cleanup possible redirect junk */
700
39.9k
  curlx_safefree(data->req.newurl);
701
39.9k
  curlx_safefree(data->req.location);
702
703
39.9k
  switch(status) {
704
20
  case CURLE_ABORTED_BY_CALLBACK:
705
385
  case CURLE_READ_ERROR:
706
468
  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
468
    premature = TRUE;
712
468
    FALLTHROUGH();
713
39.9k
  default:
714
39.9k
    break;
715
39.9k
  }
716
717
  /* this calls the protocol-specific function pointer previously set */
718
39.9k
  if(conn && conn->scheme->run->done && (data->mstate >= MSTATE_PROTOCONNECT))
719
38.1k
    result = conn->scheme->run->done(data, status, premature);
720
1.79k
  else
721
1.79k
    result = status;
722
723
39.9k
  if(data->mstate > MSTATE_CONNECTING &&
724
38.1k
     (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
38.1k
    int rc = Curl_pgrsDone(data);
730
38.1k
    if(!result && rc)
731
0
      result = CURLE_ABORTED_BY_CALLBACK;
732
38.1k
  }
733
734
  /* Make sure that transfer client writes are really done now. */
735
39.9k
  result = Curl_1st_fatal(result, Curl_xfer_write_done(data, premature));
736
737
  /* Inform connection filters that this transfer is done */
738
39.9k
  if(conn)
739
39.9k
    Curl_conn_ev_data_done(data, premature);
740
741
39.9k
  multi_schedule_pending(data->multi); /* connection / multiplex */
742
743
39.9k
  if(!result)
744
24.4k
    result = Curl_req_done(&data->req, data, premature);
745
746
39.9k
  if(conn) {
747
    /* Under the potential connection pool's share lock, decide what to
748
     * do with the transfer's connection. */
749
39.9k
    struct multi_done_ctx mdctx;
750
751
39.9k
    memset(&mdctx, 0, sizeof(mdctx));
752
39.9k
    mdctx.premature = premature;
753
39.9k
    Curl_cpool_do_locked(data, data->conn, multi_done_locked, &mdctx);
754
39.9k
  }
755
756
  /* flush the netrc cache */
757
39.9k
  Curl_netrc_cleanup(&data->state.netrc);
758
39.9k
  return result;
759
39.9k
}
760
761
CURLMcode Curl_multi_remove_handle(struct Curl_multi *multi,
762
                                   struct Curl_easy *data)
763
17.8k
{
764
17.8k
  CURLMcode mresult;
765
17.8k
  bool premature;
766
17.8k
  uint32_t mid;
767
768
  /* Prevent users from trying to remove same easy handle more than once */
769
17.8k
  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
17.8k
  if(data->multi != multi)
774
0
    return CURLM_BAD_EASY_HANDLE;
775
776
17.8k
  if(data->mid == UINT32_MAX) {
777
0
    DEBUGASSERT(0);
778
0
    return CURLM_INTERNAL_ERROR;
779
0
  }
780
17.8k
  if(Curl_uint32_tbl_get(&multi->xfers, data->mid) != data) {
781
0
    DEBUGASSERT(0);
782
0
    return CURLM_INTERNAL_ERROR;
783
0
  }
784
785
17.8k
  premature = (data->mstate < MSTATE_COMPLETED);
786
787
17.8k
  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
142
    if(premature && (data->mstate > MSTATE_DO))
791
142
      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
142
    (void)multi_done(data, data->result, premature);
798
142
  }
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
17.8k
  Curl_expire_clear_all(data);
804
805
  /* In MSGSENT, it was deducted from `multi->xfers_alive` already. */
806
17.8k
  if(data->mstate != MSTATE_MSGSENT)
807
142
    --multi->xfers_alive;
808
809
17.8k
  if(data->state.really_alive) {
810
142
    data->state.really_alive = FALSE;
811
142
    --multi->xfers_really_alive;
812
142
    if(!multi->xfers_really_alive)
813
142
      (void)multi_assess_wakeup(multi);
814
142
  }
815
816
17.8k
  Curl_wildcard_dtor(&data->wildcard);
817
818
17.8k
  data->mstate = MSTATE_COMPLETED;
819
820
  /* Remove the association between the connection and the handle */
821
17.8k
  Curl_detach_connection(data);
822
823
  /* Tell event handling that this transfer is definitely going away */
824
17.8k
  Curl_multi_ev_xfer_done(multi, data);
825
826
17.8k
  if(data->set.connect_only) {
827
82
    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
82
    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
82
      struct connectdata *conn;
845
82
      (void)Curl_getconnectinfo(data, &conn);
846
82
      if(conn)
847
29
        Curl_conn_close(data, conn, TRUE);
848
82
    }
849
82
  }
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
17.8k
  mid = data->mid;
859
17.8k
  DEBUGASSERT(Curl_uint32_tbl_contains(&multi->xfers, mid));
860
17.8k
  Curl_uint32_tbl_remove(&multi->xfers, mid);
861
17.8k
  Curl_uint32_bset_remove(&multi->process, mid);
862
17.8k
  Curl_uint32_bset_remove(&multi->dirty, mid);
863
17.8k
  Curl_uint32_bset_remove(&multi->pending, mid);
864
17.8k
  Curl_uint32_bset_remove(&multi->msgsent, mid);
865
17.8k
  data->multi = NULL;
866
17.8k
  data->mid = UINT32_MAX;
867
17.8k
  data->master_mid = UINT32_MAX;
868
869
  /* A pending transfer *might* be able to run now. */
870
17.8k
  multi_schedule_pending(multi);
871
17.8k
  mresult = Curl_update_timer(multi);
872
17.8k
  if(mresult)
873
0
    return mresult;
874
875
17.8k
  mresult = multi_assess_wakeup(multi);
876
17.8k
  if(mresult) {
877
0
    failf(data, "error enabling wakeup listening: %d", mresult);
878
0
    return mresult;
879
0
  }
880
881
17.8k
  CURL_TRC_M(data, "removed from multi, mid=%u, running=%u, total=%u",
882
17.8k
             mid, Curl_multi_xfers_running(multi),
883
17.8k
             Curl_uint32_tbl_count(&multi->xfers));
884
17.8k
  return CURLM_OK;
885
17.8k
}
886
887
CURLMcode curl_multi_remove_handle(CURLM *m, CURL *curl)
888
17.8k
{
889
17.8k
  struct Curl_mapi_guard guard;
890
17.8k
  CURLMcode mresult;
891
892
17.8k
  if(CURL_MAPI_ENTER(&guard, m, multi_remove_handle, &mresult)) {
893
17.8k
    struct Curl_easy *data = curl;
894
17.8k
    if(!GOOD_EASY_HANDLE(data))
895
0
      mresult = CURLM_BAD_EASY_HANDLE;
896
17.8k
    else
897
17.8k
      mresult = Curl_multi_remove_handle(m, data);
898
17.8k
  }
899
17.8k
  CURL_MAPI_LEAVE(&guard);
900
17.8k
  return mresult;
901
17.8k
}
902
903
/* Return TRUE if the application asked for multiplexing */
904
bool Curl_multiplex_wanted(const struct Curl_multi *multi)
905
39.6k
{
906
39.6k
  return multi && multi->multiplexing;
907
39.6k
}
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
156k
{
917
156k
  struct connectdata *conn = data->conn;
918
156k
  if(conn) {
919
    /* this should never happen, prevent underflow */
920
85.6k
    DEBUGASSERT(conn->attached_xfers);
921
85.6k
    if(conn->attached_xfers) {
922
85.6k
      conn->attached_xfers--;
923
85.6k
      if(!conn->attached_xfers)
924
85.6k
        conn->attached_multi = NULL;
925
85.6k
    }
926
85.6k
  }
927
156k
  data->conn = NULL;
928
156k
}
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
85.6k
{
941
85.6k
  DEBUGASSERT(data);
942
85.6k
  DEBUGASSERT(!data->conn);
943
85.6k
  DEBUGASSERT(conn);
944
85.6k
  DEBUGASSERT(conn->attached_xfers < UINT32_MAX);
945
85.6k
  data->conn = conn;
946
85.6k
  if(matched)
947
39.9k
    data->state.lastconnect_id = conn->connection_id;
948
45.7k
  else
949
85.6k
    DEBUGASSERT(!data->mid); /* admin handle */
950
85.6k
  conn->attached_xfers++;
951
  /* all attached transfers must be from the same multi */
952
85.6k
  if(!conn->attached_multi)
953
85.6k
    conn->attached_multi = data->multi;
954
85.6k
  DEBUGASSERT(conn->attached_multi == data->multi);
955
956
85.6k
  if(conn->scheme && conn->scheme->run->attach)
957
0
    conn->scheme->run->attach(data, conn);
958
85.6k
}
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
541k
{
1725
541k
  bool retval = FALSE;
1726
541k
  DEBUGASSERT(multi);
1727
541k
  if(multi) {
1728
541k
    retval = (bool)multi->recheckstate;
1729
541k
    if(clear)
1730
449k
      multi->recheckstate = FALSE;
1731
541k
  }
1732
541k
  return retval;
1733
541k
}
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
28.1k
{
1744
28.1k
  multi->recheckstate = TRUE;
1745
28.1k
}
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
38.1k
{
1775
38.1k
  CURLcode result = CURLE_OK;
1776
38.1k
  struct connectdata *conn = data->conn;
1777
1778
38.1k
  DEBUGASSERT(conn);
1779
38.1k
  DEBUGASSERT(conn->scheme);
1780
1781
38.1k
  if(conn->scheme->run->do_it)
1782
38.1k
    result = conn->scheme->run->do_it(data, done);
1783
1784
38.1k
  return result;
1785
38.1k
}
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
331k
{
1817
331k
  timediff_t timeout_ms;
1818
1819
331k
  timeout_ms = Curl_timeleft_now_ms(data, pnow);
1820
331k
  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
331k
  return FALSE;
1856
331k
}
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
23.0k
{
1906
23.0k
  struct connectdata *conn = data->conn;
1907
23.0k
  CURLcode result = CURLE_OK;
1908
1909
23.0k
  DEBUGASSERT(conn);
1910
23.0k
  DEBUGASSERT(protocol_done);
1911
23.0k
  DEBUGASSERT(Curl_conn_is_connected(conn, FIRSTSOCKET));
1912
1913
23.0k
  *protocol_done = FALSE;
1914
23.0k
  if(!conn->bits.protoconnstart) {
1915
23.0k
    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
23.0k
    conn->bits.protoconnstart = TRUE;
1922
23.0k
  }
1923
1924
  /* Unless this protocol does not have any protocol-connect callback, as
1925
     then we know we are done. */
1926
23.0k
  if(!conn->scheme->run->connecting)
1927
23.0k
    *protocol_done = TRUE;
1928
23.0k
  return CURLE_OK;
1929
23.0k
}
1930
1931
/*
1932
 * posttransfer() is called immediately after a transfer ends
1933
 */
1934
static void multi_posttransfer(struct Curl_easy *data)
1935
39.8k
{
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
39.8k
  (void)data;
1942
39.8k
#endif
1943
39.8k
}
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
22.7k
{
1956
22.7k
  if(handler && handler->run->follow)
1957
22.7k
    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
123k
{
1969
123k
  if(Curl_rlimit_active(&data->progress.dl.rlimit) ||
1970
123k
     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
123k
  if(data->mstate != MSTATE_PERFORMING) {
2005
0
    CURL_TRC_M(data, "[RLIMIT] wait over, continue");
2006
0
    multistate(data, MSTATE_PERFORMING);
2007
0
  }
2008
123k
  return CURLE_OK;
2009
123k
}
2010
2011
static CURLMcode multistate_performing(struct Curl_easy *data,
2012
                                       bool *stream_errorp,
2013
                                       CURLcode *resultp)
2014
80.6k
{
2015
80.6k
  char *newurl = NULL;
2016
80.6k
  bool retry = FALSE;
2017
80.6k
  CURLMcode mresult = CURLM_OK;
2018
80.6k
  CURLcode result = *resultp = CURLE_OK;
2019
80.6k
  *stream_errorp = FALSE;
2020
2021
80.6k
  if(mspeed_check(data) == CURLE_AGAIN)
2022
0
    return CURLM_OK;
2023
2024
  /* read/write data if it is ready to do so */
2025
80.6k
  result = Curl_sendrecv(data);
2026
2027
80.6k
  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
32.5k
    CURLcode ret = Curl_retry_request(data, &newurl);
2033
32.5k
    if(!ret)
2034
32.5k
      retry = !!newurl;
2035
0
    else if(!result)
2036
0
      result = ret;
2037
2038
32.5k
    if(retry) {
2039
      /* if we are to retry, set the result to OK and consider the
2040
         request as done */
2041
5.14k
      result = CURLE_OK;
2042
5.14k
      data->req.done = TRUE;
2043
5.14k
    }
2044
32.5k
  }
2045
48.0k
#ifndef CURL_DISABLE_HTTP
2046
48.0k
  else if((result == CURLE_HTTP2_STREAM) &&
2047
133
          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
80.6k
#endif
2075
2076
80.6k
  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
5.08k
    if(!(data->conn->scheme->flags & PROTOPT_DUAL) &&
2086
5.08k
       result != CURLE_HTTP2_STREAM)
2087
4.94k
      streamclose(data->conn);
2088
2089
5.08k
    multi_posttransfer(data);
2090
5.08k
    multi_done(data, result, TRUE);
2091
5.08k
  }
2092
75.5k
  else if(data->req.done && !Curl_cwriter_is_paused(data)) {
2093
32.5k
    const struct Curl_scheme *handler = data->conn->scheme;
2094
2095
    /* call this even if the readwrite function returned error */
2096
32.5k
    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
32.5k
    if(data->req.newurl || retry) {
2101
22.4k
      followtype follow = FOLLOW_NONE;
2102
22.4k
      if(!retry) {
2103
        /* if the URL is a follow-location and not a retried request then
2104
           figure out the URL here */
2105
17.2k
        curlx_free(newurl);
2106
17.2k
        newurl = data->req.newurl;
2107
17.2k
        data->req.newurl = NULL;
2108
17.2k
        follow = FOLLOW_REDIR;
2109
17.2k
      }
2110
5.14k
      else
2111
5.14k
        follow = FOLLOW_RETRY;
2112
22.4k
      (void)multi_done(data, CURLE_OK, FALSE);
2113
      /* multi_done() might return CURLE_GOT_NOTHING */
2114
22.4k
      result = multi_follow(data, handler, newurl, follow);
2115
22.4k
      if(!result) {
2116
22.2k
        multistate(data, MSTATE_SETUP);
2117
22.2k
        mresult = CURLM_CALL_MULTI_PERFORM;
2118
22.2k
      }
2119
22.4k
    }
2120
10.1k
    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
10.1k
      if(data->req.location) {
2126
319
        curlx_free(newurl);
2127
319
        newurl = data->req.location;
2128
319
        data->req.location = NULL;
2129
319
        result = multi_follow(data, handler, newurl, FOLLOW_FAKE);
2130
319
        if(result) {
2131
0
          *stream_errorp = TRUE;
2132
0
          result = multi_done(data, result, TRUE);
2133
0
        }
2134
319
      }
2135
2136
10.1k
      if(!result) {
2137
10.1k
        multistate(data, MSTATE_DONE);
2138
10.1k
        mresult = CURLM_CALL_MULTI_PERFORM;
2139
10.1k
      }
2140
10.1k
    }
2141
32.5k
  }
2142
43.0k
  else { /* not errored, not done */
2143
43.0k
    mspeed_check(data);
2144
43.0k
  }
2145
80.6k
  curlx_free(newurl);
2146
80.6k
  *resultp = result;
2147
80.6k
  return mresult;
2148
80.6k
}
2149
2150
static CURLMcode multistate_do(struct Curl_easy *data,
2151
                               bool *stream_errorp,
2152
                               CURLcode *resultp)
2153
38.1k
{
2154
38.1k
  CURLMcode mresult = CURLM_OK;
2155
38.1k
  CURLcode result = CURLE_OK;
2156
38.1k
  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
38.1k
  if(data->set.connect_only && !data->set.connect_only_ws) {
2180
8
    multistate(data, MSTATE_DONE);
2181
8
    mresult = CURLM_CALL_MULTI_PERFORM;
2182
8
  }
2183
38.1k
  else {
2184
38.1k
    bool dophase_done = FALSE;
2185
    /* Perform the protocol's DO action */
2186
38.1k
    result = multi_do(data, &dophase_done);
2187
2188
38.1k
    if(!result) {
2189
37.7k
      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
37.7k
      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
37.7k
      else {
2219
        /* we are done with the DO, now DID */
2220
37.7k
        multistate(data, MSTATE_DID);
2221
37.7k
        mresult = CURLM_CALL_MULTI_PERFORM;
2222
37.7k
      }
2223
37.7k
    }
2224
327
    else if((result == CURLE_SEND_ERROR) &&
2225
6
            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
327
    else {
2274
      /* failure detected */
2275
327
      multi_posttransfer(data);
2276
327
      if(data->conn)
2277
327
        multi_done(data, result, FALSE);
2278
327
      *stream_errorp = TRUE;
2279
327
    }
2280
38.1k
  }
2281
38.1k
end:
2282
38.1k
  *resultp = result;
2283
38.1k
  return mresult;
2284
38.1k
}
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
39.9k
{
2315
  /* Connect. We want to get a connection identifier filled in. This state can
2316
     be entered from SETUP and from PENDING. */
2317
39.9k
  bool connected;
2318
39.9k
  CURLMcode mresult = CURLM_OK;
2319
39.9k
  CURLcode result = Curl_connect(data, &connected);
2320
39.9k
  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
39.9k
  else
2332
39.9k
    multi_schedule_pending(data->multi);
2333
2334
39.9k
  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
39.9k
    mresult = CURLM_CALL_MULTI_PERFORM;
2339
2340
39.9k
    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
39.9k
    else {
2349
39.9k
      multistate(data, MSTATE_CONNECTING);
2350
39.9k
    }
2351
39.9k
  }
2352
39.9k
  *resultp = result;
2353
39.9k
  return mresult;
2354
39.9k
}
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
366k
{
2363
366k
  if(data->mstate < MSTATE_COMPLETED) {
2364
355k
    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
7.51k
      multi_schedule_pending(multi); /* connection */
2375
2376
7.51k
      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
7.51k
      else if(data->mstate == MSTATE_CONNECT) {
2390
        /* Curl_connect() failed */
2391
83
        multi_posttransfer(data);
2392
83
        Curl_pgrsUpdate_nometer(data);
2393
83
      }
2394
2395
7.51k
      multistate(data, MSTATE_COMPLETED);
2396
7.51k
      return result;
2397
7.51k
    }
2398
    /* if there is still a connection to use, call the progress function */
2399
348k
    else if(data->conn && Curl_conn_is_connected(data->conn, FIRSTSOCKET)) {
2400
220k
      result = Curl_pgrsUpdateX(data, pnow);
2401
220k
      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
220k
    }
2412
355k
  }
2413
358k
  return result;
2414
366k
}
2415
2416
static void handle_completed(struct Curl_multi *multi,
2417
                             struct Curl_easy *data,
2418
                             CURLcode result)
2419
17.6k
{
2420
17.6k
  bool msg_to_app = data->master_mid == UINT32_MAX;
2421
2422
17.6k
  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
17.6k
  else {
2436
    /* now fill in the CURLMsg with this info */
2437
17.6k
    struct CURLMsg *msg = &data->msg;
2438
2439
17.6k
    msg->msg = CURLMSG_DONE;
2440
17.6k
    msg->easy_handle = data;
2441
17.6k
    msg->data.result = result;
2442
2443
17.6k
    DEBUGASSERT(!data->conn);
2444
17.6k
  }
2445
17.6k
  multistate(data, MSTATE_MSGSENT);
2446
2447
  /* remove from the other sets */
2448
17.6k
  Curl_uint32_bset_remove(&multi->process, data->mid);
2449
17.6k
  Curl_uint32_bset_remove(&multi->dirty, data->mid);
2450
17.6k
  Curl_uint32_bset_remove(&multi->pending, data->mid);
2451
17.6k
  if(msg_to_app)
2452
17.6k
    multi_addmsg(multi, data);
2453
17.6k
  if(data->state.really_alive) {
2454
17.6k
    data->state.really_alive = FALSE;
2455
17.6k
    --multi->xfers_really_alive;
2456
17.6k
    if(!multi->xfers_really_alive)
2457
17.6k
      (void)multi_assess_wakeup(multi);
2458
17.6k
  }
2459
17.6k
  --multi->xfers_alive;
2460
17.6k
  if(!multi->xfers_alive)
2461
17.6k
    multi_assess_wakeup(multi);
2462
17.6k
}
2463
2464
static CURLMcode multistate_init(struct Curl_easy *data, CURLcode *result)
2465
17.8k
{
2466
17.8k
  if(!data->state.really_alive) {
2467
17.8k
    data->state.really_alive = TRUE;
2468
17.8k
    ++data->multi->xfers_really_alive;
2469
17.8k
    if(data->multi->xfers_really_alive == 1) {
2470
17.8k
      CURLMcode mresult = multi_assess_wakeup(data->multi);
2471
17.8k
      if(mresult) {
2472
0
        failf(data, "error enabling wakeup listening: %d", mresult);
2473
0
        return mresult;
2474
0
      }
2475
17.8k
    }
2476
17.8k
  }
2477
2478
17.8k
  *result = Curl_pretransfer(data);
2479
17.8k
  if(*result)
2480
72
    return CURLM_OK;
2481
2482
  /* after init, go SETUP */
2483
17.7k
  multistate(data, MSTATE_SETUP);
2484
17.7k
  Curl_pgrsTime(data, TIMER_STARTOP);
2485
17.7k
  return CURLM_CALL_MULTI_PERFORM;
2486
17.8k
}
2487
2488
static CURLMcode multistate_setup(struct Curl_easy *data)
2489
39.9k
{
2490
39.9k
  const struct curltime *pnow = Curl_pgrs_now(data);
2491
39.9k
  Curl_pgrsTimeWas(data, TIMER_STARTSINGLE, *pnow);
2492
39.9k
  if(data->set.timeout)
2493
39.9k
    Curl_expire_set(data, EXPIRE_TIMEOUT, data->set.timeout, pnow);
2494
39.9k
  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
39.9k
    Curl_expire_set(data, EXPIRE_CONNECTTIMEOUT,
2499
39.9k
                    data->set.connecttimeout, pnow);
2500
2501
39.9k
  multistate(data, MSTATE_CONNECT);
2502
39.9k
  return CURLM_CALL_MULTI_PERFORM;
2503
39.9k
}
2504
2505
static CURLMcode multistate_connecting(struct Curl_easy *data,
2506
                                       bool *stream_error,
2507
                                       CURLcode *result)
2508
63.3k
{
2509
63.3k
  bool connected;
2510
2511
63.3k
  if(!data->conn) {
2512
0
    DEBUGASSERT(0);
2513
0
    *result = CURLE_FAILED_INIT;
2514
0
    return CURLM_OK;
2515
0
  }
2516
63.3k
  if(!Curl_xfer_recv_is_paused(data)) {
2517
63.3k
    *result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
2518
63.3k
    if(connected && !*result) {
2519
38.1k
      if(!data->conn->bits.reuse &&
2520
23.0k
         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
38.1k
      multistate(data, MSTATE_PROTOCONNECT);
2525
38.1k
      return CURLM_CALL_MULTI_PERFORM;
2526
38.1k
    }
2527
25.2k
    else if(*result) {
2528
      /* failure detected */
2529
1.79k
      CURL_TRC_M(data, "connect failed -> %d", (int)*result);
2530
1.79k
      multi_posttransfer(data);
2531
1.79k
      multi_done(data, *result, TRUE);
2532
1.79k
      *stream_error = TRUE;
2533
1.79k
      return CURLM_OK;
2534
1.79k
    }
2535
63.3k
  }
2536
23.4k
  return CURLM_OK;
2537
63.3k
}
2538
2539
static CURLMcode multistate_protoconnect(struct Curl_easy *data,
2540
                                         bool *stream_error,
2541
                                         CURLcode *result)
2542
38.1k
{
2543
38.1k
  bool protocol_connected = FALSE;
2544
2545
38.1k
  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
15.0k
    multistate(data, MSTATE_DO);
2551
15.0k
    return CURLM_CALL_MULTI_PERFORM;
2552
15.0k
  }
2553
23.0k
  if(!*result)
2554
23.0k
    *result = protocol_connect(data, &protocol_connected);
2555
23.0k
  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
23.0k
  else if(!*result) {
2561
    /* protocol connect has completed, go WAITDO or DO */
2562
23.0k
    multistate(data, MSTATE_DO);
2563
23.0k
    return CURLM_CALL_MULTI_PERFORM;
2564
23.0k
  }
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
23.0k
}
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
37.7k
{
2655
37.7k
  DEBUGASSERT(data->conn);
2656
37.7k
  if(data->conn->bits.multiplex)
2657
    /* Check if we can move pending requests to send pipe */
2658
2.15k
    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
37.7k
  if(CONN_SOCK_IDX_VALID(data->conn->recv_idx) ||
2663
37.7k
     CONN_SOCK_IDX_VALID(data->conn->send_idx)) {
2664
37.7k
    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
37.7k
    return ((multi->xfers_alive > 1) &&
2670
0
            (data->conn->scheme->protocol & PROTO_FAMILY_HTTP)) ?
2671
37.7k
           CURLM_OK : CURLM_CALL_MULTI_PERFORM;
2672
37.7k
  }
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
37.7k
}
2684
2685
static CURLMcode multistate_done(struct Curl_easy *data, CURLcode *presult)
2686
10.1k
{
2687
10.1k
  if(data->conn) {
2688
10.1k
    CURLcode result;
2689
2690
    /* post-transfer command */
2691
10.1k
    result = multi_done(data, *presult, FALSE);
2692
2693
    /* allow a previously set error code take precedence */
2694
10.1k
    if(!(*presult))
2695
10.1k
      *presult = result;
2696
10.1k
  }
2697
2698
10.1k
#ifndef CURL_DISABLE_FTP
2699
10.1k
  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
10.1k
#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
10.1k
  multistate(data, MSTATE_COMPLETED);
2711
10.1k
  return CURLM_CALL_MULTI_PERFORM;
2712
10.1k
}
2713
2714
static CURLMcode multi_runsingle(struct Curl_multi *multi,
2715
                                 struct Curl_easy *data,
2716
                                 struct Curl_sigpipe_ctx *sigpipe_ctx)
2717
166k
{
2718
166k
  CURLMcode mresult = CURLM_OK;
2719
166k
  CURLcode result = CURLE_OK;
2720
166k
  const struct curltime *pnow = NULL;
2721
2722
166k
  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
166k
  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
166k
  Curl_uint32_bset_remove(&multi->dirty, data->mid);
2736
2737
166k
  if(data == multi->admin) {
2738
83.2k
#ifdef ENABLE_INTERNAL_WAKEUP
2739
    /* Consume any pending wakeup signals before processing.
2740
     * This is necessary for event based processing. See #21547 */
2741
83.2k
    (void)Curl_wakeup_consume(multi->wakeup_internal, TRUE);
2742
83.2k
#endif
2743
83.2k
#ifdef USE_RESOLV_THREADED
2744
83.2k
    Curl_async_thrdd_multi_process(multi);
2745
83.2k
#endif
2746
83.2k
    Curl_cshutdn_perform(&multi->cshutdn, sigpipe_ctx);
2747
83.2k
    goto out;
2748
83.2k
  }
2749
2750
83.2k
  sigpipe_apply(data, sigpipe_ctx);
2751
366k
  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
366k
    bool stream_error = FALSE;
2755
366k
    mresult = CURLM_OK;
2756
366k
    pnow = NULL;
2757
2758
366k
    if(multi_ischanged(multi, TRUE)) {
2759
9.75k
      CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
2760
9.75k
      multi_schedule_pending(multi); /* multiplexed */
2761
9.75k
    }
2762
2763
366k
    if(data->mstate > MSTATE_CONNECT &&
2764
268k
       data->mstate < MSTATE_COMPLETED) {
2765
      /* Make sure we set the connection's current owner */
2766
268k
      DEBUGASSERT(data->conn);
2767
268k
      if(!data->conn) {
2768
0
        mresult = CURLM_INTERNAL_ERROR;
2769
0
        goto out;
2770
0
      }
2771
268k
    }
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
366k
    if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED)) {
2776
308k
      pnow = Curl_pgrs_now(data);
2777
308k
      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
308k
      pnow = NULL;
2781
308k
    }
2782
2783
366k
    switch(data->mstate) {
2784
17.8k
    case MSTATE_INIT:
2785
      /* Transitional state. init this transfer. A handle never comes back to
2786
         this state. */
2787
17.8k
      mresult = multistate_init(data, &result);
2788
17.8k
      break;
2789
2790
39.9k
    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
39.9k
      mresult = multistate_setup(data);
2794
39.9k
      break;
2795
2796
39.9k
    case MSTATE_CONNECT:
2797
39.9k
      mresult = multistate_connect(multi, data, &result);
2798
39.9k
      break;
2799
2800
63.3k
    case MSTATE_CONNECTING:
2801
      /* awaiting a completion of an asynch TCP connect */
2802
63.3k
      mresult = multistate_connecting(data, &stream_error, &result);
2803
63.3k
      break;
2804
2805
38.1k
    case MSTATE_PROTOCONNECT:
2806
38.1k
      mresult = multistate_protoconnect(data, &stream_error, &result);
2807
38.1k
      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
38.1k
    case MSTATE_DO:
2815
38.1k
      mresult = multistate_do(data, &stream_error, &result);
2816
38.1k
      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
37.7k
    case MSTATE_DID:
2831
37.7k
      mresult = multistate_did(multi, data);
2832
37.7k
      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
80.6k
    case MSTATE_PERFORMING:
2839
80.6k
      mresult = multistate_performing(data, &stream_error, &result);
2840
80.6k
      break;
2841
2842
10.1k
    case MSTATE_DONE:
2843
10.1k
      mresult = multistate_done(data, &result);
2844
10.1k
      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
366k
    }
2858
2859
366k
    if(data->mstate >= MSTATE_CONNECT &&
2860
325k
       data->mstate < MSTATE_DO &&
2861
143k
       mresult != CURLM_CALL_MULTI_PERFORM &&
2862
25.3k
       !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
23.5k
      pnow = Curl_pgrs_now(data);
2870
23.5k
      multi_handle_timeout(data, pnow, &stream_error, &result);
2871
23.5k
    }
2872
2873
366k
statemachine_end:
2874
366k
    if(!pnow)
2875
342k
      pnow = Curl_pgrs_now(data);
2876
366k
    result = is_finished(multi, data, pnow, stream_error, result);
2877
366k
    if(result)
2878
15.7k
      mresult = CURLM_CALL_MULTI_PERFORM;
2879
2880
366k
    if(MSTATE_COMPLETED == data->mstate) {
2881
17.6k
      handle_completed(multi, data, result);
2882
17.6k
      mresult = CURLM_OK;
2883
17.6k
      goto out;
2884
17.6k
    }
2885
366k
  } while((mresult == CURLM_CALL_MULTI_PERFORM) ||
2886
66.4k
          multi_ischanged(multi, FALSE));
2887
2888
166k
out:
2889
166k
  data->result = result;
2890
166k
  return mresult;
2891
83.2k
}
2892
2893
static CURLMcode multi_perform(struct Curl_multi *multi,
2894
                               int *running_handles)
2895
83.2k
{
2896
83.2k
  CURLMcode returncode = CURLM_OK;
2897
83.2k
  struct curltime start = *multi_now(multi);
2898
83.2k
  uint32_t mid;
2899
83.2k
  struct Curl_sigpipe_ctx sigpipe_ctx;
2900
2901
83.2k
  sigpipe_init(&sigpipe_ctx);
2902
2903
83.2k
  if(Curl_uint32_bset_first(&multi->process, &mid)) {
2904
83.2k
    CURL_TRC_M(multi->admin, "multi_perform(running=%u)",
2905
83.2k
               Curl_multi_xfers_running(multi));
2906
166k
    do {
2907
166k
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
2908
166k
      CURLMcode mresult;
2909
166k
      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
166k
      mresult = multi_runsingle(multi, data, &sigpipe_ctx);
2916
166k
      if(mresult)
2917
0
        returncode = mresult;
2918
166k
    } while(Curl_uint32_bset_next(&multi->process, mid, &mid));
2919
83.2k
  }
2920
83.2k
  sigpipe_restore(&sigpipe_ctx);
2921
2922
83.2k
  if(multi_ischanged(multi, TRUE))
2923
16.7k
    multi_schedule_pending(multi);
2924
2925
83.2k
  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
83.3k
  while(Curl_timeouts_remove_expired(&multi->timeouts, &start, &mid)) {
2939
    /* the removed may have another timeout in queue */
2940
18
    struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
2941
18
    if(!data) {
2942
0
      DEBUGASSERT(0);
2943
0
      continue;
2944
0
    }
2945
18
    (void)add_next_timeout(&start, multi, data);
2946
18
    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
18
  }
2956
2957
83.2k
  if(running_handles) {
2958
83.2k
    uint32_t running = Curl_multi_xfers_running(multi);
2959
83.2k
    *running_handles = (running < INT_MAX) ? (int)running : INT_MAX;
2960
83.2k
  }
2961
2962
83.2k
  if(CURLM_OK >= returncode)
2963
83.2k
    returncode = Curl_update_timer(multi);
2964
2965
83.2k
  return returncode;
2966
83.2k
}
2967
2968
CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
2969
83.2k
{
2970
83.2k
  struct Curl_mapi_guard guard;
2971
83.2k
  CURLMcode mresult;
2972
2973
83.2k
  if(CURL_MAPI_ENTER(&guard, m, multi_perform, &mresult)) {
2974
83.2k
    mresult = multi_perform(m, running_handles);
2975
83.2k
  }
2976
83.2k
  CURL_MAPI_LEAVE(&guard);
2977
83.2k
  return mresult;
2978
83.2k
}
2979
2980
CURLMcode curl_multi_cleanup(CURLM *m)
2981
17.8k
{
2982
17.8k
  struct Curl_mapi_guard guard;
2983
17.8k
  CURLMcode mresult;
2984
2985
17.8k
  if(CURL_MAPI_ENTER(&guard, m, multi_cleanup, &mresult)) {
2986
17.8k
    struct Curl_multi *multi = m;
2987
17.8k
    void *entry;
2988
17.8k
    uint32_t mid;
2989
2990
    /* First remove all remaining easy handles,
2991
     * close internal ones. admin handle is special */
2992
17.8k
    if(Curl_uint32_tbl_first(&multi->xfers, &mid, &entry)) {
2993
17.8k
      do {
2994
17.8k
        struct Curl_easy *data = entry;
2995
17.8k
        if(!GOOD_EASY_HANDLE(data)) {
2996
0
          mresult = CURLM_BAD_HANDLE;
2997
0
          goto out;
2998
0
        }
2999
3000
17.8k
#ifdef DEBUGBUILD
3001
17.8k
        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
17.8k
#endif
3007
3008
17.8k
        if(data == multi->admin)
3009
17.8k
          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
17.8k
      } while(Curl_uint32_tbl_next(&multi->xfers, mid, &mid, &entry));
3026
17.8k
    }
3027
3028
17.8k
#ifdef USE_RESOLV_THREADED
3029
17.8k
    Curl_async_thrdd_multi_destroy(multi, !multi->quick_exit);
3030
17.8k
#endif
3031
17.8k
    Curl_cpool_destroy(&multi->cpool, multi->admin);
3032
17.8k
    Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
3033
17.8k
    if(multi->admin) {
3034
17.8k
      CURL_TRC_M(multi->admin, "multi_cleanup, closing admin handle, done");
3035
17.8k
      multi->admin->multi = NULL;
3036
17.8k
      Curl_uint32_tbl_remove(&multi->xfers, multi->admin->mid);
3037
17.8k
      Curl_close(&multi->admin);
3038
17.8k
    }
3039
3040
17.8k
    multi->magic = 0; /* not good anymore */
3041
3042
17.8k
    Curl_multi_ev_cleanup(multi);
3043
17.8k
    Curl_hash_destroy(&multi->proto_hash);
3044
17.8k
    Curl_dnscache_destroy(&multi->dnscache);
3045
17.8k
    Curl_psl_destroy(&multi->psl);
3046
17.8k
#ifdef USE_SSL
3047
17.8k
    Curl_ssl_scache_destroy(multi->ssl_scache);
3048
17.8k
#endif
3049
3050
#ifdef USE_WINSOCK
3051
    WSACloseEvent(multi->wsa_event);
3052
#endif
3053
17.8k
#ifdef ENABLE_WAKEUP
3054
17.8k
  Curl_wakeup_destroy(multi->wakeup_pair);
3055
17.8k
#endif
3056
17.8k
#ifdef ENABLE_INTERNAL_WAKEUP
3057
17.8k
  Curl_wakeup_destroy(multi->wakeup_internal);
3058
17.8k
#endif
3059
3060
17.8k
    multi_xfer_bufs_free(multi);
3061
17.8k
    Curl_mntfy_cleanup(multi);
3062
17.8k
#ifdef DEBUGBUILD
3063
17.8k
    if(Curl_uint32_tbl_count(&multi->xfers)) {
3064
0
      multi_xfer_tbl_dump(multi);
3065
0
      DEBUGASSERT(0);
3066
0
    }
3067
17.8k
#endif
3068
17.8k
    Curl_uint32_bset_destroy(&multi->process);
3069
17.8k
    Curl_uint32_bset_destroy(&multi->dirty);
3070
17.8k
    Curl_uint32_bset_destroy(&multi->pending);
3071
17.8k
    Curl_uint32_bset_destroy(&multi->msgsent);
3072
17.8k
    Curl_uint32_tbl_destroy(&multi->xfers);
3073
17.8k
    curlx_memzero(multi, sizeof(*multi));
3074
17.8k
    curlx_free(multi);
3075
3076
17.8k
    mresult = CURLM_OK;
3077
17.8k
  }
3078
17.8k
out:
3079
17.8k
  CURL_MAPI_LEAVE(&guard);
3080
17.8k
  return mresult;
3081
17.8k
}
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
35.4k
{
3092
35.4k
  struct Curl_mapi_guard guard;
3093
35.4k
  CURLMsg *msg_result = NULL;
3094
3095
35.4k
  *msgs_in_queue = 0; /* default to none */
3096
35.4k
  if(CURL_MAPI_ENTER(&guard, m, multi_info_read, NULL)) {
3097
35.4k
    struct Curl_multi *multi = m;
3098
35.4k
    uint32_t mid;
3099
35.4k
    if(Curl_uint32_bset_first(&multi->msgsent, &mid)) {
3100
17.6k
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3101
3102
17.6k
      DEBUGASSERT(data);
3103
17.6k
      Curl_uint32_bset_remove(&multi->msgsent, mid);
3104
17.6k
      *msgs_in_queue =
3105
17.6k
        curlx_uztosi(Curl_uint32_bset_count(&multi->msgsent));
3106
17.6k
      if(data)
3107
17.6k
        msg_result = &data->msg;
3108
17.6k
    }
3109
35.4k
  }
3110
35.4k
  CURL_MAPI_LEAVE(&guard);
3111
35.4k
  return msg_result;
3112
35.4k
}
3113
3114
void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s)
3115
23.5k
{
3116
23.5k
  if(data) {
3117
23.5k
    struct Curl_multi *multi = data->multi;
3118
23.5k
    if(multi) {
3119
23.5k
      CURL_TRC_M(data, "Curl_multi_will_close fd=%" FMT_SOCKET_T, s);
3120
23.5k
      Curl_multi_ev_socket_done(multi, data, s);
3121
23.5k
    }
3122
23.5k
  }
3123
23.5k
}
3124
3125
static void multi_timeouts_init(struct Curl_easy *data)
3126
53.3k
{
3127
53.3k
  data->state.timeouts.first = EXPIRE_LAST;
3128
53.3k
  data->state.timeouts.splaynode.registered = FALSE;
3129
53.3k
}
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
18
{
3145
18
  struct expire_timers *timeouts = &data->state.timeouts;
3146
18
  timediff_t now_us = Curl_timeouts_offset_us(&multi->timeouts, pnow);
3147
3148
36
  while(timeouts->first < EXPIRE_LAST) {
3149
36
    if(timeouts->offset_us[timeouts->first] <= now_us)  /* already expired */
3150
18
      timeouts->first = timeouts->next[timeouts->first];
3151
18
    else /* timeouts are sorted, first is first in the future now */
3152
18
      break;
3153
36
  }
3154
3155
18
  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
18
    Curl_timeouts_add(&multi->timeouts, data,
3159
18
                      timeouts->offset_us[timeouts->first]);
3160
18
  }
3161
18
  return CURLM_OK;
3162
18
}
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
118k
{
3569
118k
  timediff_t timeouts_offset_us = 0;
3570
118k
  int timeout_ms;
3571
118k
  int rc;
3572
118k
  bool set_value = FALSE;
3573
3574
118k
  if(!multi->timer_cb || multi->dead)
3575
118k
    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
192k
{
3624
192k
  struct expire_timers *timeouts = &data->state.timeouts;
3625
192k
  uint8_t id;
3626
192k
  int i = 0;
3627
460k
  for(id = timeouts->first; id < EXPIRE_LAST; id = timeouts->next[id]) {
3628
267k
    if(++i >= EXPIRE_LAST) {
3629
0
      failf(data, "expire timeouts looped: %d iterations and no end", i);
3630
0
      return FALSE;
3631
0
    }
3632
267k
    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
267k
    if((timeouts->next[id] < EXPIRE_LAST) &&
3637
94.4k
       (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
267k
  }
3643
192k
  return TRUE;
3644
192k
}
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
108k
{
3652
108k
  struct expire_timers *timeouts = &data->state.timeouts;
3653
108k
  uint8_t orig_first = timeouts->first;
3654
108k
  uint8_t *anchor = &timeouts->first;
3655
108k
  uint8_t id = (uint8_t)eid;
3656
3657
108k
  if((unsigned)eid >= EXPIRE_LAST) {
3658
0
    DEBUGASSERT(0);
3659
0
    return;
3660
0
  }
3661
3662
179k
  while(*anchor < EXPIRE_LAST) {
3663
118k
    if(*anchor == id) {
3664
47.7k
      *anchor = timeouts->next[id];
3665
47.7k
      break;
3666
47.7k
    }
3667
70.7k
    anchor = &timeouts->next[*anchor];
3668
70.7k
  }
3669
108k
  DEBUGASSERT(multi_timeouts_check(data));
3670
108k
  if(Curl_timeouts_has(data)) {
3671
90.6k
    struct Curl_multi *multi = data->multi;
3672
3673
90.6k
    if(!multi) {
3674
0
      DEBUGASSERT(0);
3675
0
      return;
3676
0
    }
3677
90.6k
    if((timeouts->first >= EXPIRE_LAST) || /* no more timeouts */
3678
88.6k
       (timeouts->first != orig_first)) {  /* active timeout changed */
3679
46.5k
      Curl_timeouts_remove(&multi->timeouts, data);
3680
46.5k
    }
3681
90.6k
    if((timeouts->first < EXPIRE_LAST) && !Curl_timeouts_has(data)) {
3682
44.4k
      Curl_timeouts_add(&multi->timeouts, data,
3683
44.4k
                        timeouts->offset_us[timeouts->first]);
3684
44.4k
    }
3685
90.6k
  }
3686
108k
}
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
84.0k
{
3696
84.0k
  struct expire_timers *timeouts = &data->state.timeouts;
3697
84.0k
  uint8_t *anchor = &timeouts->first;
3698
84.0k
  uint8_t id = (uint8_t)eid;
3699
3700
84.0k
  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
84.0k
  multi_clear_timeout(data, eid);
3706
84.0k
  timeouts->offset_us[id] =
3707
84.0k
    Curl_timeouts_offset_us(&data->multi->timeouts, stamp);
3708
3709
149k
  while(*anchor < EXPIRE_LAST) {
3710
66.3k
    if(timeouts->offset_us[*anchor] > timeouts->offset_us[id])
3711
1.29k
      break;
3712
65.0k
    anchor = &timeouts->next[*anchor];
3713
65.0k
  }
3714
84.0k
  timeouts->next[eid] = *anchor;
3715
84.0k
  timeouts->next[eid] = *anchor;
3716
84.0k
  *anchor = id;
3717
84.0k
  DEBUGASSERT(multi_timeouts_check(data));
3718
84.0k
  CURL_TRC_TIMER(data, eid, "set for %" FMT_TIMEDIFF_T "us",
3719
84.0k
                 curlx_ptimediff_us(stamp, Curl_pgrs_now(data)));
3720
84.0k
  return CURLM_OK;
3721
84.0k
}
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
84.0k
{
3736
84.0k
  struct Curl_multi *multi = data->multi;
3737
84.0k
  struct expire_timers *timeouts = &data->state.timeouts;
3738
84.0k
  uint8_t prev_id = timeouts->first;
3739
84.0k
  struct curltime set;
3740
3741
  /* this is only interesting while there is still an associated multi struct
3742
     remaining! */
3743
84.0k
  if(!multi)
3744
0
    return;
3745
84.0k
  DEBUGASSERT(eid < EXPIRE_LAST);
3746
84.0k
  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
84.0k
  set = *pnow;
3752
84.0k
  set.tv_sec += (time_t)(ms / 1000); /* may be a 64 to 32-bit conversion */
3753
84.0k
  set.tv_usec += (int)(ms % 1000) * 1000;
3754
84.0k
  if(set.tv_usec >= 1000000) {
3755
17.9k
    set.tv_sec++;
3756
17.9k
    set.tv_usec -= 1000000;
3757
17.9k
  }
3758
3759
  /* Add the timeout, will replace any previous value for this timer. */
3760
84.0k
  multi_set_timeout(data, &set, eid);
3761
84.0k
  DEBUGASSERT(timeouts->first < EXPIRE_LAST);
3762
3763
84.0k
  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
63.7k
    if((prev_id != eid) && (prev_id == timeouts->first))
3769
19.1k
      return;
3770
3771
    /* Since this is an updated time, we must remove data from
3772
     * timeouts and then add it again. */
3773
44.5k
    Curl_timeouts_remove(&multi->timeouts, data);
3774
44.5k
  }
3775
3776
  /* Insert the new timer expiry since it is our local minimum. */
3777
64.8k
  Curl_timeouts_add(&multi->timeouts, data,
3778
64.8k
                    timeouts->offset_us[timeouts->first]);
3779
64.8k
}
3780
3781
void Curl_expire(struct Curl_easy *data,
3782
                 timediff_t milli, expire_id eid)
3783
2.55k
{
3784
2.55k
  Curl_expire_set(data, eid, milli, Curl_pgrs_now(data));
3785
2.55k
}
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
24.9k
{
3792
  /* remove the timer, if there */
3793
24.9k
  multi_clear_timeout(data, eid);
3794
24.9k
  CURL_TRC_TIMER(data, eid, "cleared");
3795
24.9k
}
3796
3797
/*
3798
 * Clear ALL timeout values for this handle.
3799
 */
3800
void Curl_expire_clear_all(struct Curl_easy *data)
3801
71.0k
{
3802
71.0k
  struct Curl_multi *multi = data->multi;
3803
3804
  /* this is only interesting while there is still an associated multi struct
3805
     remaining! */
3806
71.0k
  if(!multi)
3807
35.6k
    return;
3808
3809
35.4k
  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
17.7k
    multi_timeouts_init(data);
3813
3814
17.7k
    if(data->id >= 0)
3815
17.7k
      CURL_TRC_M(data, "[TIMEOUT] all cleared");
3816
17.7k
  }
3817
35.4k
}
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
133k
{
3860
133k
  uint32_t mid = multi->last_pending_mid;
3861
3862
133k
  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
133k
  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
133k
}
3893
3894
uint32_t Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
3895
4.40k
{
3896
4.40k
  DEBUGASSERT(multi);
3897
4.40k
  return multi->max_concurrent_streams;
3898
4.40k
}
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
16.9k
{
3981
16.9k
  struct Curl_fixed_buf *fbuf;
3982
16.9k
  if((SIZE_MAX - sizeof(*fbuf)) < len)
3983
0
    return NULL; /* too large */
3984
16.9k
  fbuf = curlx_malloc(len + sizeof(*fbuf));
3985
16.9k
  if(fbuf)
3986
16.9k
    fbuf->len = len;
3987
16.9k
  return fbuf;
3988
16.9k
}
3989
3990
CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
3991
                                    char **pbuf, size_t *pbuflen)
3992
80.1k
{
3993
80.1k
  DEBUGASSERT(data);
3994
80.1k
  DEBUGASSERT(data->multi);
3995
80.1k
  *pbuf = NULL;
3996
80.1k
  *pbuflen = 0;
3997
80.1k
  if(!data->multi) {
3998
0
    failf(data, "transfer has no multi handle");
3999
0
    return CURLE_FAILED_INIT;
4000
0
  }
4001
80.1k
  if(!data->set.buffer_size) {
4002
0
    failf(data, "transfer buffer size is 0");
4003
0
    return CURLE_FAILED_INIT;
4004
0
  }
4005
80.1k
  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
80.1k
  if(data->multi->xfer_buf &&
4011
63.2k
     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
80.1k
  if(!data->multi->xfer_buf) {
4017
16.9k
    data->multi->xfer_buf =
4018
16.9k
      fixed_buf_create(curlx_uitouz(data->set.buffer_size));
4019
16.9k
    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
16.9k
  }
4025
4026
80.1k
  data->multi->xfer_buf_borrowed = TRUE;
4027
80.1k
  *pbuf = data->multi->xfer_buf->data;
4028
80.1k
  *pbuflen = data->multi->xfer_buf->len;
4029
80.1k
  return CURLE_OK;
4030
80.1k
}
4031
4032
void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
4033
80.1k
{
4034
80.1k
  (void)buf;
4035
80.1k
  DEBUGASSERT(data);
4036
80.1k
  DEBUGASSERT(data->multi);
4037
80.1k
  DEBUGASSERT(!buf || (data->multi->xfer_buf &&
4038
80.1k
                       data->multi->xfer_buf->data == buf));
4039
80.1k
  data->multi->xfer_buf_borrowed = FALSE;
4040
80.1k
}
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
17.8k
{
4141
17.8k
  DEBUGASSERT(multi);
4142
17.8k
  curlx_safefree(multi->xfer_buf);
4143
17.8k
  multi->xfer_buf_borrowed = FALSE;
4144
17.8k
  curlx_safefree(multi->xfer_ulbuf);
4145
17.8k
  multi->xfer_ulbuf_borrowed = FALSE;
4146
17.8k
  curlx_safefree(multi->xfer_sockbuf);
4147
17.8k
  multi->xfer_sockbuf_borrowed = FALSE;
4148
17.8k
}
4149
4150
struct Curl_easy *Curl_multi_get_easy(struct Curl_multi *multi,
4151
                                      uint32_t mid)
4152
184k
{
4153
184k
  struct Curl_easy *data = Curl_uint32_tbl_get(&multi->xfers, mid);
4154
184k
  if(GOOD_EASY_HANDLE(data))
4155
184k
    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
184k
}
4161
4162
bool Curl_multi_knows_easy(struct Curl_multi *multi, struct Curl_easy *data)
4163
142k
{
4164
142k
  return Curl_uint32_tbl_get(&multi->xfers, data->mid) == data;
4165
142k
}
4166
4167
uint32_t Curl_multi_xfers_running(struct Curl_multi *multi)
4168
83.2k
{
4169
83.2k
  if(!multi) {
4170
0
    DEBUGASSERT(0);
4171
0
    return 0;
4172
0
  }
4173
83.2k
  return multi->xfers_alive;
4174
83.2k
}
4175
4176
uint32_t Curl_multi_xfers_attached(struct Curl_multi *multi)
4177
16.0k
{
4178
16.0k
  if(!multi || !multi->admin) {
4179
0
    DEBUGASSERT(0);
4180
0
    return 0;
4181
0
  }
4182
  /* Discount the admin handle */
4183
16.0k
  return Curl_uint32_tbl_count(&multi->xfers) - 1;
4184
16.0k
}
4185
4186
void Curl_multi_mark_dirty(struct Curl_easy *data)
4187
18.1k
{
4188
18.1k
  if(data->multi && data->mid != UINT32_MAX)
4189
18.1k
    Curl_uint32_bset_add(&data->multi->dirty, data->mid);
4190
18.1k
}
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 */