Coverage Report

Created: 2025-08-29 06:10

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