Coverage Report

Created: 2026-09-14 06:43

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