Coverage Report

Created: 2026-08-13 07:42

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