Coverage Report

Created: 2026-04-12 06:56

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