Coverage Report

Created: 2025-11-11 06:28

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