Coverage Report

Created: 2026-05-30 06:06

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