Coverage Report

Created: 2026-03-12 06:35

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