Coverage Report

Created: 2026-07-14 07:09

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