Coverage Report

Created: 2025-12-14 06:23

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