Coverage Report

Created: 2025-10-30 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/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
0
#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
0
#define CURL_SOCKET_HASH_TABLE_SIZE 911
72
#endif
73
74
#ifndef CURL_CONNECTION_HASH_SIZE
75
0
#define CURL_CONNECTION_HASH_SIZE 97
76
#endif
77
78
#ifndef CURL_DNS_HASH_SIZE
79
0
#define CURL_DNS_HASH_SIZE 71
80
#endif
81
82
#ifndef CURL_TLS_SESSION_SIZE
83
0
#define CURL_TLS_SESSION_SIZE 25
84
#endif
85
86
0
#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
  (((x) && (x)->magic == CURL_MULTI_HANDLE)? TRUE:      \
94
  (DEBUGASSERT(!(x)), FALSE))
95
#else
96
#define GOOD_MULTI_HANDLE(x) \
97
0
  ((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
0
{
120
0
  data->req.chunk = FALSE;
121
0
  Curl_pgrsTime(data, TIMER_PRETRANSFER);
122
0
}
123
124
static void init_completed(struct Curl_easy *data)
125
0
{
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
0
  Curl_detach_connection(data);
131
0
  Curl_expire_clear(data); /* stop all timers */
132
0
}
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
0
{
141
0
  CURLMstate oldstate = data->mstate;
142
0
  static const init_multistate_func finit[MSTATE_LAST] = {
143
0
    NULL,              /* INIT */
144
0
    NULL,              /* PENDING */
145
0
    NULL,              /* SETUP */
146
0
    Curl_init_CONNECT, /* CONNECT */
147
0
    NULL,              /* RESOLVING */
148
0
    NULL,              /* CONNECTING */
149
0
    NULL,              /* TUNNELING */
150
0
    NULL,              /* PROTOCONNECT */
151
0
    NULL,              /* PROTOCONNECTING */
152
0
    NULL,              /* DO */
153
0
    NULL,              /* DOING */
154
0
    NULL,              /* DOING_MORE */
155
0
    before_perform,    /* DID */
156
0
    NULL,              /* PERFORMING */
157
0
    NULL,              /* RATELIMITING */
158
0
    NULL,              /* DONE */
159
0
    init_completed,    /* COMPLETED */
160
    NULL               /* MSGSENT */
161
0
  };
162
163
0
  if(oldstate == state)
164
    /* do not bother when the new state is the same as the old state */
165
0
    return;
166
167
#ifdef DEBUGBUILD
168
  CURL_TRC_M(data, "-> [%s] (line %d)", CURL_MSTATE_NAME(state), lineno);
169
#else
170
0
  CURL_TRC_M(data, "-> [%s]", CURL_MSTATE_NAME(state));
171
0
#endif
172
173
0
  data->mstate = state;
174
0
  switch(state) {
175
0
  case MSTATE_DONE:
176
0
    CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE);
177
0
    break;
178
0
  case MSTATE_COMPLETED:
179
    /* we sometimes directly jump to COMPLETED, trigger also a notification
180
     * in that case. */
181
0
    if(oldstate < MSTATE_DONE)
182
0
      CURLM_NTFY(data, CURLMNOTIFY_EASY_DONE);
183
    /* changing to COMPLETED means it is in process and needs to go */
184
0
    DEBUGASSERT(Curl_uint_bset_contains(&data->multi->process, data->mid));
185
0
    Curl_uint_bset_remove(&data->multi->process, data->mid);
186
0
    Curl_uint_bset_remove(&data->multi->pending, data->mid); /* to be sure */
187
188
0
    if(Curl_uint_bset_empty(&data->multi->process)) {
189
      /* free the transfer buffer when we have no more active transfers */
190
0
      multi_xfer_bufs_free(data->multi);
191
0
    }
192
0
    break;
193
0
  default:
194
0
    break;
195
0
  }
196
197
  /* if this state has an init-function, run it */
198
0
  if(finit[state])
199
0
    finit[state](data);
200
0
}
201
202
#ifndef DEBUGBUILD
203
0
#define multistate(x,y) mstate(x,y)
204
#else
205
#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
0
{
228
0
  if(!Curl_llist_count(&multi->msglist))
229
0
    CURLM_NTFY(multi->admin, CURLMNOTIFY_INFO_READ);
230
0
  Curl_llist_append(&multi->msglist, msg, &msg->list);
231
0
}
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
0
{
239
0
  struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
240
241
0
  if(!multi)
242
0
    return NULL;
243
244
0
  multi->magic = CURL_MULTI_HANDLE;
245
246
0
  Curl_dnscache_init(&multi->dnscache, dnssize);
247
0
  Curl_mntfy_init(multi);
248
0
  Curl_multi_ev_init(multi, ev_hashsize);
249
0
  Curl_uint_tbl_init(&multi->xfers, NULL);
250
0
  Curl_uint_bset_init(&multi->process);
251
0
  Curl_uint_bset_init(&multi->dirty);
252
0
  Curl_uint_bset_init(&multi->pending);
253
0
  Curl_uint_bset_init(&multi->msgsent);
254
0
  Curl_hash_init(&multi->proto_hash, 23,
255
0
                 Curl_hash_str, curlx_str_key_compare, ph_freeentry);
256
0
  Curl_llist_init(&multi->msglist, NULL);
257
258
0
  multi->multiplexing = TRUE;
259
0
  multi->max_concurrent_streams = 100;
260
0
  multi->last_timeout_ms = -1;
261
262
0
  if(Curl_mntfy_resize(multi) ||
263
0
     Curl_uint_bset_resize(&multi->process, xfer_table_size) ||
264
0
     Curl_uint_bset_resize(&multi->pending, xfer_table_size) ||
265
0
     Curl_uint_bset_resize(&multi->dirty, xfer_table_size) ||
266
0
     Curl_uint_bset_resize(&multi->msgsent, xfer_table_size) ||
267
0
     Curl_uint_tbl_resize(&multi->xfers, xfer_table_size))
268
0
    goto error;
269
270
0
  multi->admin = curl_easy_init();
271
0
  if(!multi->admin)
272
0
    goto error;
273
  /* Initialize admin handle to operate inside this multi */
274
0
  multi->admin->multi = multi;
275
0
  multi->admin->state.internal = TRUE;
276
0
  Curl_llist_init(&multi->admin->state.timeoutlist, NULL);
277
#ifdef DEBUGBUILD
278
  if(getenv("CURL_DEBUG"))
279
    multi->admin->set.verbose = TRUE;
280
#endif
281
0
  Curl_uint_tbl_add(&multi->xfers, multi->admin, &multi->admin->mid);
282
283
0
  if(Curl_cshutdn_init(&multi->cshutdn, multi))
284
0
    goto error;
285
286
0
  Curl_cpool_init(&multi->cpool, multi->admin, NULL, chashsize);
287
288
0
#ifdef USE_SSL
289
0
  if(Curl_ssl_scache_create(sesssize, 2, &multi->ssl_scache))
290
0
    goto error;
291
#else
292
  (void)sesssize;
293
#endif
294
295
#ifdef USE_WINSOCK
296
  multi->wsa_event = WSACreateEvent();
297
  if(multi->wsa_event == WSA_INVALID_EVENT)
298
    goto error;
299
#elif defined(ENABLE_WAKEUP)
300
0
  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
0
#endif
305
306
0
  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
0
}
333
334
CURLM *curl_multi_init(void)
335
0
{
336
0
  return Curl_multi_handle(CURL_XFER_TABLE_SIZE,
337
0
                           CURL_SOCKET_HASH_TABLE_SIZE,
338
0
                           CURL_CONNECTION_HASH_SIZE,
339
0
                           CURL_DNS_HASH_SIZE,
340
0
                           CURL_TLS_SESSION_SIZE);
341
0
}
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
{
346
  if(!multi->warned) {
347
    infof(data, "!!! WARNING !!!");
348
    infof(data, "This is a debug build of libcurl, "
349
          "do not use in production.");
350
    multi->warned = TRUE;
351
  }
352
}
353
#else
354
0
#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
0
{
361
0
  unsigned int capacity = Curl_uint_tbl_capacity(&multi->xfers);
362
0
  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
0
  const unsigned int max_capacity = UINT_MAX - 1;
367
368
0
  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
0
    unsigned int used = Curl_uint_tbl_count(&multi->xfers);
375
0
    unsigned int unused = capacity - used;
376
0
    unsigned int min_unused = CURLMAX(capacity >> 2, 4);
377
0
    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
0
  }
392
393
0
  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
0
  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
0
  return CURLM_OK;
415
0
}
416
417
418
CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
419
0
{
420
0
  CURLMcode rc;
421
0
  struct Curl_multi *multi = m;
422
0
  struct Curl_easy *data = d;
423
  /* First, make some basic checks that the CURLM handle is a good handle */
424
0
  if(!GOOD_MULTI_HANDLE(multi))
425
0
    return CURLM_BAD_HANDLE;
426
427
  /* Verify that we got a somewhat good easy handle too */
428
0
  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
0
  if(data->multi)
434
0
    return CURLM_ADDED_ALREADY;
435
436
0
  if(multi->in_callback)
437
0
    return CURLM_RECURSIVE_API_CALL;
438
439
0
  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
0
  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
0
  if(multi_xfers_add(multi, data))
463
0
    return CURLM_OUT_OF_MEMORY;
464
465
  /* Initialize timeout list for this handle */
466
0
  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
0
  if(data->set.errorbuffer)
475
0
    data->set.errorbuffer[0] = 0;
476
477
0
  data->state.os_errno = 0;
478
479
  /* make the Curl_easy refer back to this multi handle - before Curl_expire()
480
     is called. */
481
0
  data->multi = multi;
482
483
  /* set the easy handle */
484
0
  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
0
  Curl_uint_bset_add(&multi->process, data->mid);
496
0
  ++multi->xfers_alive;
497
0
  ++multi->xfers_total_ever;
498
499
0
  Curl_cpool_xfer_init(data);
500
0
  multi_warn_debug(multi, data);
501
502
  /* Make sure the new handle will run */
503
0
  Curl_multi_mark_dirty(data);
504
  /* Necessary in event based processing, where dirty handles trigger
505
   * a timeout callback invocation. */
506
0
  rc = Curl_update_timer(multi);
507
0
  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
0
  multi->admin->set.timeout = data->set.timeout;
519
0
  multi->admin->set.server_response_timeout =
520
0
    data->set.server_response_timeout;
521
0
  multi->admin->set.no_signal = data->set.no_signal;
522
523
0
  CURL_TRC_M(data, "added to multi, mid=%u, running=%u, total=%u",
524
0
             data->mid, Curl_multi_xfers_running(multi),
525
0
             Curl_uint_tbl_count(&multi->xfers));
526
0
  return CURLM_OK;
527
0
}
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
0
{
553
0
  struct multi_done_ctx *mdctx = userdata;
554
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
555
0
  const char *host =
556
0
#ifndef CURL_DISABLE_PROXY
557
0
        conn->bits.socksproxy ?
558
0
        conn->socks_proxy.host.dispname :
559
0
        conn->bits.httpproxy ? conn->http_proxy.host.dispname :
560
0
#endif
561
0
        conn->bits.conn_to_host ? conn->conn_to_host.dispname :
562
0
        conn->host.dispname;
563
0
  int port =
564
0
#ifndef CURL_DISABLE_PROXY
565
0
        conn->bits.httpproxy ? conn->http_proxy.port :
566
0
#endif
567
0
        conn->bits.conn_to_port ? conn->conn_to_port :
568
0
        conn->remote_port;
569
0
#endif
570
571
0
  Curl_detach_connection(data);
572
573
0
  CURL_TRC_M(data, "multi_done_locked, in use=%u",
574
0
             Curl_uint_spbset_count(&conn->xfers_attached));
575
0
  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
0
  data->state.done = TRUE; /* called just now! */
583
0
  data->state.recent_conn_id = conn->connection_id;
584
585
0
  Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
586
0
  Curl_resolv_unlink(data, &data->state.dns[1]);
587
0
  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
0
  if((data->set.reuse_forbid
605
0
#ifdef USE_NTLM
606
0
      && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
607
0
           conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
608
0
#endif
609
#ifdef USE_SPNEGO
610
      && !(conn->http_negotiate_state == GSS_AUTHRECV ||
611
           conn->proxy_negotiate_state == GSS_AUTHRECV)
612
#endif
613
0
     ) || conn->bits.close
614
0
       || (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
615
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
616
0
    CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s:%d, "
617
0
               "forbid=%d, close=%d, premature=%d, conn_multiplex=%d",
618
0
               conn->connection_id, host, port, data->set.reuse_forbid,
619
0
               conn->bits.close, mdctx->premature,
620
0
               Curl_conn_is_multiplex(conn, FIRSTSOCKET));
621
0
#endif
622
0
    connclose(conn, "disconnecting");
623
0
    Curl_conn_terminate(data, conn, mdctx->premature);
624
0
  }
625
0
  else if(!Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) {
626
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
627
0
    CURL_TRC_M(data, "multi_done, conn #%" FMT_OFF_T " to %s:%d was shutdown"
628
0
               " by server, not reusing", conn->connection_id, host, port);
629
0
#endif
630
0
    connclose(conn, "server shutdown");
631
0
    Curl_conn_terminate(data, conn, mdctx->premature);
632
0
  }
633
0
  else {
634
    /* the connection is no longer in use by any transfer */
635
0
    if(Curl_cpool_conn_now_idle(data, conn)) {
636
      /* connection kept in the cpool */
637
0
      data->state.lastconnect_id = conn->connection_id;
638
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
639
0
      infof(data, "Connection #%" FMT_OFF_T " to host %s:%d left intact",
640
0
            conn->connection_id, host, port);
641
0
#endif
642
0
    }
643
0
    else {
644
      /* connection was removed from the cpool and destroyed. */
645
0
      data->state.lastconnect_id = -1;
646
0
    }
647
0
  }
648
0
}
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
0
{
655
0
  CURLcode result;
656
0
  struct connectdata *conn = data->conn;
657
0
  struct multi_done_ctx mdctx;
658
659
0
  memset(&mdctx, 0, sizeof(mdctx));
660
661
0
  CURL_TRC_M(data, "multi_done: status: %d prem: %d done: %d",
662
0
             (int)status, (int)premature, data->state.done);
663
664
0
  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
0
  Curl_async_shutdown(data);
670
671
  /* Cleanup possible redirect junk */
672
0
  Curl_safefree(data->req.newurl);
673
0
  Curl_safefree(data->req.location);
674
675
0
  switch(status) {
676
0
  case CURLE_ABORTED_BY_CALLBACK:
677
0
  case CURLE_READ_ERROR:
678
0
  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
0
    premature = TRUE;
684
0
    FALLTHROUGH();
685
0
  default:
686
0
    break;
687
0
  }
688
689
  /* this calls the protocol-specific function pointer previously set */
690
0
  if(conn->handler->done && (data->mstate >= MSTATE_PROTOCONNECT))
691
0
    result = conn->handler->done(data, status, premature);
692
0
  else
693
0
    result = status;
694
695
0
  if(CURLE_ABORTED_BY_CALLBACK != result) {
696
    /* avoid this if we already aborted by callback to avoid this calling
697
       another callback */
698
0
    int rc = Curl_pgrsDone(data);
699
0
    if(!result && rc)
700
0
      result = CURLE_ABORTED_BY_CALLBACK;
701
0
  }
702
703
  /* Make sure that transfer client writes are really done now. */
704
0
  result = Curl_1st_err(result, Curl_xfer_write_done(data, premature));
705
706
  /* Inform connection filters that this transfer is done */
707
0
  Curl_conn_ev_data_done(data, premature);
708
709
0
  process_pending_handles(data->multi); /* connection / multiplex */
710
711
0
  if(!result)
712
0
    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
0
  mdctx.premature = premature;
717
0
  Curl_cpool_do_locked(data, data->conn, multi_done_locked, &mdctx);
718
719
  /* flush the netrc cache */
720
0
  Curl_netrc_cleanup(&data->state.netrc);
721
0
  return result;
722
0
}
723
724
static void close_connect_only(struct connectdata *conn,
725
                               struct Curl_easy *data,
726
                               void *userdata)
727
0
{
728
0
  (void)userdata;
729
0
  (void)data;
730
0
  if(conn->connect_only)
731
0
    connclose(conn, "Removing connect-only easy handle");
732
0
}
733
734
CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
735
0
{
736
0
  struct Curl_multi *multi = m;
737
0
  struct Curl_easy *data = d;
738
0
  bool premature;
739
0
  struct Curl_llist_node *e;
740
0
  CURLMcode rc;
741
0
  bool removed_timer = FALSE;
742
0
  unsigned int mid;
743
744
  /* First, make some basic checks that the CURLM handle is a good handle */
745
0
  if(!GOOD_MULTI_HANDLE(multi))
746
0
    return CURLM_BAD_HANDLE;
747
748
  /* Verify that we got a somewhat good easy handle too */
749
0
  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
0
  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
0
  if(data->multi != multi)
758
0
    return CURLM_BAD_EASY_HANDLE;
759
760
0
  if(data->mid == UINT_MAX) {
761
0
    DEBUGASSERT(0);
762
0
    return CURLM_INTERNAL_ERROR;
763
0
  }
764
0
  if(Curl_uint_tbl_get(&multi->xfers, data->mid) != data) {
765
0
    DEBUGASSERT(0);
766
0
    return CURLM_INTERNAL_ERROR;
767
0
  }
768
769
0
  if(multi->in_callback)
770
0
    return CURLM_RECURSIVE_API_CALL;
771
772
0
  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
0
  if(data->conn &&
777
0
     data->mstate > MSTATE_DO &&
778
0
     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
0
    streamclose(data->conn, "Removed with partial response");
782
0
  }
783
784
0
  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
0
    (void)multi_done(data, data->result, premature);
791
0
  }
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
0
  removed_timer = Curl_expire_clear(data);
797
798
  /* If in `msgsent`, it was deducted from `multi->xfers_alive` already. */
799
0
  if(!Curl_uint_bset_contains(&multi->msgsent, data->mid))
800
0
    --multi->xfers_alive;
801
802
0
  Curl_wildcard_dtor(&data->wildcard);
803
804
0
  data->mstate = MSTATE_COMPLETED;
805
806
  /* Remove the association between the connection and the handle */
807
0
  Curl_detach_connection(data);
808
809
  /* Tell event handling that this transfer is definitely going away */
810
0
  Curl_multi_ev_xfer_done(multi, data);
811
812
0
  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
0
    struct connectdata *c;
822
0
    curl_socket_t s;
823
0
    s = Curl_getconnectinfo(data, &c);
824
0
    if((s != CURL_SOCKET_BAD) && c) {
825
0
      Curl_conn_terminate(data, c, TRUE);
826
0
    }
827
0
  }
828
829
0
  if(data->state.lastconnect_id != -1) {
830
    /* Mark any connect-only connection for closure */
831
0
    Curl_cpool_do_by_id(data, data->state.lastconnect_id,
832
0
                            close_connect_only, NULL);
833
0
  }
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
0
  for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) {
844
0
    struct Curl_message *msg = Curl_node_elem(e);
845
846
0
    if(msg->extmsg.easy_handle == data) {
847
0
      Curl_node_remove(e);
848
      /* there can only be one from this specific handle */
849
0
      break;
850
0
    }
851
0
  }
852
853
  /* clear the association to this multi handle */
854
0
  mid = data->mid;
855
0
  DEBUGASSERT(Curl_uint_tbl_contains(&multi->xfers, mid));
856
0
  Curl_uint_tbl_remove(&multi->xfers, mid);
857
0
  Curl_uint_bset_remove(&multi->process, mid);
858
0
  Curl_uint_bset_remove(&multi->dirty, mid);
859
0
  Curl_uint_bset_remove(&multi->pending, mid);
860
0
  Curl_uint_bset_remove(&multi->msgsent, mid);
861
0
  data->multi = NULL;
862
0
  data->mid = UINT_MAX;
863
0
  data->master_mid = UINT_MAX;
864
865
  /* NOTE NOTE NOTE
866
     We do not touch the easy handle here! */
867
0
  process_pending_handles(multi);
868
869
0
  if(removed_timer) {
870
0
    rc = Curl_update_timer(multi);
871
0
    if(rc)
872
0
      return rc;
873
0
  }
874
875
0
  CURL_TRC_M(data, "removed from multi, mid=%u, running=%u, total=%u",
876
0
             mid, Curl_multi_xfers_running(multi),
877
0
             Curl_uint_tbl_count(&multi->xfers));
878
0
  return CURLM_OK;
879
0
}
880
881
/* Return TRUE if the application asked for multiplexing */
882
bool Curl_multiplex_wanted(const struct Curl_multi *multi)
883
0
{
884
0
  return multi && multi->multiplexing;
885
0
}
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
0
{
895
0
  struct connectdata *conn = data->conn;
896
0
  if(conn) {
897
0
    Curl_uint_spbset_remove(&conn->xfers_attached, data->mid);
898
0
    if(Curl_uint_spbset_empty(&conn->xfers_attached))
899
0
      conn->attached_multi = NULL;
900
0
  }
901
0
  data->conn = NULL;
902
0
}
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
0
{
912
0
  DEBUGASSERT(data);
913
0
  DEBUGASSERT(!data->conn);
914
0
  DEBUGASSERT(conn);
915
0
  data->conn = conn;
916
0
  Curl_uint_spbset_add(&conn->xfers_attached, data->mid);
917
  /* all attached transfers must be from the same multi */
918
0
  if(!conn->attached_multi)
919
0
    conn->attached_multi = data->multi;
920
0
  DEBUGASSERT(conn->attached_multi == data->multi);
921
922
0
  if(conn->handler && conn->handler->attach)
923
0
    conn->handler->attach(data, conn);
924
0
}
925
926
static CURLcode mstate_connecting_pollset(struct Curl_easy *data,
927
                                          struct easy_pollset *ps)
928
0
{
929
0
  if(data->conn) {
930
0
    curl_socket_t sockfd = Curl_conn_get_first_socket(data);
931
0
    if(sockfd != CURL_SOCKET_BAD) {
932
      /* Default is to wait to something from the server */
933
0
      return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0);
934
0
    }
935
0
  }
936
0
  return CURLE_OK;
937
0
}
938
939
static CURLcode mstate_protocol_pollset(struct Curl_easy *data,
940
                                        struct easy_pollset *ps)
941
0
{
942
0
  struct connectdata *conn = data->conn;
943
0
  if(conn) {
944
0
    curl_socket_t sockfd;
945
0
    if(conn->handler->proto_pollset)
946
0
      return conn->handler->proto_pollset(data, ps);
947
0
    sockfd = conn->sock[FIRSTSOCKET];
948
0
    if(sockfd != CURL_SOCKET_BAD) {
949
      /* Default is to wait to something from the server */
950
0
      return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0);
951
0
    }
952
0
  }
953
0
  return CURLE_OK;
954
0
}
955
956
static CURLcode mstate_do_pollset(struct Curl_easy *data,
957
                                  struct easy_pollset *ps)
958
0
{
959
0
  struct connectdata *conn = data->conn;
960
0
  if(conn) {
961
0
    if(conn->handler->doing_pollset)
962
0
      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
0
  }
969
0
  return CURLE_OK;
970
0
}
971
972
static CURLcode mstate_domore_pollset(struct Curl_easy *data,
973
                                      struct easy_pollset *ps)
974
0
{
975
0
  struct connectdata *conn = data->conn;
976
0
  if(conn) {
977
0
    if(conn->handler->domore_pollset)
978
0
      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
0
  }
985
0
  return CURLE_OK;
986
0
}
987
988
static CURLcode mstate_perform_pollset(struct Curl_easy *data,
989
                                       struct easy_pollset *ps)
990
0
{
991
0
  struct connectdata *conn = data->conn;
992
0
  if(!conn)
993
0
    return CURLE_OK;
994
0
  else if(conn->handler->perform_pollset)
995
0
    return conn->handler->perform_pollset(data, ps);
996
0
  else {
997
    /* Default is to obey the data->req.keepon flags for send/recv */
998
0
    CURLcode result = CURLE_OK;
999
0
    if(CURL_WANT_RECV(data) && CONN_SOCK_IDX_VALID(conn->recv_idx)) {
1000
0
      result = Curl_pollset_add_in(
1001
0
        data, ps, conn->sock[conn->recv_idx]);
1002
0
    }
1003
1004
0
    if(!result && Curl_req_want_send(data) &&
1005
0
       CONN_SOCK_IDX_VALID(conn->send_idx)) {
1006
0
      result = Curl_pollset_add_out(
1007
0
        data, ps, conn->sock[conn->send_idx]);
1008
0
    }
1009
0
    return result;
1010
0
  }
1011
0
}
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
0
{
1019
0
  CURLMcode mresult = CURLM_OK;
1020
0
  CURLcode result = CURLE_OK;
1021
0
  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
0
  Curl_pollset_reset(ps);
1027
0
  if(!data->conn)
1028
0
    return CURLM_OK;
1029
1030
0
  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
0
  case MSTATE_RESOLVING:
1040
0
    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
0
    expect_sockets = FALSE;
1044
0
    break;
1045
1046
0
  case MSTATE_CONNECTING:
1047
0
  case MSTATE_TUNNELING:
1048
0
    if(!Curl_xfer_recv_is_paused(data)) {
1049
0
      result = mstate_connecting_pollset(data, ps);
1050
0
      if(!result)
1051
0
        result = Curl_conn_adjust_pollset(data, data->conn, ps);
1052
0
    }
1053
0
    else
1054
0
      expect_sockets = FALSE;
1055
0
    break;
1056
1057
0
  case MSTATE_PROTOCONNECT:
1058
0
  case MSTATE_PROTOCONNECTING:
1059
0
    result = mstate_protocol_pollset(data, ps);
1060
0
    if(!result)
1061
0
      result = Curl_conn_adjust_pollset(data, data->conn, ps);
1062
0
    break;
1063
1064
0
  case MSTATE_DO:
1065
0
  case MSTATE_DOING:
1066
0
    result = mstate_do_pollset(data, ps);
1067
0
    if(!result)
1068
0
      result = Curl_conn_adjust_pollset(data, data->conn, ps);
1069
0
    break;
1070
1071
0
  case MSTATE_DOING_MORE:
1072
0
    result = mstate_domore_pollset(data, ps);
1073
0
    if(!result)
1074
0
      result = Curl_conn_adjust_pollset(data, data->conn, ps);
1075
0
    break;
1076
1077
0
  case MSTATE_DID: /* same as PERFORMING in regard to polling */
1078
0
  case MSTATE_PERFORMING:
1079
0
    result = mstate_perform_pollset(data, ps);
1080
0
    if(!result)
1081
0
      result = Curl_conn_adjust_pollset(data, data->conn, ps);
1082
0
    break;
1083
1084
0
  case MSTATE_RATELIMITING:
1085
    /* we need to let time pass, ignore socket(s) */
1086
0
    expect_sockets = FALSE;
1087
0
    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
0
  }
1102
1103
0
  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
0
  if(!Curl_xfer_is_blocked(data) && !Curl_xfer_is_too_fast(data) &&
1116
0
     ((Curl_pollset_want_read(data, ps, data->conn->sock[FIRSTSOCKET]) &&
1117
0
       Curl_conn_data_pending(data, FIRSTSOCKET)) ||
1118
0
      (Curl_pollset_want_read(data, ps, data->conn->sock[SECONDARYSOCKET]) &&
1119
0
       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
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
1126
0
  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
0
#endif
1161
1162
0
  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
0
out:
1176
0
  return mresult;
1177
0
}
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
0
{
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
0
  int this_max_fd = -1;
1187
0
  struct Curl_multi *multi = m;
1188
0
  struct easy_pollset ps;
1189
0
  unsigned int i, mid;
1190
0
  (void)exc_fd_set;
1191
1192
0
  if(!GOOD_MULTI_HANDLE(multi))
1193
0
    return CURLM_BAD_HANDLE;
1194
1195
0
  if(multi->in_callback)
1196
0
    return CURLM_RECURSIVE_API_CALL;
1197
1198
0
  Curl_pollset_init(&ps);
1199
0
  if(Curl_uint_bset_first(&multi->process, &mid)) {
1200
0
    do {
1201
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
1202
1203
0
      if(!data) {
1204
0
        DEBUGASSERT(0);
1205
0
        continue;
1206
0
      }
1207
1208
0
      Curl_multi_pollset(data, &ps, "curl_multi_fdset");
1209
0
      for(i = 0; i < ps.n; i++) {
1210
0
        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
0
        if(ps.actions[i] & CURL_POLL_IN)
1218
0
          FD_SET(ps.sockets[i], read_fd_set);
1219
0
        if(ps.actions[i] & CURL_POLL_OUT)
1220
0
          FD_SET(ps.sockets[i], write_fd_set);
1221
#ifdef __DJGPP__
1222
#pragma GCC diagnostic pop
1223
#endif
1224
0
        if((int)ps.sockets[i] > this_max_fd)
1225
0
          this_max_fd = (int)ps.sockets[i];
1226
0
      }
1227
0
    }
1228
0
    while(Curl_uint_bset_next(&multi->process, mid, &mid));
1229
0
  }
1230
1231
0
  Curl_cshutdn_setfds(&multi->cshutdn, multi->admin,
1232
0
                      read_fd_set, write_fd_set, &this_max_fd);
1233
1234
0
  *max_fd = this_max_fd;
1235
0
  Curl_pollset_cleanup(&ps);
1236
1237
0
  return CURLM_OK;
1238
0
}
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
0
{
1649
0
  bool retval = multi->recheckstate;
1650
0
  if(clear)
1651
0
    multi->recheckstate = FALSE;
1652
0
  return retval;
1653
0
}
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
0
{
1664
0
  multi->recheckstate = TRUE;
1665
0
}
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
0
{
1699
0
  CURLcode result = CURLE_OK;
1700
0
  struct connectdata *conn = data->conn;
1701
1702
0
  DEBUGASSERT(conn);
1703
0
  DEBUGASSERT(conn->handler);
1704
1705
0
  if(conn->handler->do_it)
1706
0
    result = conn->handler->do_it(data, done);
1707
1708
0
  return result;
1709
0
}
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
0
{
1722
0
  CURLcode result = CURLE_OK;
1723
0
  struct connectdata *conn = data->conn;
1724
1725
0
  *complete = 0;
1726
1727
0
  if(conn->handler->do_more)
1728
0
    result = conn->handler->do_more(data, complete);
1729
1730
0
  return result;
1731
0
}
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
0
{
1741
0
  bool connect_timeout = data->mstate < MSTATE_DO;
1742
0
  timediff_t timeout_ms = Curl_timeleft(data, now, connect_timeout);
1743
0
  if(timeout_ms < 0) {
1744
    /* Handle timed out */
1745
0
    struct curltime since;
1746
0
    if(connect_timeout)
1747
0
      since = data->progress.t_startsingle;
1748
0
    else
1749
0
      since = data->progress.t_startop;
1750
0
    if(data->mstate == MSTATE_RESOLVING)
1751
0
      failf(data, "Resolving timed out after %" FMT_TIMEDIFF_T
1752
0
            " milliseconds", curlx_timediff(*now, since));
1753
0
    else if(data->mstate == MSTATE_CONNECTING)
1754
0
      failf(data, "Connection timed out after %" FMT_TIMEDIFF_T
1755
0
            " milliseconds", curlx_timediff(*now, since));
1756
0
    else {
1757
0
      struct SingleRequest *k = &data->req;
1758
0
      if(k->size != -1) {
1759
0
        failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
1760
0
              " milliseconds with %" FMT_OFF_T " out of %"
1761
0
              FMT_OFF_T " bytes received",
1762
0
              curlx_timediff(*now, since), k->bytecount, k->size);
1763
0
      }
1764
0
      else {
1765
0
        failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
1766
0
              " milliseconds with %" FMT_OFF_T " bytes received",
1767
0
              curlx_timediff(*now, since), k->bytecount);
1768
0
      }
1769
0
    }
1770
0
    *result = CURLE_OPERATION_TIMEDOUT;
1771
0
    if(data->conn) {
1772
      /* Force connection closed if the connection has indeed been used */
1773
0
      if(data->mstate > MSTATE_DO) {
1774
0
        streamclose(data->conn, "Disconnect due to timeout");
1775
0
        *stream_error = TRUE;
1776
0
      }
1777
0
      (void)multi_done(data, *result, TRUE);
1778
0
    }
1779
0
    return TRUE;
1780
0
  }
1781
1782
0
  return FALSE;
1783
0
}
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
0
{
1793
0
  CURLcode result = CURLE_OK;
1794
0
  struct connectdata *conn = data->conn;
1795
1796
0
  if(conn && conn->handler->connecting) {
1797
0
    *done = FALSE;
1798
0
    result = conn->handler->connecting(data, done);
1799
0
  }
1800
0
  else
1801
0
    *done = TRUE;
1802
1803
0
  return result;
1804
0
}
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
0
{
1813
0
  CURLcode result = CURLE_OK;
1814
0
  struct connectdata *conn = data->conn;
1815
1816
0
  if(conn && conn->handler->doing) {
1817
0
    *done = FALSE;
1818
0
    result = conn->handler->doing(data, done);
1819
0
  }
1820
0
  else
1821
0
    *done = TRUE;
1822
1823
0
  return result;
1824
0
}
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
0
{
1834
0
  CURLcode result = CURLE_OK;
1835
0
  struct connectdata *conn = data->conn;
1836
0
  DEBUGASSERT(conn);
1837
0
  DEBUGASSERT(protocol_done);
1838
1839
0
  *protocol_done = FALSE;
1840
1841
0
  if(Curl_conn_is_connected(conn, FIRSTSOCKET)
1842
0
     && 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
0
  if(!conn->bits.protoconnstart) {
1856
0
    if(conn->handler->connect_it) {
1857
      /* is there a protocol-specific connect() procedure? */
1858
1859
      /* Call the protocol-specific connect function */
1860
0
      result = conn->handler->connect_it(data, protocol_done);
1861
0
    }
1862
0
    else
1863
0
      *protocol_done = TRUE;
1864
1865
    /* it has started, possibly even completed but that knowledge is not stored
1866
       in this bit! */
1867
0
    if(!result)
1868
0
      conn->bits.protoconnstart = TRUE;
1869
0
  }
1870
1871
0
  return result; /* pass back status */
1872
0
}
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
0
{
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
0
  (void)data;
1890
0
#endif
1891
0
}
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
0
{
1904
0
  if(handler && handler->follow)
1905
0
    return handler->follow(data, newurl, type);
1906
0
  return CURLE_TOO_MANY_REDIRECTS;
1907
0
}
1908
1909
static CURLcode mspeed_check(struct Curl_easy *data,
1910
                             struct curltime *nowp)
1911
0
{
1912
0
  timediff_t recv_wait_ms = 0;
1913
0
  timediff_t send_wait_ms = 0;
1914
1915
  /* check if over send speed */
1916
0
  if(data->set.max_send_speed)
1917
0
    send_wait_ms = Curl_pgrsLimitWaitTime(&data->progress.ul,
1918
0
                                          data->set.max_send_speed,
1919
0
                                          *nowp);
1920
1921
  /* check if over recv speed */
1922
0
  if(data->set.max_recv_speed)
1923
0
    recv_wait_ms = Curl_pgrsLimitWaitTime(&data->progress.dl,
1924
0
                                          data->set.max_recv_speed,
1925
0
                                          *nowp);
1926
1927
0
  if(send_wait_ms || recv_wait_ms) {
1928
0
    if(data->mstate != MSTATE_RATELIMITING) {
1929
0
      Curl_ratelimit(data, *nowp);
1930
0
      multistate(data, MSTATE_RATELIMITING);
1931
0
    }
1932
0
    Curl_expire(data, CURLMAX(send_wait_ms, recv_wait_ms), EXPIRE_TOOFAST);
1933
0
    Curl_multi_clear_dirty(data);
1934
0
    return CURLE_AGAIN;
1935
0
  }
1936
0
  else if(data->mstate != MSTATE_PERFORMING) {
1937
0
    multistate(data, MSTATE_PERFORMING);
1938
0
    Curl_ratelimit(data, *nowp);
1939
0
  }
1940
0
  return CURLE_OK;
1941
0
}
1942
1943
static CURLMcode state_performing(struct Curl_easy *data,
1944
                                  struct curltime *nowp,
1945
                                  bool *stream_errorp,
1946
                                  CURLcode *resultp)
1947
0
{
1948
0
  char *newurl = NULL;
1949
0
  bool retry = FALSE;
1950
0
  CURLMcode rc = CURLM_OK;
1951
0
  CURLcode result = *resultp = CURLE_OK;
1952
0
  *stream_errorp = FALSE;
1953
1954
0
  if(mspeed_check(data, nowp) == CURLE_AGAIN)
1955
0
    return CURLM_OK;
1956
1957
  /* read/write data if it is ready to do so */
1958
0
  result = Curl_sendrecv(data, nowp);
1959
1960
0
  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
0
    CURLcode ret = Curl_retry_request(data, &newurl);
1966
0
    if(!ret)
1967
0
      retry = !!newurl;
1968
0
    else if(!result)
1969
0
      result = ret;
1970
1971
0
    if(retry) {
1972
      /* if we are to retry, set the result to OK and consider the
1973
         request as done */
1974
0
      result = CURLE_OK;
1975
0
      data->req.done = TRUE;
1976
0
    }
1977
0
  }
1978
0
#ifndef CURL_DISABLE_HTTP
1979
0
  else if((CURLE_HTTP2_STREAM == result) &&
1980
0
          Curl_h2_http_1_1_error(data)) {
1981
0
    CURLcode ret = Curl_retry_request(data, &newurl);
1982
1983
0
    if(!ret) {
1984
0
      infof(data, "Downgrades to HTTP/1.1");
1985
0
      streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
1986
0
      data->state.http_neg.wanted = CURL_HTTP_V1x;
1987
0
      data->state.http_neg.allowed = CURL_HTTP_V1x;
1988
      /* clear the error message bit too as we ignore the one we got */
1989
0
      data->state.errorbuf = FALSE;
1990
0
      if(!newurl)
1991
        /* typically for HTTP_1_1_REQUIRED error on first flight */
1992
0
        newurl = strdup(data->state.url);
1993
      /* if we are to retry, set the result to OK and consider the request
1994
         as done */
1995
0
      retry = TRUE;
1996
0
      result = CURLE_OK;
1997
0
      data->req.done = TRUE;
1998
0
    }
1999
0
    else
2000
0
      result = ret;
2001
0
  }
2002
0
#endif
2003
2004
0
  if(result) {
2005
    /*
2006
     * The transfer phase returned error, we mark the connection to get closed
2007
     * to prevent being reused. This is because we cannot possibly know if the
2008
     * connection is in a good shape or not now. Unless it is a protocol which
2009
     * uses two "channels" like FTP, as then the error happened in the data
2010
     * connection.
2011
     */
2012
2013
0
    if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2014
0
       result != CURLE_HTTP2_STREAM)
2015
0
      streamclose(data->conn, "Transfer returned error");
2016
2017
0
    multi_posttransfer(data);
2018
0
    multi_done(data, result, TRUE);
2019
0
  }
2020
0
  else if(data->req.done && !Curl_cwriter_is_paused(data)) {
2021
0
    const struct Curl_handler *handler = data->conn->handler;
2022
2023
    /* call this even if the readwrite function returned error */
2024
0
    multi_posttransfer(data);
2025
2026
    /* When we follow redirects or is set to retry the connection, we must to
2027
       go back to the CONNECT state */
2028
0
    if(data->req.newurl || retry) {
2029
0
      followtype follow = FOLLOW_NONE;
2030
0
      if(!retry) {
2031
        /* if the URL is a follow-location and not just a retried request then
2032
           figure out the URL here */
2033
0
        free(newurl);
2034
0
        newurl = data->req.newurl;
2035
0
        data->req.newurl = NULL;
2036
0
        follow = FOLLOW_REDIR;
2037
0
      }
2038
0
      else
2039
0
        follow = FOLLOW_RETRY;
2040
0
      (void)multi_done(data, CURLE_OK, FALSE);
2041
      /* multi_done() might return CURLE_GOT_NOTHING */
2042
0
      result = multi_follow(data, handler, newurl, follow);
2043
0
      if(!result) {
2044
0
        multistate(data, MSTATE_SETUP);
2045
0
        rc = CURLM_CALL_MULTI_PERFORM;
2046
0
      }
2047
0
    }
2048
0
    else {
2049
      /* after the transfer is done, go DONE */
2050
2051
      /* but first check to see if we got a location info even though we are
2052
         not following redirects */
2053
0
      if(data->req.location) {
2054
0
        free(newurl);
2055
0
        newurl = data->req.location;
2056
0
        data->req.location = NULL;
2057
0
        result = multi_follow(data, handler, newurl, FOLLOW_FAKE);
2058
0
        if(result) {
2059
0
          *stream_errorp = TRUE;
2060
0
          result = multi_done(data, result, TRUE);
2061
0
        }
2062
0
      }
2063
2064
0
      if(!result) {
2065
0
        multistate(data, MSTATE_DONE);
2066
0
        rc = CURLM_CALL_MULTI_PERFORM;
2067
0
      }
2068
0
    }
2069
0
  }
2070
0
  else { /* not errored, not done */
2071
0
    mspeed_check(data, nowp);
2072
0
  }
2073
0
  free(newurl);
2074
0
  *resultp = result;
2075
0
  return rc;
2076
0
}
2077
2078
static CURLMcode state_do(struct Curl_easy *data,
2079
                          bool *stream_errorp,
2080
                          CURLcode *resultp)
2081
0
{
2082
0
  CURLMcode rc = CURLM_OK;
2083
0
  CURLcode result = CURLE_OK;
2084
0
  if(data->set.fprereq) {
2085
0
    int prereq_rc;
2086
2087
    /* call the prerequest callback function */
2088
0
    Curl_set_in_callback(data, TRUE);
2089
0
    prereq_rc = data->set.fprereq(data->set.prereq_userp,
2090
0
                                  data->info.primary.remote_ip,
2091
0
                                  data->info.primary.local_ip,
2092
0
                                  data->info.primary.remote_port,
2093
0
                                  data->info.primary.local_port);
2094
0
    Curl_set_in_callback(data, FALSE);
2095
0
    if(prereq_rc != CURL_PREREQFUNC_OK) {
2096
0
      failf(data, "operation aborted by pre-request callback");
2097
      /* failure in pre-request callback - do not do any other processing */
2098
0
      result = CURLE_ABORTED_BY_CALLBACK;
2099
0
      multi_posttransfer(data);
2100
0
      multi_done(data, result, FALSE);
2101
0
      *stream_errorp = TRUE;
2102
0
      goto end;
2103
0
    }
2104
0
  }
2105
2106
0
  if(data->set.connect_only && !data->set.connect_only_ws) {
2107
    /* keep connection open for application to use the socket */
2108
0
    connkeep(data->conn, "CONNECT_ONLY");
2109
0
    multistate(data, MSTATE_DONE);
2110
0
    rc = CURLM_CALL_MULTI_PERFORM;
2111
0
  }
2112
0
  else {
2113
0
    bool dophase_done = FALSE;
2114
    /* Perform the protocol's DO action */
2115
0
    result = multi_do(data, &dophase_done);
2116
2117
    /* When multi_do() returns failure, data->conn might be NULL! */
2118
2119
0
    if(!result) {
2120
0
      if(!dophase_done) {
2121
0
#ifndef CURL_DISABLE_FTP
2122
        /* some steps needed for wildcard matching */
2123
0
        if(data->state.wildcardmatch) {
2124
0
          struct WildcardData *wc = data->wildcard;
2125
0
          if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
2126
            /* skip some states if it is important */
2127
0
            multi_done(data, CURLE_OK, FALSE);
2128
2129
            /* if there is no connection left, skip the DONE state */
2130
0
            multistate(data, data->conn ?
2131
0
                       MSTATE_DONE : MSTATE_COMPLETED);
2132
0
            rc = CURLM_CALL_MULTI_PERFORM;
2133
0
            goto end;
2134
0
          }
2135
0
        }
2136
0
#endif
2137
        /* DO was not completed in one function call, we must continue
2138
           DOING... */
2139
0
        multistate(data, MSTATE_DOING);
2140
0
        rc = CURLM_CALL_MULTI_PERFORM;
2141
0
      }
2142
2143
      /* after DO, go DO_DONE... or DO_MORE */
2144
0
      else if(data->conn->bits.do_more) {
2145
        /* we are supposed to do more, but we need to sit down, relax and wait
2146
           a little while first */
2147
0
        multistate(data, MSTATE_DOING_MORE);
2148
0
        rc = CURLM_CALL_MULTI_PERFORM;
2149
0
      }
2150
0
      else {
2151
        /* we are done with the DO, now DID */
2152
0
        multistate(data, MSTATE_DID);
2153
0
        rc = CURLM_CALL_MULTI_PERFORM;
2154
0
      }
2155
0
    }
2156
0
    else if((CURLE_SEND_ERROR == result) &&
2157
0
            data->conn->bits.reuse) {
2158
      /*
2159
       * In this situation, a connection that we were trying to use may have
2160
       * unexpectedly died. If possible, send the connection back to the
2161
       * CONNECT phase so we can try again.
2162
       */
2163
0
      const struct Curl_handler *handler = data->conn->handler;
2164
0
      char *newurl = NULL;
2165
0
      followtype follow = FOLLOW_NONE;
2166
0
      CURLcode drc;
2167
2168
0
      drc = Curl_retry_request(data, &newurl);
2169
0
      if(drc) {
2170
        /* a failure here pretty much implies an out of memory */
2171
0
        result = drc;
2172
0
        *stream_errorp = TRUE;
2173
0
      }
2174
2175
0
      multi_posttransfer(data);
2176
0
      drc = multi_done(data, result, FALSE);
2177
2178
      /* When set to retry the connection, we must go back to the CONNECT
2179
       * state */
2180
0
      if(newurl) {
2181
0
        if(!drc || (drc == CURLE_SEND_ERROR)) {
2182
0
          follow = FOLLOW_RETRY;
2183
0
          drc = multi_follow(data, handler, newurl, follow);
2184
0
          if(!drc) {
2185
0
            multistate(data, MSTATE_SETUP);
2186
0
            rc = CURLM_CALL_MULTI_PERFORM;
2187
0
            result = CURLE_OK;
2188
0
          }
2189
0
          else {
2190
            /* Follow failed */
2191
0
            result = drc;
2192
0
          }
2193
0
        }
2194
0
        else {
2195
          /* done did not return OK or SEND_ERROR */
2196
0
          result = drc;
2197
0
        }
2198
0
      }
2199
0
      else {
2200
        /* Have error handler disconnect conn if we cannot retry */
2201
0
        *stream_errorp = TRUE;
2202
0
      }
2203
0
      free(newurl);
2204
0
    }
2205
0
    else {
2206
      /* failure detected */
2207
0
      multi_posttransfer(data);
2208
0
      if(data->conn)
2209
0
        multi_done(data, result, FALSE);
2210
0
      *stream_errorp = TRUE;
2211
0
    }
2212
0
  }
2213
0
end:
2214
0
  *resultp = result;
2215
0
  return rc;
2216
0
}
2217
2218
static CURLMcode state_ratelimiting(struct Curl_easy *data,
2219
                                    struct curltime *nowp,
2220
                                    CURLcode *resultp)
2221
0
{
2222
0
  CURLcode result = CURLE_OK;
2223
0
  CURLMcode rc = CURLM_OK;
2224
0
  DEBUGASSERT(data->conn);
2225
  /* if both rates are within spec, resume transfer */
2226
0
  if(Curl_pgrsUpdate(data))
2227
0
    result = CURLE_ABORTED_BY_CALLBACK;
2228
0
  else
2229
0
    result = Curl_speedcheck(data, *nowp);
2230
2231
0
  if(result) {
2232
0
    if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2233
0
       result != CURLE_HTTP2_STREAM)
2234
0
      streamclose(data->conn, "Transfer returned error");
2235
2236
0
    multi_posttransfer(data);
2237
0
    multi_done(data, result, TRUE);
2238
0
  }
2239
0
  else {
2240
0
    if(!mspeed_check(data, nowp))
2241
0
      rc = CURLM_CALL_MULTI_PERFORM;
2242
0
  }
2243
0
  *resultp = result;
2244
0
  return rc;
2245
0
}
2246
2247
static CURLMcode state_resolving(struct Curl_multi *multi,
2248
                                 struct Curl_easy *data,
2249
                                 bool *stream_errorp,
2250
                                 CURLcode *resultp)
2251
0
{
2252
0
  struct Curl_dns_entry *dns = NULL;
2253
0
  CURLcode result;
2254
0
  CURLMcode rc = CURLM_OK;
2255
2256
0
  result = Curl_resolv_check(data, &dns);
2257
0
  CURL_TRC_DNS(data, "Curl_resolv_check() -> %d, %s",
2258
0
               result, dns ? "found" : "missing");
2259
  /* Update sockets here, because the socket(s) may have been closed and the
2260
     application thus needs to be told, even if it is likely that the same
2261
     socket(s) will again be used further down. If the name has not yet been
2262
     resolved, it is likely that new sockets have been opened in an attempt to
2263
     contact another resolver. */
2264
0
  rc = Curl_multi_ev_assess_xfer(multi, data);
2265
0
  if(rc)
2266
0
    return rc;
2267
2268
0
  if(dns) {
2269
0
    bool connected;
2270
    /* Perform the next step in the connection phase, and then move on to the
2271
       WAITCONNECT state */
2272
0
    result = Curl_once_resolved(data, dns, &connected);
2273
2274
0
    if(result)
2275
      /* if Curl_once_resolved() returns failure, the connection struct is
2276
         already freed and gone */
2277
0
      data->conn = NULL; /* no more connection */
2278
0
    else {
2279
      /* call again please so that we get the next socket setup */
2280
0
      rc = CURLM_CALL_MULTI_PERFORM;
2281
0
      if(connected)
2282
0
        multistate(data, MSTATE_PROTOCONNECT);
2283
0
      else {
2284
0
        multistate(data, MSTATE_CONNECTING);
2285
0
      }
2286
0
    }
2287
0
  }
2288
2289
0
  if(result)
2290
    /* failure detected */
2291
0
    *stream_errorp = TRUE;
2292
2293
0
  *resultp = result;
2294
0
  return rc;
2295
0
}
2296
2297
static CURLMcode state_connect(struct Curl_multi *multi,
2298
                               struct Curl_easy *data,
2299
                               struct curltime *nowp,
2300
                               CURLcode *resultp)
2301
0
{
2302
  /* Connect. We want to get a connection identifier filled in. This state can
2303
     be entered from SETUP and from PENDING. */
2304
0
  bool connected;
2305
0
  bool async;
2306
0
  CURLMcode rc = CURLM_OK;
2307
0
  CURLcode result = Curl_connect(data, &async, &connected);
2308
0
  if(CURLE_NO_CONNECTION_AVAILABLE == result) {
2309
    /* There was no connection available. We will go to the pending state and
2310
       wait for an available connection. */
2311
0
    multistate(data, MSTATE_PENDING);
2312
    /* move from process to pending set */
2313
0
    Curl_uint_bset_remove(&multi->process, data->mid);
2314
0
    Curl_uint_bset_remove(&multi->dirty, data->mid);
2315
0
    Curl_uint_bset_add(&multi->pending, data->mid);
2316
0
    *resultp = CURLE_OK;
2317
0
    return rc;
2318
0
  }
2319
0
  else
2320
0
    process_pending_handles(data->multi);
2321
2322
0
  if(!result) {
2323
0
    *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
2324
0
    if(async)
2325
      /* We are now waiting for an asynchronous name lookup */
2326
0
      multistate(data, MSTATE_RESOLVING);
2327
0
    else {
2328
      /* after the connect has been sent off, go WAITCONNECT unless the
2329
         protocol connect is already done and we can go directly to WAITDO or
2330
         DO! */
2331
0
      rc = CURLM_CALL_MULTI_PERFORM;
2332
2333
0
      if(connected) {
2334
0
        if(!data->conn->bits.reuse &&
2335
0
           Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
2336
          /* new connection, can multiplex, wake pending handles */
2337
0
          process_pending_handles(data->multi);
2338
0
        }
2339
0
        multistate(data, MSTATE_PROTOCONNECT);
2340
0
      }
2341
0
      else {
2342
0
        multistate(data, MSTATE_CONNECTING);
2343
0
      }
2344
0
    }
2345
0
  }
2346
0
  *resultp = result;
2347
0
  return rc;
2348
0
}
2349
2350
static CURLMcode multi_runsingle(struct Curl_multi *multi,
2351
                                 struct curltime *nowp,
2352
                                 struct Curl_easy *data)
2353
0
{
2354
0
  struct Curl_message *msg = NULL;
2355
0
  bool connected;
2356
0
  bool protocol_connected = FALSE;
2357
0
  bool dophase_done = FALSE;
2358
0
  CURLMcode rc;
2359
0
  CURLcode result = CURLE_OK;
2360
0
  int control;
2361
2362
0
  if(!GOOD_EASY_HANDLE(data))
2363
0
    return CURLM_BAD_EASY_HANDLE;
2364
2365
0
  if(multi->dead) {
2366
    /* a multi-level callback returned error before, meaning every individual
2367
     transfer now has failed */
2368
0
    result = CURLE_ABORTED_BY_CALLBACK;
2369
0
    multi_posttransfer(data);
2370
0
    multi_done(data, result, FALSE);
2371
0
    multistate(data, MSTATE_COMPLETED);
2372
0
  }
2373
2374
0
  multi_warn_debug(multi, data);
2375
2376
  /* transfer runs now, clear the dirty bit. This may be set
2377
   * again during processing, triggering a re-run later. */
2378
0
  Curl_uint_bset_remove(&multi->dirty, data->mid);
2379
2380
0
  do {
2381
    /* A "stream" here is a logical stream if the protocol can handle that
2382
       (HTTP/2), or the full connection for older protocols */
2383
0
    bool stream_error = FALSE;
2384
0
    rc = CURLM_OK;
2385
2386
0
    if(multi_ischanged(multi, TRUE)) {
2387
0
      CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
2388
0
      process_pending_handles(multi); /* multiplexed */
2389
0
    }
2390
2391
0
    if(data->mstate > MSTATE_CONNECT &&
2392
0
       data->mstate < MSTATE_COMPLETED) {
2393
      /* Make sure we set the connection's current owner */
2394
0
      DEBUGASSERT(data->conn);
2395
0
      if(!data->conn)
2396
0
        return CURLM_INTERNAL_ERROR;
2397
0
    }
2398
2399
    /* Wait for the connect state as only then is the start time stored, but
2400
       we must not check already completed handles */
2401
0
    if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
2402
0
       multi_handle_timeout(data, nowp, &stream_error, &result))
2403
      /* Skip the statemachine and go directly to error handling section. */
2404
0
      goto statemachine_end;
2405
2406
0
    switch(data->mstate) {
2407
0
    case MSTATE_INIT:
2408
      /* Transitional state. init this transfer. A handle never comes back to
2409
         this state. */
2410
0
      result = Curl_pretransfer(data);
2411
0
      if(result)
2412
0
        break;
2413
2414
      /* after init, go SETUP */
2415
0
      multistate(data, MSTATE_SETUP);
2416
0
      (void)Curl_pgrsTime(data, TIMER_STARTOP);
2417
0
      FALLTHROUGH();
2418
2419
0
    case MSTATE_SETUP:
2420
      /* Transitional state. Setup things for a new transfer. The handle
2421
         can come back to this state on a redirect. */
2422
0
      *nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
2423
0
      if(data->set.timeout)
2424
0
        Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
2425
0
      if(data->set.connecttimeout)
2426
        /* Since a connection might go to pending and back to CONNECT several
2427
           times before it actually takes off, we need to set the timeout once
2428
           in SETUP before we enter CONNECT the first time. */
2429
0
        Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
2430
2431
0
      multistate(data, MSTATE_CONNECT);
2432
0
      FALLTHROUGH();
2433
2434
0
    case MSTATE_CONNECT:
2435
0
      rc = state_connect(multi, data, nowp, &result);
2436
0
      break;
2437
2438
0
    case MSTATE_RESOLVING:
2439
      /* awaiting an asynch name resolve to complete */
2440
0
      rc = state_resolving(multi, data, &stream_error, &result);
2441
0
      break;
2442
2443
0
#ifndef CURL_DISABLE_HTTP
2444
0
    case MSTATE_TUNNELING:
2445
      /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
2446
0
      DEBUGASSERT(data->conn);
2447
0
      result = Curl_http_connect(data, &protocol_connected);
2448
0
      if(!result) {
2449
0
        rc = CURLM_CALL_MULTI_PERFORM;
2450
        /* initiate protocol connect phase */
2451
0
        multistate(data, MSTATE_PROTOCONNECT);
2452
0
      }
2453
0
      else
2454
0
        stream_error = TRUE;
2455
0
      break;
2456
0
#endif
2457
2458
0
    case MSTATE_CONNECTING:
2459
      /* awaiting a completion of an asynch TCP connect */
2460
0
      DEBUGASSERT(data->conn);
2461
0
      if(!Curl_xfer_recv_is_paused(data)) {
2462
0
        result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
2463
0
        if(connected && !result) {
2464
0
          if(!data->conn->bits.reuse &&
2465
0
             Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
2466
            /* new connection, can multiplex, wake pending handles */
2467
0
            process_pending_handles(data->multi);
2468
0
          }
2469
0
          rc = CURLM_CALL_MULTI_PERFORM;
2470
0
          multistate(data, MSTATE_PROTOCONNECT);
2471
0
        }
2472
0
        else if(result) {
2473
          /* failure detected */
2474
0
          multi_posttransfer(data);
2475
0
          multi_done(data, result, TRUE);
2476
0
          stream_error = TRUE;
2477
0
          break;
2478
0
        }
2479
0
      }
2480
0
      break;
2481
2482
0
    case MSTATE_PROTOCONNECT:
2483
0
      if(!result && data->conn->bits.reuse) {
2484
        /* ftp seems to hang when protoconnect on reused connection since we
2485
         * handle PROTOCONNECT in general inside the filers, it seems wrong to
2486
         * restart this on a reused connection.
2487
         */
2488
0
        multistate(data, MSTATE_DO);
2489
0
        rc = CURLM_CALL_MULTI_PERFORM;
2490
0
        break;
2491
0
      }
2492
0
      if(!result)
2493
0
        result = protocol_connect(data, &protocol_connected);
2494
0
      if(!result && !protocol_connected) {
2495
        /* switch to waiting state */
2496
0
        multistate(data, MSTATE_PROTOCONNECTING);
2497
0
        rc = CURLM_CALL_MULTI_PERFORM;
2498
0
      }
2499
0
      else if(!result) {
2500
        /* protocol connect has completed, go WAITDO or DO */
2501
0
        multistate(data, MSTATE_DO);
2502
0
        rc = CURLM_CALL_MULTI_PERFORM;
2503
0
      }
2504
0
      else {
2505
        /* failure detected */
2506
0
        multi_posttransfer(data);
2507
0
        multi_done(data, result, TRUE);
2508
0
        stream_error = TRUE;
2509
0
      }
2510
0
      break;
2511
2512
0
    case MSTATE_PROTOCONNECTING:
2513
      /* protocol-specific connect phase */
2514
0
      result = protocol_connecting(data, &protocol_connected);
2515
0
      if(!result && protocol_connected) {
2516
        /* after the connect has completed, go WAITDO or DO */
2517
0
        multistate(data, MSTATE_DO);
2518
0
        rc = CURLM_CALL_MULTI_PERFORM;
2519
0
      }
2520
0
      else if(result) {
2521
        /* failure detected */
2522
0
        multi_posttransfer(data);
2523
0
        multi_done(data, result, TRUE);
2524
0
        stream_error = TRUE;
2525
0
      }
2526
0
      break;
2527
2528
0
    case MSTATE_DO:
2529
0
      rc = state_do(data, &stream_error, &result);
2530
0
      break;
2531
2532
0
    case MSTATE_DOING:
2533
      /* we continue DOING until the DO phase is complete */
2534
0
      DEBUGASSERT(data->conn);
2535
0
      result = protocol_doing(data, &dophase_done);
2536
0
      if(!result) {
2537
0
        if(dophase_done) {
2538
          /* after DO, go DO_DONE or DO_MORE */
2539
0
          multistate(data, data->conn->bits.do_more ?
2540
0
                     MSTATE_DOING_MORE : MSTATE_DID);
2541
0
          rc = CURLM_CALL_MULTI_PERFORM;
2542
0
        } /* dophase_done */
2543
0
      }
2544
0
      else {
2545
        /* failure detected */
2546
0
        multi_posttransfer(data);
2547
0
        multi_done(data, result, FALSE);
2548
0
        stream_error = TRUE;
2549
0
      }
2550
0
      break;
2551
2552
0
    case MSTATE_DOING_MORE:
2553
      /*
2554
       * When we are connected, DOING MORE and then go DID
2555
       */
2556
0
      DEBUGASSERT(data->conn);
2557
0
      result = multi_do_more(data, &control);
2558
2559
0
      if(!result) {
2560
0
        if(control) {
2561
          /* if positive, advance to DO_DONE
2562
             if negative, go back to DOING */
2563
0
          multistate(data, control == 1 ?
2564
0
                     MSTATE_DID : MSTATE_DOING);
2565
0
          rc = CURLM_CALL_MULTI_PERFORM;
2566
0
        }
2567
        /* else
2568
           stay in DO_MORE */
2569
0
      }
2570
0
      else {
2571
        /* failure detected */
2572
0
        multi_posttransfer(data);
2573
0
        multi_done(data, result, FALSE);
2574
0
        stream_error = TRUE;
2575
0
      }
2576
0
      break;
2577
2578
0
    case MSTATE_DID:
2579
0
      DEBUGASSERT(data->conn);
2580
0
      if(data->conn->bits.multiplex)
2581
        /* Check if we can move pending requests to send pipe */
2582
0
        process_pending_handles(multi); /*  multiplexed */
2583
2584
      /* Only perform the transfer if there is a good socket to work with.
2585
         Having both BAD is a signal to skip immediately to DONE */
2586
0
      if(CONN_SOCK_IDX_VALID(data->conn->recv_idx) ||
2587
0
         CONN_SOCK_IDX_VALID(data->conn->send_idx))
2588
0
        multistate(data, MSTATE_PERFORMING);
2589
0
      else {
2590
0
#ifndef CURL_DISABLE_FTP
2591
0
        if(data->state.wildcardmatch &&
2592
0
           ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
2593
0
          data->wildcard->state = CURLWC_DONE;
2594
0
        }
2595
0
#endif
2596
0
        multistate(data, MSTATE_DONE);
2597
0
      }
2598
0
      rc = CURLM_CALL_MULTI_PERFORM;
2599
0
      break;
2600
2601
0
    case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
2602
0
      rc = state_ratelimiting(data, nowp, &result);
2603
0
      break;
2604
2605
0
    case MSTATE_PERFORMING:
2606
0
      rc = state_performing(data, nowp, &stream_error, &result);
2607
0
      break;
2608
2609
0
    case MSTATE_DONE:
2610
      /* this state is highly transient, so run another loop after this */
2611
0
      rc = CURLM_CALL_MULTI_PERFORM;
2612
2613
0
      if(data->conn) {
2614
0
        CURLcode res;
2615
2616
        /* post-transfer command */
2617
0
        res = multi_done(data, result, FALSE);
2618
2619
        /* allow a previously set error code take precedence */
2620
0
        if(!result)
2621
0
          result = res;
2622
0
      }
2623
2624
0
#ifndef CURL_DISABLE_FTP
2625
0
      if(data->state.wildcardmatch) {
2626
0
        if(data->wildcard->state != CURLWC_DONE) {
2627
          /* if a wildcard is set and we are not ending -> lets start again
2628
             with MSTATE_INIT */
2629
0
          multistate(data, MSTATE_INIT);
2630
0
          break;
2631
0
        }
2632
0
      }
2633
0
#endif
2634
      /* after we have DONE what we are supposed to do, go COMPLETED, and
2635
         it does not matter what the multi_done() returned! */
2636
0
      multistate(data, MSTATE_COMPLETED);
2637
0
      break;
2638
2639
0
    case MSTATE_COMPLETED:
2640
0
      break;
2641
2642
0
    case MSTATE_PENDING:
2643
0
    case MSTATE_MSGSENT:
2644
      /* handles in these states should NOT be in this list */
2645
0
      break;
2646
2647
0
    default:
2648
0
      return CURLM_INTERNAL_ERROR;
2649
0
    }
2650
2651
0
    if(data->mstate >= MSTATE_CONNECT &&
2652
0
       data->mstate < MSTATE_DO &&
2653
0
       rc != CURLM_CALL_MULTI_PERFORM &&
2654
0
       !multi_ischanged(multi, FALSE)) {
2655
      /* We now handle stream timeouts if and only if this will be the last
2656
       * loop iteration. We only check this on the last iteration to ensure
2657
       * that if we know we have additional work to do immediately
2658
       * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
2659
       * declaring the connection timed out as we may almost have a completed
2660
       * connection. */
2661
0
      multi_handle_timeout(data, nowp, &stream_error, &result);
2662
0
    }
2663
2664
0
statemachine_end:
2665
2666
0
    if(data->mstate < MSTATE_COMPLETED) {
2667
0
      if(result) {
2668
        /*
2669
         * If an error was returned, and we are not in completed state now,
2670
         * then we go to completed and consider this transfer aborted.
2671
         */
2672
2673
        /* NOTE: no attempt to disconnect connections must be made
2674
           in the case blocks above - cleanup happens only here */
2675
2676
        /* Check if we can move pending requests to send pipe */
2677
0
        process_pending_handles(multi); /* connection */
2678
2679
0
        if(data->conn) {
2680
0
          if(stream_error) {
2681
            /* Do not attempt to send data over a connection that timed out */
2682
0
            bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
2683
0
            struct connectdata *conn = data->conn;
2684
2685
            /* This is where we make sure that the conn pointer is reset.
2686
               We do not have to do this in every case block above where a
2687
               failure is detected */
2688
0
            Curl_detach_connection(data);
2689
0
            Curl_conn_terminate(data, conn, dead_connection);
2690
0
          }
2691
0
        }
2692
0
        else if(data->mstate == MSTATE_CONNECT) {
2693
          /* Curl_connect() failed */
2694
0
          multi_posttransfer(data);
2695
0
          Curl_pgrsUpdate_nometer(data);
2696
0
        }
2697
2698
0
        multistate(data, MSTATE_COMPLETED);
2699
0
        rc = CURLM_CALL_MULTI_PERFORM;
2700
0
      }
2701
      /* if there is still a connection to use, call the progress function */
2702
0
      else if(data->conn && Curl_pgrsUpdate(data)) {
2703
        /* aborted due to progress callback return code must close the
2704
           connection */
2705
0
        result = CURLE_ABORTED_BY_CALLBACK;
2706
0
        streamclose(data->conn, "Aborted by callback");
2707
2708
        /* if not yet in DONE state, go there, otherwise COMPLETED */
2709
0
        multistate(data, (data->mstate < MSTATE_DONE) ?
2710
0
                   MSTATE_DONE : MSTATE_COMPLETED);
2711
0
        rc = CURLM_CALL_MULTI_PERFORM;
2712
0
      }
2713
0
    }
2714
2715
0
    if(MSTATE_COMPLETED == data->mstate) {
2716
0
      if(data->master_mid != UINT_MAX) {
2717
        /* A sub transfer, not for msgsent to application */
2718
0
        struct Curl_easy *mdata;
2719
2720
0
        CURL_TRC_M(data, "sub xfer done for master %u", data->master_mid);
2721
0
        mdata = Curl_multi_get_easy(multi, data->master_mid);
2722
0
        if(mdata) {
2723
0
          if(mdata->sub_xfer_done)
2724
0
            mdata->sub_xfer_done(mdata, data, result);
2725
0
          else
2726
0
            CURL_TRC_M(data, "master easy %u without sub_xfer_done callback.",
2727
0
                       data->master_mid);
2728
0
        }
2729
0
        else {
2730
0
          CURL_TRC_M(data, "master easy %u already gone.", data->master_mid);
2731
0
        }
2732
0
      }
2733
0
      else {
2734
        /* now fill in the Curl_message with this info */
2735
0
        msg = &data->msg;
2736
2737
0
        msg->extmsg.msg = CURLMSG_DONE;
2738
0
        msg->extmsg.easy_handle = data;
2739
0
        msg->extmsg.data.result = result;
2740
2741
0
        multi_addmsg(multi, msg);
2742
0
        DEBUGASSERT(!data->conn);
2743
0
      }
2744
0
      multistate(data, MSTATE_MSGSENT);
2745
2746
      /* remove from the other sets, add to msgsent */
2747
0
      Curl_uint_bset_remove(&multi->process, data->mid);
2748
0
      Curl_uint_bset_remove(&multi->dirty, data->mid);
2749
0
      Curl_uint_bset_remove(&multi->pending, data->mid);
2750
0
      Curl_uint_bset_add(&multi->msgsent, data->mid);
2751
0
      --multi->xfers_alive;
2752
0
      return CURLM_OK;
2753
0
    }
2754
0
  } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
2755
2756
0
  data->result = result;
2757
0
  return rc;
2758
0
}
2759
2760
2761
CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
2762
0
{
2763
0
  CURLMcode returncode = CURLM_OK;
2764
0
  struct Curl_tree *t = NULL;
2765
0
  struct curltime now = curlx_now();
2766
0
  struct Curl_multi *multi = m;
2767
0
  unsigned int mid;
2768
0
  SIGPIPE_VARIABLE(pipe_st);
2769
2770
0
  if(!GOOD_MULTI_HANDLE(multi))
2771
0
    return CURLM_BAD_HANDLE;
2772
2773
0
  if(multi->in_callback)
2774
0
    return CURLM_RECURSIVE_API_CALL;
2775
2776
0
  if(multi->in_ntfy_callback)
2777
0
    return CURLM_RECURSIVE_API_CALL;
2778
2779
0
  sigpipe_init(&pipe_st);
2780
0
  if(Curl_uint_bset_first(&multi->process, &mid)) {
2781
0
    CURL_TRC_M(multi->admin, "multi_perform(running=%u)",
2782
0
               Curl_multi_xfers_running(multi));
2783
0
    do {
2784
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
2785
0
      CURLMcode result;
2786
0
      if(!data) {
2787
0
        DEBUGASSERT(0);
2788
0
        Curl_uint_bset_remove(&multi->process, mid);
2789
0
        Curl_uint_bset_remove(&multi->dirty, mid);
2790
0
        continue;
2791
0
      }
2792
0
      if(data != multi->admin) {
2793
        /* admin handle is processed below */
2794
0
        sigpipe_apply(data, &pipe_st);
2795
0
        result = multi_runsingle(multi, &now, data);
2796
0
        if(result)
2797
0
          returncode = result;
2798
0
      }
2799
0
    }
2800
0
    while(Curl_uint_bset_next(&multi->process, mid, &mid));
2801
0
  }
2802
2803
0
  sigpipe_apply(multi->admin, &pipe_st);
2804
0
  Curl_cshutdn_perform(&multi->cshutdn, multi->admin, CURL_SOCKET_TIMEOUT);
2805
0
  sigpipe_restore(&pipe_st);
2806
2807
0
  if(multi_ischanged(m, TRUE))
2808
0
    process_pending_handles(m);
2809
2810
0
  if(!returncode)
2811
0
    returncode = Curl_mntfy_dispatch_all(multi);
2812
2813
  /*
2814
   * Simply remove all expired timers from the splay since handles are dealt
2815
   * with unconditionally by this function and curl_multi_timeout() requires
2816
   * that already passed/handled expire times are removed from the splay.
2817
   *
2818
   * It is important that the 'now' value is set at the entry of this function
2819
   * and not for the current time as it may have ticked a little while since
2820
   * then and then we risk this loop to remove timers that actually have not
2821
   * been handled!
2822
   */
2823
0
  do {
2824
0
    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
2825
0
    if(t) {
2826
      /* the removed may have another timeout in queue */
2827
0
      struct Curl_easy *data = Curl_splayget(t);
2828
0
      (void)add_next_timeout(now, multi, data);
2829
0
      if(data->mstate == MSTATE_PENDING) {
2830
0
        bool stream_unused;
2831
0
        CURLcode result_unused;
2832
0
        if(multi_handle_timeout(data, &now, &stream_unused, &result_unused)) {
2833
0
          infof(data, "PENDING handle timeout");
2834
0
          move_pending_to_connect(multi, data);
2835
0
        }
2836
0
      }
2837
0
    }
2838
0
  } while(t);
2839
2840
0
  if(running_handles) {
2841
0
    unsigned int running = Curl_multi_xfers_running(multi);
2842
0
    *running_handles = (running < INT_MAX) ? (int)running : INT_MAX;
2843
0
  }
2844
2845
0
  if(CURLM_OK >= returncode)
2846
0
    returncode = Curl_update_timer(multi);
2847
2848
0
  return returncode;
2849
0
}
2850
2851
CURLMcode curl_multi_cleanup(CURLM *m)
2852
0
{
2853
0
  struct Curl_multi *multi = m;
2854
0
  if(GOOD_MULTI_HANDLE(multi)) {
2855
0
    void *entry;
2856
0
    unsigned int mid;
2857
0
    if(multi->in_callback)
2858
0
      return CURLM_RECURSIVE_API_CALL;
2859
0
    if(multi->in_ntfy_callback)
2860
0
      return CURLM_RECURSIVE_API_CALL;
2861
2862
    /* First remove all remaining easy handles,
2863
     * close internal ones. admin handle is special */
2864
0
    if(Curl_uint_tbl_first(&multi->xfers, &mid, &entry)) {
2865
0
      do {
2866
0
        struct Curl_easy *data = entry;
2867
0
        if(!GOOD_EASY_HANDLE(data))
2868
0
          return CURLM_BAD_HANDLE;
2869
2870
#ifdef DEBUGBUILD
2871
        if(mid != data->mid) {
2872
          CURL_TRC_M(data, "multi_cleanup: still present with mid=%u, "
2873
                     "but unexpected data->mid=%u\n", mid, data->mid);
2874
          DEBUGASSERT(0);
2875
        }
2876
#endif
2877
2878
0
        if(data == multi->admin)
2879
0
          continue;
2880
2881
0
        if(!data->state.done && data->conn)
2882
          /* if DONE was never called for this handle */
2883
0
          (void)multi_done(data, CURLE_OK, TRUE);
2884
2885
0
        data->multi = NULL; /* clear the association */
2886
0
        Curl_uint_tbl_remove(&multi->xfers, mid);
2887
0
        data->mid = UINT_MAX;
2888
2889
#ifdef USE_LIBPSL
2890
        if(data->psl == &multi->psl)
2891
          data->psl = NULL;
2892
#endif
2893
0
        if(data->state.internal)
2894
0
          Curl_close(&data);
2895
0
      }
2896
0
      while(Curl_uint_tbl_next(&multi->xfers, mid, &mid, &entry));
2897
0
    }
2898
2899
0
    Curl_cpool_destroy(&multi->cpool);
2900
0
    Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
2901
0
    if(multi->admin) {
2902
0
      CURL_TRC_M(multi->admin, "multi_cleanup, closing admin handle, done");
2903
0
      multi->admin->multi = NULL;
2904
0
      Curl_uint_tbl_remove(&multi->xfers, multi->admin->mid);
2905
0
      Curl_close(&multi->admin);
2906
0
    }
2907
2908
0
    multi->magic = 0; /* not good anymore */
2909
2910
0
    Curl_multi_ev_cleanup(multi);
2911
0
    Curl_hash_destroy(&multi->proto_hash);
2912
0
    Curl_dnscache_destroy(&multi->dnscache);
2913
0
    Curl_psl_destroy(&multi->psl);
2914
0
#ifdef USE_SSL
2915
0
    Curl_ssl_scache_destroy(multi->ssl_scache);
2916
0
#endif
2917
2918
#ifdef USE_WINSOCK
2919
    WSACloseEvent(multi->wsa_event);
2920
#else
2921
0
#ifdef ENABLE_WAKEUP
2922
0
    wakeup_close(multi->wakeup_pair[0]);
2923
#ifndef USE_EVENTFD
2924
    wakeup_close(multi->wakeup_pair[1]);
2925
#endif
2926
0
#endif
2927
0
#endif
2928
2929
0
    multi_xfer_bufs_free(multi);
2930
0
    Curl_mntfy_cleanup(multi);
2931
#ifdef DEBUGBUILD
2932
    if(Curl_uint_tbl_count(&multi->xfers)) {
2933
      multi_xfer_tbl_dump(multi);
2934
      DEBUGASSERT(0);
2935
    }
2936
#endif
2937
0
    Curl_uint_bset_destroy(&multi->process);
2938
0
    Curl_uint_bset_destroy(&multi->dirty);
2939
0
    Curl_uint_bset_destroy(&multi->pending);
2940
0
    Curl_uint_bset_destroy(&multi->msgsent);
2941
0
    Curl_uint_tbl_destroy(&multi->xfers);
2942
0
    free(multi);
2943
2944
0
    return CURLM_OK;
2945
0
  }
2946
0
  return CURLM_BAD_HANDLE;
2947
0
}
2948
2949
/*
2950
 * curl_multi_info_read()
2951
 *
2952
 * This function is the primary way for a multi/multi_socket application to
2953
 * figure out if a transfer has ended. We MUST make this function as fast as
2954
 * possible as it will be polled frequently and we MUST NOT scan any lists in
2955
 * here to figure out things. We must scale fine to thousands of handles and
2956
 * beyond. The current design is fully O(1).
2957
 */
2958
2959
CURLMsg *curl_multi_info_read(CURLM *m, int *msgs_in_queue)
2960
0
{
2961
0
  struct Curl_message *msg;
2962
0
  struct Curl_multi *multi = m;
2963
2964
0
  *msgs_in_queue = 0; /* default to none */
2965
2966
0
  if(GOOD_MULTI_HANDLE(multi) &&
2967
0
     !multi->in_callback &&
2968
0
     Curl_llist_count(&multi->msglist)) {
2969
    /* there is one or more messages in the list */
2970
0
    struct Curl_llist_node *e;
2971
2972
    /* extract the head of the list to return */
2973
0
    e = Curl_llist_head(&multi->msglist);
2974
2975
0
    msg = Curl_node_elem(e);
2976
2977
    /* remove the extracted entry */
2978
0
    Curl_node_remove(e);
2979
2980
0
    *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
2981
2982
0
    return &msg->extmsg;
2983
0
  }
2984
0
  return NULL;
2985
0
}
2986
2987
2988
void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s)
2989
0
{
2990
0
  if(data) {
2991
0
    struct Curl_multi *multi = data->multi;
2992
0
    if(multi) {
2993
0
      CURL_TRC_M(data, "Curl_multi_will_close fd=%" FMT_SOCKET_T, s);
2994
0
      Curl_multi_ev_socket_done(multi, data, s);
2995
0
    }
2996
0
  }
2997
0
}
2998
2999
/*
3000
 * add_next_timeout()
3001
 *
3002
 * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
3003
 * when it has just been removed from the splay tree because the timeout has
3004
 * expired. This function is then to advance in the list to pick the next
3005
 * timeout to use (skip the already expired ones) and add this node back to
3006
 * the splay tree again.
3007
 *
3008
 * The splay tree only has each sessionhandle as a single node and the nearest
3009
 * timeout is used to sort it on.
3010
 */
3011
static CURLMcode add_next_timeout(struct curltime now,
3012
                                  struct Curl_multi *multi,
3013
                                  struct Curl_easy *d)
3014
0
{
3015
0
  struct curltime *tv = &d->state.expiretime;
3016
0
  struct Curl_llist *list = &d->state.timeoutlist;
3017
0
  struct Curl_llist_node *e;
3018
3019
  /* move over the timeout list for this specific handle and remove all
3020
     timeouts that are now passed tense and store the next pending
3021
     timeout in *tv */
3022
0
  for(e = Curl_llist_head(list); e;) {
3023
0
    struct Curl_llist_node *n = Curl_node_next(e);
3024
0
    struct time_node *node = Curl_node_elem(e);
3025
0
    timediff_t diff = curlx_timediff_us(node->time, now);
3026
0
    if(diff <= 0)
3027
      /* remove outdated entry */
3028
0
      Curl_node_remove(e);
3029
0
    else
3030
      /* the list is sorted so get out on the first mismatch */
3031
0
      break;
3032
0
    e = n;
3033
0
  }
3034
0
  e = Curl_llist_head(list);
3035
0
  if(!e) {
3036
    /* clear the expire times within the handles that we remove from the
3037
       splay tree */
3038
0
    tv->tv_sec = 0;
3039
0
    tv->tv_usec = 0;
3040
0
  }
3041
0
  else {
3042
0
    struct time_node *node = Curl_node_elem(e);
3043
    /* copy the first entry to 'tv' */
3044
0
    memcpy(tv, &node->time, sizeof(*tv));
3045
3046
    /* Insert this node again into the splay. Keep the timer in the list in
3047
       case we need to recompute future timers. */
3048
0
    multi->timetree = Curl_splayinsert(*tv, multi->timetree,
3049
0
                                       &d->state.timenode);
3050
0
  }
3051
0
  return CURLM_OK;
3052
0
}
3053
3054
struct multi_run_ctx {
3055
  struct Curl_multi *multi;
3056
  struct curltime now;
3057
  size_t run_xfers;
3058
  SIGPIPE_MEMBER(pipe_st);
3059
  bool run_cpool;
3060
};
3061
3062
static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc)
3063
0
{
3064
0
  struct Curl_multi *multi = mrc->multi;
3065
0
  struct Curl_easy *data = NULL;
3066
0
  struct Curl_tree *t = NULL;
3067
3068
  /*
3069
   * The loop following here will go on as long as there are expire-times left
3070
   * to process (compared to mrc->now) in the splay and 'data' will be
3071
   * re-assigned for every expired handle we deal with.
3072
   */
3073
0
  while(1) {
3074
    /* Check if there is one (more) expired timer to deal with! This function
3075
       extracts a matching node if there is one */
3076
0
    multi->timetree = Curl_splaygetbest(mrc->now, multi->timetree, &t);
3077
0
    if(!t)
3078
0
      return;
3079
3080
0
    data = Curl_splayget(t); /* assign this for next loop */
3081
0
    if(!data)
3082
0
      continue;
3083
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
3084
0
    if(CURL_TRC_TIMER_is_verbose(data)) {
3085
0
      struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
3086
0
      if(e) {
3087
0
        struct time_node *n = Curl_node_elem(e);
3088
0
        CURL_TRC_TIMER(data, n->eid, "has expired");
3089
0
      }
3090
0
    }
3091
0
#endif
3092
0
    (void)add_next_timeout(mrc->now, multi, data);
3093
0
    Curl_multi_mark_dirty(data);
3094
0
  }
3095
0
}
3096
3097
static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc)
3098
0
{
3099
0
  struct Curl_multi *multi = mrc->multi;
3100
0
  CURLMcode result = CURLM_OK;
3101
0
  unsigned int mid;
3102
3103
0
  if(Curl_uint_bset_first(&multi->dirty, &mid)) {
3104
0
    do {
3105
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3106
0
      if(data) {
3107
0
        CURL_TRC_M(data, "multi_run_dirty");
3108
3109
0
        if(data == multi->admin) {
3110
0
          Curl_uint_bset_remove(&multi->dirty, mid);
3111
0
          mrc->run_cpool = TRUE;
3112
0
          continue;
3113
0
        }
3114
0
        else if(!Curl_uint_bset_contains(&multi->process, mid)) {
3115
          /* We are no longer processing this transfer */
3116
0
          Curl_uint_bset_remove(&multi->dirty, mid);
3117
0
          continue;
3118
0
        }
3119
3120
0
        mrc->run_xfers++;
3121
0
        sigpipe_apply(data, &mrc->pipe_st);
3122
        /* runsingle() clears the dirty mid */
3123
0
        result = multi_runsingle(multi, &mrc->now, data);
3124
3125
0
        if(CURLM_OK >= result) {
3126
          /* reassess event handling of data */
3127
0
          result = Curl_multi_ev_assess_xfer(multi, data);
3128
0
          if(result)
3129
0
            goto out;
3130
0
        }
3131
0
      }
3132
0
      else {
3133
0
        CURL_TRC_M(multi->admin, "multi_run_dirty, %u no longer found", mid);
3134
0
        Curl_uint_bset_remove(&multi->dirty, mid);
3135
0
      }
3136
0
    }
3137
0
    while(Curl_uint_bset_next(&multi->dirty, mid, &mid));
3138
0
  }
3139
3140
0
out:
3141
0
  return result;
3142
0
}
3143
3144
static CURLMcode multi_socket(struct Curl_multi *multi,
3145
                              bool checkall,
3146
                              curl_socket_t s,
3147
                              int ev_bitmask,
3148
                              int *running_handles)
3149
0
{
3150
0
  CURLMcode result = CURLM_OK;
3151
0
  struct multi_run_ctx mrc;
3152
3153
0
  (void)ev_bitmask;
3154
0
  memset(&mrc, 0, sizeof(mrc));
3155
0
  mrc.multi = multi;
3156
0
  mrc.now = curlx_now();
3157
0
  sigpipe_init(&mrc.pipe_st);
3158
3159
0
  if(checkall) {
3160
    /* *perform() deals with running_handles on its own */
3161
0
    result = curl_multi_perform(multi, running_handles);
3162
3163
0
    if(result != CURLM_BAD_HANDLE) {
3164
      /* Reassess event status of all active transfers */
3165
0
      result = Curl_multi_ev_assess_xfer_bset(multi, &multi->process);
3166
0
    }
3167
0
    mrc.run_cpool = TRUE;
3168
0
    goto out;
3169
0
  }
3170
3171
0
  if(s != CURL_SOCKET_TIMEOUT) {
3172
    /* Mark all transfers of that socket as dirty */
3173
0
    Curl_multi_ev_dirty_xfers(multi, s, &mrc.run_cpool);
3174
0
  }
3175
0
  else {
3176
    /* Asked to run due to time-out. Clear the 'last_expire_ts' variable to
3177
       force Curl_update_timer() to trigger a callback to the app again even
3178
       if the same timeout is still the one to run after this call. That
3179
       handles the case when the application asks libcurl to run the timeout
3180
       prematurely. */
3181
0
    memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts));
3182
0
    mrc.run_cpool = TRUE;
3183
0
  }
3184
3185
0
  multi_mark_expired_as_dirty(&mrc);
3186
0
  result = multi_run_dirty(&mrc);
3187
0
  if(result)
3188
0
    goto out;
3189
3190
0
  if(mrc.run_xfers) {
3191
    /* Running transfers takes time. With a new timestamp, we might catch
3192
     * other expires which are due now. Instead of telling the application
3193
     * to set a 0 timeout and call us again, we run them here.
3194
     * Do that only once or it might be unfair to transfers on other
3195
     * sockets. */
3196
0
    mrc.now = curlx_now();
3197
0
    multi_mark_expired_as_dirty(&mrc);
3198
0
    result = multi_run_dirty(&mrc);
3199
0
  }
3200
3201
0
out:
3202
0
  if(mrc.run_cpool) {
3203
0
    sigpipe_apply(multi->admin, &mrc.pipe_st);
3204
0
    Curl_cshutdn_perform(&multi->cshutdn, multi->admin, s);
3205
0
  }
3206
0
  sigpipe_restore(&mrc.pipe_st);
3207
3208
0
  if(multi_ischanged(multi, TRUE))
3209
0
    process_pending_handles(multi);
3210
3211
0
  if(!result)
3212
0
    result = Curl_mntfy_dispatch_all(multi);
3213
3214
0
  if(running_handles) {
3215
0
    unsigned int running = Curl_multi_xfers_running(multi);
3216
0
    *running_handles = (running < INT_MAX) ? (int)running : INT_MAX;
3217
0
  }
3218
3219
0
  if(CURLM_OK >= result)
3220
0
    result = Curl_update_timer(multi);
3221
0
  return result;
3222
0
}
3223
3224
#undef curl_multi_setopt
3225
CURLMcode curl_multi_setopt(CURLM *m,
3226
                            CURLMoption option, ...)
3227
0
{
3228
0
  CURLMcode res = CURLM_OK;
3229
0
  va_list param;
3230
0
  unsigned long uarg;
3231
0
  struct Curl_multi *multi = m;
3232
3233
0
  if(!GOOD_MULTI_HANDLE(multi))
3234
0
    return CURLM_BAD_HANDLE;
3235
3236
0
  if(multi->in_callback)
3237
0
    return CURLM_RECURSIVE_API_CALL;
3238
3239
0
  va_start(param, option);
3240
3241
0
  switch(option) {
3242
0
  case CURLMOPT_SOCKETFUNCTION:
3243
0
    multi->socket_cb = va_arg(param, curl_socket_callback);
3244
0
    break;
3245
0
  case CURLMOPT_SOCKETDATA:
3246
0
    multi->socket_userp = va_arg(param, void *);
3247
0
    break;
3248
0
  case CURLMOPT_PUSHFUNCTION:
3249
0
    multi->push_cb = va_arg(param, curl_push_callback);
3250
0
    break;
3251
0
  case CURLMOPT_PUSHDATA:
3252
0
    multi->push_userp = va_arg(param, void *);
3253
0
    break;
3254
0
  case CURLMOPT_PIPELINING:
3255
0
    multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX ? 1 : 0;
3256
0
    break;
3257
0
  case CURLMOPT_TIMERFUNCTION:
3258
0
    multi->timer_cb = va_arg(param, curl_multi_timer_callback);
3259
0
    break;
3260
0
  case CURLMOPT_TIMERDATA:
3261
0
    multi->timer_userp = va_arg(param, void *);
3262
0
    break;
3263
0
  case CURLMOPT_MAXCONNECTS:
3264
0
    uarg = va_arg(param, unsigned long);
3265
0
    if(uarg <= UINT_MAX)
3266
0
      multi->maxconnects = (unsigned int)uarg;
3267
0
    break;
3268
0
  case CURLMOPT_MAX_HOST_CONNECTIONS:
3269
0
    multi->max_host_connections = va_arg(param, long);
3270
0
    break;
3271
0
  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
3272
0
    multi->max_total_connections = va_arg(param, long);
3273
0
    break;
3274
    /* options formerly used for pipelining */
3275
0
  case CURLMOPT_MAX_PIPELINE_LENGTH:
3276
0
    break;
3277
0
  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
3278
0
    break;
3279
0
  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
3280
0
    break;
3281
0
  case CURLMOPT_PIPELINING_SITE_BL:
3282
0
    break;
3283
0
  case CURLMOPT_PIPELINING_SERVER_BL:
3284
0
    break;
3285
0
  case CURLMOPT_MAX_CONCURRENT_STREAMS:
3286
0
    {
3287
0
      long streams = va_arg(param, long);
3288
0
      if((streams < 1) || (streams > INT_MAX))
3289
0
        streams = 100;
3290
0
      multi->max_concurrent_streams = (unsigned int)streams;
3291
0
    }
3292
0
    break;
3293
0
  case CURLMOPT_NETWORK_CHANGED: {
3294
0
    long val = va_arg(param, long);
3295
0
    if(val & CURLMNWC_CLEAR_DNS) {
3296
0
      Curl_dnscache_clear(multi->admin);
3297
0
    }
3298
0
    if(val & CURLMNWC_CLEAR_CONNS) {
3299
0
      Curl_cpool_nw_changed(multi->admin);
3300
0
    }
3301
0
    break;
3302
0
  }
3303
0
  case CURLMOPT_NOTIFYFUNCTION:
3304
0
    multi->ntfy.ntfy_cb = va_arg(param, curl_notify_callback);
3305
0
    break;
3306
0
  case CURLMOPT_NOTIFYDATA:
3307
0
    multi->ntfy.ntfy_cb_data = va_arg(param, void *);
3308
0
    break;
3309
0
  default:
3310
0
    res = CURLM_UNKNOWN_OPTION;
3311
0
    break;
3312
0
  }
3313
0
  va_end(param);
3314
0
  return res;
3315
0
}
3316
3317
/* we define curl_multi_socket() in the public multi.h header */
3318
#undef curl_multi_socket
3319
3320
CURLMcode curl_multi_socket(CURLM *m, curl_socket_t s, int *running_handles)
3321
0
{
3322
0
  struct Curl_multi *multi = m;
3323
0
  if(multi->in_callback)
3324
0
    return CURLM_RECURSIVE_API_CALL;
3325
0
  if(multi->in_ntfy_callback)
3326
0
    return CURLM_RECURSIVE_API_CALL;
3327
0
  return multi_socket(multi, FALSE, s, 0, running_handles);
3328
0
}
3329
3330
CURLMcode curl_multi_socket_action(CURLM *m, curl_socket_t s,
3331
                                   int ev_bitmask, int *running_handles)
3332
0
{
3333
0
  struct Curl_multi *multi = m;
3334
0
  if(multi->in_callback)
3335
0
    return CURLM_RECURSIVE_API_CALL;
3336
0
  if(multi->in_ntfy_callback)
3337
0
    return CURLM_RECURSIVE_API_CALL;
3338
0
  return multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
3339
0
}
3340
3341
CURLMcode curl_multi_socket_all(CURLM *m, int *running_handles)
3342
0
{
3343
0
  struct Curl_multi *multi = m;
3344
0
  if(multi->in_callback)
3345
0
    return CURLM_RECURSIVE_API_CALL;
3346
0
  if(multi->in_ntfy_callback)
3347
0
    return CURLM_RECURSIVE_API_CALL;
3348
0
  return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
3349
0
}
3350
3351
3352
static bool multi_has_dirties(struct Curl_multi *multi)
3353
0
{
3354
0
  unsigned int mid;
3355
0
  if(Curl_uint_bset_first(&multi->dirty, &mid)) {
3356
0
    do {
3357
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3358
0
      if(data) {
3359
0
        if(Curl_uint_bset_contains(&multi->process, mid))
3360
0
          return TRUE;
3361
        /* We are no longer processing this transfer */
3362
0
        Curl_uint_bset_remove(&multi->dirty, mid);
3363
0
      }
3364
0
      else {
3365
0
        CURL_TRC_M(multi->admin, "dirty transfer %u no longer found", mid);
3366
0
        Curl_uint_bset_remove(&multi->dirty, mid);
3367
0
      }
3368
0
    }
3369
0
    while(Curl_uint_bset_next(&multi->dirty, mid, &mid));
3370
0
  }
3371
0
  return FALSE;
3372
0
}
3373
3374
static CURLMcode multi_timeout(struct Curl_multi *multi,
3375
                               struct curltime *expire_time,
3376
                               long *timeout_ms)
3377
0
{
3378
0
  static const struct curltime tv_zero = {0, 0};
3379
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
3380
0
  struct Curl_easy *data = NULL;
3381
0
#endif
3382
3383
0
  if(multi->dead) {
3384
0
    *timeout_ms = 0;
3385
0
    return CURLM_OK;
3386
0
  }
3387
3388
0
  if(multi_has_dirties(multi)) {
3389
0
    *expire_time = curlx_now();
3390
0
    *timeout_ms = 0;
3391
0
    return CURLM_OK;
3392
0
  }
3393
0
  else if(multi->timetree) {
3394
    /* we have a tree of expire times */
3395
0
    struct curltime now = curlx_now();
3396
3397
    /* splay the lowest to the bottom */
3398
0
    multi->timetree = Curl_splay(tv_zero, multi->timetree);
3399
    /* this will not return NULL from a non-empty tree, but some compilers
3400
     * are not convinced of that. Analyzers are hard. */
3401
0
    *expire_time = multi->timetree ? multi->timetree->key : tv_zero;
3402
3403
    /* 'multi->timetree' will be non-NULL here but the compilers sometimes
3404
       yell at us if we assume so */
3405
0
    if(multi->timetree &&
3406
0
       curlx_timediff_us(multi->timetree->key, now) > 0) {
3407
      /* some time left before expiration */
3408
0
      timediff_t diff = curlx_timediff_ceil(multi->timetree->key, now);
3409
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
3410
0
      data = Curl_splayget(multi->timetree);
3411
0
#endif
3412
      /* this should be safe even on 32-bit archs, as we do not use that
3413
         overly long timeouts */
3414
0
      *timeout_ms = (long)diff;
3415
0
    }
3416
0
    else {
3417
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
3418
0
      if(multi->timetree) {
3419
0
        data = Curl_splayget(multi->timetree);
3420
0
      }
3421
0
#endif
3422
      /* 0 means immediately */
3423
0
      *timeout_ms = 0;
3424
0
    }
3425
0
  }
3426
0
  else {
3427
0
    *expire_time = tv_zero;
3428
0
    *timeout_ms = -1;
3429
0
  }
3430
3431
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
3432
0
  if(data && CURL_TRC_TIMER_is_verbose(data)) {
3433
0
    struct Curl_llist_node *e =
3434
0
      Curl_llist_head(&data->state.timeoutlist);
3435
0
    if(e) {
3436
0
      struct time_node *n = Curl_node_elem(e);
3437
0
      CURL_TRC_TIMER(data, n->eid, "gives multi timeout in %ldms",
3438
0
                     *timeout_ms);
3439
0
    }
3440
0
  }
3441
0
#endif
3442
3443
0
  return CURLM_OK;
3444
0
}
3445
3446
CURLMcode curl_multi_timeout(CURLM *m,
3447
                             long *timeout_ms)
3448
0
{
3449
0
  struct curltime expire_time;
3450
0
  struct Curl_multi *multi = m;
3451
3452
  /* First, make some basic checks that the CURLM handle is a good handle */
3453
0
  if(!GOOD_MULTI_HANDLE(multi))
3454
0
    return CURLM_BAD_HANDLE;
3455
3456
0
  if(multi->in_callback)
3457
0
    return CURLM_RECURSIVE_API_CALL;
3458
3459
0
  return multi_timeout(multi, &expire_time, timeout_ms);
3460
0
}
3461
3462
/*
3463
 * Tell the application it should update its timers, if it subscribes to the
3464
 * update timer callback.
3465
 */
3466
CURLMcode Curl_update_timer(struct Curl_multi *multi)
3467
0
{
3468
0
  struct curltime expire_ts;
3469
0
  long timeout_ms;
3470
0
  int rc;
3471
0
  bool set_value = FALSE;
3472
3473
0
  if(!multi->timer_cb || multi->dead)
3474
0
    return CURLM_OK;
3475
0
  if(multi_timeout(multi, &expire_ts, &timeout_ms)) {
3476
0
    return CURLM_OK;
3477
0
  }
3478
3479
0
  if(timeout_ms < 0 && multi->last_timeout_ms < 0) {
3480
    /* nothing to do */
3481
0
  }
3482
0
  else if(timeout_ms < 0) {
3483
    /* there is no timeout now but there was one previously */
3484
0
    CURL_TRC_M(multi->admin, "[TIMER] clear");
3485
0
    timeout_ms = -1; /* normalize */
3486
0
    set_value = TRUE;
3487
0
  }
3488
0
  else if(multi->last_timeout_ms < 0) {
3489
0
    CURL_TRC_M(multi->admin, "[TIMER] set %ldms, none before",
3490
0
               timeout_ms);
3491
0
    set_value = TRUE;
3492
0
  }
3493
0
  else if(curlx_timediff_us(multi->last_expire_ts, expire_ts)) {
3494
    /* We had a timeout before and have one now, the absolute timestamp
3495
     * differs. The relative timeout_ms may be the same, but the starting
3496
     * point differs. Let the application restart its timer. */
3497
0
    CURL_TRC_M(multi->admin, "[TIMER] set %ldms, replace previous",
3498
0
               timeout_ms);
3499
0
    set_value = TRUE;
3500
0
  }
3501
0
  else {
3502
    /* We have same expire time as previously. Our relative 'timeout_ms'
3503
     * may be different now, but the application has the timer running
3504
     * and we do not to tell it to start this again. */
3505
0
  }
3506
3507
0
  if(set_value) {
3508
0
    multi->last_expire_ts = expire_ts;
3509
0
    multi->last_timeout_ms = timeout_ms;
3510
0
    set_in_callback(multi, TRUE);
3511
0
    rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
3512
0
    set_in_callback(multi, FALSE);
3513
0
    if(rc == -1) {
3514
0
      multi->dead = TRUE;
3515
0
      return CURLM_ABORTED_BY_CALLBACK;
3516
0
    }
3517
0
  }
3518
0
  return CURLM_OK;
3519
0
}
3520
3521
/*
3522
 * multi_deltimeout()
3523
 *
3524
 * Remove a given timestamp from the list of timeouts.
3525
 */
3526
static void
3527
multi_deltimeout(struct Curl_easy *data, expire_id eid)
3528
0
{
3529
0
  struct Curl_llist_node *e;
3530
0
  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3531
  /* find and remove the specific node from the list */
3532
0
  for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
3533
0
    struct time_node *n = Curl_node_elem(e);
3534
0
    if(n->eid == eid) {
3535
0
      Curl_node_remove(e);
3536
0
      return;
3537
0
    }
3538
0
  }
3539
0
}
3540
3541
/*
3542
 * multi_addtimeout()
3543
 *
3544
 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
3545
 * of list is always the timeout nearest in time.
3546
 *
3547
 */
3548
static CURLMcode
3549
multi_addtimeout(struct Curl_easy *data,
3550
                 struct curltime *stamp,
3551
                 expire_id eid,
3552
                 const struct curltime *nowp)
3553
0
{
3554
0
  struct Curl_llist_node *e;
3555
0
  struct time_node *node;
3556
0
  struct Curl_llist_node *prev = NULL;
3557
0
  size_t n;
3558
0
  struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3559
3560
0
  (void)nowp;
3561
0
  node = &data->state.expires[eid];
3562
3563
  /* copy the timestamp and id */
3564
0
  memcpy(&node->time, stamp, sizeof(*stamp));
3565
0
  node->eid = eid; /* also marks it as in use */
3566
3567
0
  n = Curl_llist_count(timeoutlist);
3568
0
  if(n) {
3569
    /* find the correct spot in the list */
3570
0
    for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
3571
0
      struct time_node *check = Curl_node_elem(e);
3572
0
      timediff_t diff = curlx_timediff(check->time, node->time);
3573
0
      if(diff > 0)
3574
0
        break;
3575
0
      prev = e;
3576
0
    }
3577
3578
0
  }
3579
  /* else
3580
     this is the first timeout on the list */
3581
3582
0
  Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
3583
0
  CURL_TRC_TIMER(data, eid, "set for %" FMT_TIMEDIFF_T "ns",
3584
0
                 curlx_timediff_us(node->time, *nowp));
3585
0
  return CURLM_OK;
3586
0
}
3587
3588
void Curl_expire_ex(struct Curl_easy *data,
3589
                    const struct curltime *nowp,
3590
                    timediff_t milli, expire_id id)
3591
0
{
3592
0
  struct Curl_multi *multi = data->multi;
3593
0
  struct curltime *curr_expire = &data->state.expiretime;
3594
0
  struct curltime set;
3595
3596
  /* this is only interesting while there is still an associated multi struct
3597
     remaining! */
3598
0
  if(!multi)
3599
0
    return;
3600
3601
0
  DEBUGASSERT(id < EXPIRE_LAST);
3602
3603
0
  set = *nowp;
3604
0
  set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bits conversion */
3605
0
  set.tv_usec += (int)(milli%1000)*1000;
3606
3607
0
  if(set.tv_usec >= 1000000) {
3608
0
    set.tv_sec++;
3609
0
    set.tv_usec -= 1000000;
3610
0
  }
3611
3612
  /* Remove any timer with the same id just in case. */
3613
0
  multi_deltimeout(data, id);
3614
3615
  /* Add it to the timer list. It must stay in the list until it has expired
3616
     in case we need to recompute the minimum timer later. */
3617
0
  multi_addtimeout(data, &set, id, nowp);
3618
3619
0
  if(curr_expire->tv_sec || curr_expire->tv_usec) {
3620
    /* This means that the struct is added as a node in the splay tree.
3621
       Compare if the new time is earlier, and only remove-old/add-new if it
3622
       is. */
3623
0
    timediff_t diff = curlx_timediff(set, *curr_expire);
3624
0
    int rc;
3625
3626
0
    if(diff > 0) {
3627
      /* The current splay tree entry is sooner than this new expiry time.
3628
         We do not need to update our splay tree entry. */
3629
0
      return;
3630
0
    }
3631
3632
    /* Since this is an updated time, we must remove the previous entry from
3633
       the splay tree first and then re-add the new value */
3634
0
    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3635
0
                          &multi->timetree);
3636
0
    if(rc)
3637
0
      infof(data, "Internal error removing splay node = %d", rc);
3638
0
  }
3639
3640
  /* Indicate that we are in the splay tree and insert the new timer expiry
3641
     value since it is our local minimum. */
3642
0
  *curr_expire = set;
3643
0
  Curl_splayset(&data->state.timenode, data);
3644
0
  multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree,
3645
0
                                     &data->state.timenode);
3646
0
}
3647
3648
/*
3649
 * Curl_expire()
3650
 *
3651
 * given a number of milliseconds from now to use to set the 'act before
3652
 * this'-time for the transfer, to be extracted by curl_multi_timeout()
3653
 *
3654
 * The timeout will be added to a queue of timeouts if it defines a moment in
3655
 * time that is later than the current head of queue.
3656
 *
3657
 * Expire replaces a former timeout using the same id if already set.
3658
 */
3659
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
3660
0
{
3661
0
  struct curltime now = curlx_now();
3662
0
  Curl_expire_ex(data, &now, milli, id);
3663
0
}
3664
3665
/*
3666
 * Curl_expire_done()
3667
 *
3668
 * Removes the expire timer. Marks it as done.
3669
 *
3670
 */
3671
void Curl_expire_done(struct Curl_easy *data, expire_id eid)
3672
0
{
3673
  /* remove the timer, if there */
3674
0
  multi_deltimeout(data, eid);
3675
0
  CURL_TRC_TIMER(data, eid, "cleared");
3676
0
}
3677
3678
/*
3679
 * Curl_expire_clear()
3680
 *
3681
 * Clear ALL timeout values for this handle.
3682
 */
3683
bool Curl_expire_clear(struct Curl_easy *data)
3684
0
{
3685
0
  struct Curl_multi *multi = data->multi;
3686
0
  struct curltime *nowp = &data->state.expiretime;
3687
3688
  /* this is only interesting while there is still an associated multi struct
3689
     remaining! */
3690
0
  if(!multi)
3691
0
    return FALSE;
3692
3693
0
  if(nowp->tv_sec || nowp->tv_usec) {
3694
    /* Since this is an cleared time, we must remove the previous entry from
3695
       the splay tree */
3696
0
    struct Curl_llist *list = &data->state.timeoutlist;
3697
0
    int rc;
3698
3699
0
    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3700
0
                          &multi->timetree);
3701
0
    if(rc)
3702
0
      infof(data, "Internal error clearing splay node = %d", rc);
3703
3704
    /* clear the timeout list too */
3705
0
    Curl_llist_destroy(list, NULL);
3706
3707
0
    if(data->id >= 0)
3708
0
      CURL_TRC_M(data, "[TIMEOUT] all cleared");
3709
0
    nowp->tv_sec = 0;
3710
0
    nowp->tv_usec = 0;
3711
0
    return TRUE;
3712
0
  }
3713
0
  return FALSE;
3714
0
}
3715
3716
CURLMcode curl_multi_assign(CURLM *m, curl_socket_t s,
3717
                            void *hashp)
3718
0
{
3719
0
  struct Curl_multi *multi = m;
3720
0
  if(!GOOD_MULTI_HANDLE(multi))
3721
0
    return CURLM_BAD_HANDLE;
3722
3723
0
  return Curl_multi_ev_assign(multi, s, hashp);
3724
0
}
3725
3726
static void move_pending_to_connect(struct Curl_multi *multi,
3727
                                    struct Curl_easy *data)
3728
0
{
3729
0
  DEBUGASSERT(data->mstate == MSTATE_PENDING);
3730
3731
  /* Remove this node from the pending set, add into process set */
3732
0
  Curl_uint_bset_remove(&multi->pending, data->mid);
3733
0
  Curl_uint_bset_add(&multi->process, data->mid);
3734
3735
0
  multistate(data, MSTATE_CONNECT);
3736
0
  Curl_multi_mark_dirty(data); /* make it run */
3737
0
}
3738
3739
/* process_pending_handles() moves a handle from PENDING back into the process
3740
   list and change state to CONNECT.
3741
3742
   We do not move all transfers because that can be a significant amount.
3743
   Since this is tried every now and then doing too many too often becomes a
3744
   performance problem.
3745
3746
   When there is a change for connection limits like max host connections etc,
3747
   this likely only allows one new transfer. When there is a pipewait change,
3748
   it can potentially allow hundreds of new transfers.
3749
3750
   We could consider an improvement where we store the queue reason and allow
3751
   more pipewait rechecks than others.
3752
*/
3753
static void process_pending_handles(struct Curl_multi *multi)
3754
0
{
3755
0
  unsigned int mid;
3756
0
  if(Curl_uint_bset_first(&multi->pending, &mid)) {
3757
0
    do {
3758
0
      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
3759
0
      if(data) {
3760
0
        move_pending_to_connect(multi, data);
3761
0
        break;
3762
0
      }
3763
      /* transfer no longer known, should not happen */
3764
0
      Curl_uint_bset_remove(&multi->pending, mid);
3765
0
      DEBUGASSERT(0);
3766
0
    }
3767
0
    while(Curl_uint_bset_next(&multi->pending, mid, &mid));
3768
0
  }
3769
0
}
3770
3771
void Curl_set_in_callback(struct Curl_easy *data, bool value)
3772
0
{
3773
0
  if(data && data->multi)
3774
0
    data->multi->in_callback = value;
3775
0
}
3776
3777
bool Curl_is_in_callback(struct Curl_easy *data)
3778
0
{
3779
0
  return data && data->multi && data->multi->in_callback;
3780
0
}
3781
3782
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
3783
0
{
3784
0
  DEBUGASSERT(multi);
3785
0
  return multi->max_concurrent_streams;
3786
0
}
3787
3788
CURL **curl_multi_get_handles(CURLM *m)
3789
0
{
3790
0
  struct Curl_multi *multi = m;
3791
0
  void *entry;
3792
0
  unsigned int count = Curl_uint_tbl_count(&multi->xfers);
3793
0
  CURL **a = malloc(sizeof(struct Curl_easy *) * (count + 1));
3794
0
  if(a) {
3795
0
    unsigned int i = 0, mid;
3796
3797
0
    if(Curl_uint_tbl_first(&multi->xfers, &mid, &entry)) {
3798
0
      do {
3799
0
        struct Curl_easy *data = entry;
3800
0
        DEBUGASSERT(i < count);
3801
0
        if(!data->state.internal)
3802
0
          a[i++] = data;
3803
0
      }
3804
0
      while(Curl_uint_tbl_next(&multi->xfers, mid, &mid, &entry));
3805
0
    }
3806
0
    a[i] = NULL; /* last entry is a NULL */
3807
0
  }
3808
0
  return a;
3809
0
}
3810
3811
CURLMcode curl_multi_get_offt(CURLM *m,
3812
                              CURLMinfo_offt info,
3813
                              curl_off_t *pvalue)
3814
0
{
3815
0
  struct Curl_multi *multi = m;
3816
3817
0
  if(!GOOD_MULTI_HANDLE(multi))
3818
0
    return CURLM_BAD_HANDLE;
3819
0
  if(!pvalue)
3820
0
    return CURLM_BAD_FUNCTION_ARGUMENT;
3821
3822
0
  switch(info) {
3823
0
  case CURLMINFO_XFERS_CURRENT: {
3824
0
    unsigned int n = Curl_uint_tbl_count(&multi->xfers);
3825
0
    if(n && multi->admin)
3826
0
      --n;
3827
0
    *pvalue = (curl_off_t)n;
3828
0
    return CURLM_OK;
3829
0
  }
3830
0
  case CURLMINFO_XFERS_RUNNING:
3831
0
    *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->process);
3832
0
    return CURLM_OK;
3833
0
  case CURLMINFO_XFERS_PENDING:
3834
0
    *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->pending);
3835
0
    return CURLM_OK;
3836
0
  case CURLMINFO_XFERS_DONE:
3837
0
    *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->msgsent);
3838
0
    return CURLM_OK;
3839
0
  case CURLMINFO_XFERS_ADDED:
3840
0
    *pvalue = multi->xfers_total_ever;
3841
0
    return CURLM_OK;
3842
0
  default:
3843
0
    *pvalue = -1;
3844
0
    return CURLM_UNKNOWN_OPTION;
3845
0
  }
3846
0
}
3847
3848
CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
3849
                                    char **pbuf, size_t *pbuflen)
3850
0
{
3851
0
  DEBUGASSERT(data);
3852
0
  DEBUGASSERT(data->multi);
3853
0
  *pbuf = NULL;
3854
0
  *pbuflen = 0;
3855
0
  if(!data->multi) {
3856
0
    failf(data, "transfer has no multi handle");
3857
0
    return CURLE_FAILED_INIT;
3858
0
  }
3859
0
  if(!data->set.buffer_size) {
3860
0
    failf(data, "transfer buffer size is 0");
3861
0
    return CURLE_FAILED_INIT;
3862
0
  }
3863
0
  if(data->multi->xfer_buf_borrowed) {
3864
0
    failf(data, "attempt to borrow xfer_buf when already borrowed");
3865
0
    return CURLE_AGAIN;
3866
0
  }
3867
3868
0
  if(data->multi->xfer_buf &&
3869
0
     data->set.buffer_size > data->multi->xfer_buf_len) {
3870
    /* not large enough, get a new one */
3871
0
    free(data->multi->xfer_buf);
3872
0
    data->multi->xfer_buf = NULL;
3873
0
    data->multi->xfer_buf_len = 0;
3874
0
  }
3875
3876
0
  if(!data->multi->xfer_buf) {
3877
0
    data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
3878
0
    if(!data->multi->xfer_buf) {
3879
0
      failf(data, "could not allocate xfer_buf of %zu bytes",
3880
0
            (size_t)data->set.buffer_size);
3881
0
      return CURLE_OUT_OF_MEMORY;
3882
0
    }
3883
0
    data->multi->xfer_buf_len = data->set.buffer_size;
3884
0
  }
3885
3886
0
  data->multi->xfer_buf_borrowed = TRUE;
3887
0
  *pbuf = data->multi->xfer_buf;
3888
0
  *pbuflen = data->multi->xfer_buf_len;
3889
0
  return CURLE_OK;
3890
0
}
3891
3892
void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
3893
0
{
3894
0
  (void)buf;
3895
0
  DEBUGASSERT(data);
3896
0
  DEBUGASSERT(data->multi);
3897
0
  DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
3898
0
  data->multi->xfer_buf_borrowed = FALSE;
3899
0
}
3900
3901
CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
3902
                                      char **pbuf, size_t *pbuflen)
3903
0
{
3904
0
  DEBUGASSERT(data);
3905
0
  DEBUGASSERT(data->multi);
3906
0
  *pbuf = NULL;
3907
0
  *pbuflen = 0;
3908
0
  if(!data->multi) {
3909
0
    failf(data, "transfer has no multi handle");
3910
0
    return CURLE_FAILED_INIT;
3911
0
  }
3912
0
  if(!data->set.upload_buffer_size) {
3913
0
    failf(data, "transfer upload buffer size is 0");
3914
0
    return CURLE_FAILED_INIT;
3915
0
  }
3916
0
  if(data->multi->xfer_ulbuf_borrowed) {
3917
0
    failf(data, "attempt to borrow xfer_ulbuf when already borrowed");
3918
0
    return CURLE_AGAIN;
3919
0
  }
3920
3921
0
  if(data->multi->xfer_ulbuf &&
3922
0
     data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
3923
    /* not large enough, get a new one */
3924
0
    free(data->multi->xfer_ulbuf);
3925
0
    data->multi->xfer_ulbuf = NULL;
3926
0
    data->multi->xfer_ulbuf_len = 0;
3927
0
  }
3928
3929
0
  if(!data->multi->xfer_ulbuf) {
3930
0
    data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
3931
0
    if(!data->multi->xfer_ulbuf) {
3932
0
      failf(data, "could not allocate xfer_ulbuf of %zu bytes",
3933
0
            (size_t)data->set.upload_buffer_size);
3934
0
      return CURLE_OUT_OF_MEMORY;
3935
0
    }
3936
0
    data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
3937
0
  }
3938
3939
0
  data->multi->xfer_ulbuf_borrowed = TRUE;
3940
0
  *pbuf = data->multi->xfer_ulbuf;
3941
0
  *pbuflen = data->multi->xfer_ulbuf_len;
3942
0
  return CURLE_OK;
3943
0
}
3944
3945
void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf)
3946
0
{
3947
0
  (void)buf;
3948
0
  DEBUGASSERT(data);
3949
0
  DEBUGASSERT(data->multi);
3950
0
  DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
3951
0
  data->multi->xfer_ulbuf_borrowed = FALSE;
3952
0
}
3953
3954
CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
3955
                                        size_t blen, char **pbuf)
3956
0
{
3957
0
  DEBUGASSERT(data);
3958
0
  DEBUGASSERT(data->multi);
3959
0
  *pbuf = NULL;
3960
0
  if(!data->multi) {
3961
0
    failf(data, "transfer has no multi handle");
3962
0
    return CURLE_FAILED_INIT;
3963
0
  }
3964
0
  if(data->multi->xfer_sockbuf_borrowed) {
3965
0
    failf(data, "attempt to borrow xfer_sockbuf when already borrowed");
3966
0
    return CURLE_AGAIN;
3967
0
  }
3968
3969
0
  if(data->multi->xfer_sockbuf && blen > data->multi->xfer_sockbuf_len) {
3970
    /* not large enough, get a new one */
3971
0
    free(data->multi->xfer_sockbuf);
3972
0
    data->multi->xfer_sockbuf = NULL;
3973
0
    data->multi->xfer_sockbuf_len = 0;
3974
0
  }
3975
3976
0
  if(!data->multi->xfer_sockbuf) {
3977
0
    data->multi->xfer_sockbuf = malloc(blen);
3978
0
    if(!data->multi->xfer_sockbuf) {
3979
0
      failf(data, "could not allocate xfer_sockbuf of %zu bytes", blen);
3980
0
      return CURLE_OUT_OF_MEMORY;
3981
0
    }
3982
0
    data->multi->xfer_sockbuf_len = blen;
3983
0
  }
3984
3985
0
  data->multi->xfer_sockbuf_borrowed = TRUE;
3986
0
  *pbuf = data->multi->xfer_sockbuf;
3987
0
  return CURLE_OK;
3988
0
}
3989
3990
void Curl_multi_xfer_sockbuf_release(struct Curl_easy *data, char *buf)
3991
0
{
3992
0
  (void)buf;
3993
0
  DEBUGASSERT(data);
3994
0
  DEBUGASSERT(data->multi);
3995
0
  DEBUGASSERT(!buf || data->multi->xfer_sockbuf == buf);
3996
0
  data->multi->xfer_sockbuf_borrowed = FALSE;
3997
0
}
3998
3999
static void multi_xfer_bufs_free(struct Curl_multi *multi)
4000
0
{
4001
0
  DEBUGASSERT(multi);
4002
0
  Curl_safefree(multi->xfer_buf);
4003
0
  multi->xfer_buf_len = 0;
4004
0
  multi->xfer_buf_borrowed = FALSE;
4005
0
  Curl_safefree(multi->xfer_ulbuf);
4006
0
  multi->xfer_ulbuf_len = 0;
4007
0
  multi->xfer_ulbuf_borrowed = FALSE;
4008
0
  Curl_safefree(multi->xfer_sockbuf);
4009
0
  multi->xfer_sockbuf_len = 0;
4010
0
  multi->xfer_sockbuf_borrowed = FALSE;
4011
0
}
4012
4013
struct Curl_easy *Curl_multi_get_easy(struct Curl_multi *multi,
4014
                                      unsigned int mid)
4015
0
{
4016
0
  struct Curl_easy *data = mid ? Curl_uint_tbl_get(&multi->xfers, mid) : NULL;
4017
0
  if(data && GOOD_EASY_HANDLE(data))
4018
0
    return data;
4019
0
  CURL_TRC_M(multi->admin, "invalid easy handle in xfer table for mid=%u",
4020
0
             mid);
4021
0
  Curl_uint_tbl_remove(&multi->xfers, mid);
4022
0
  return NULL;
4023
0
}
4024
4025
unsigned int Curl_multi_xfers_running(struct Curl_multi *multi)
4026
0
{
4027
0
  return multi->xfers_alive;
4028
0
}
4029
4030
void Curl_multi_mark_dirty(struct Curl_easy *data)
4031
0
{
4032
0
  if(data->multi && data->mid != UINT_MAX)
4033
0
    Curl_uint_bset_add(&data->multi->dirty, data->mid);
4034
0
}
4035
4036
void Curl_multi_clear_dirty(struct Curl_easy *data)
4037
0
{
4038
0
  if(data->multi && data->mid != UINT_MAX)
4039
0
    Curl_uint_bset_remove(&data->multi->dirty, data->mid);
4040
0
}
4041
4042
CURLMcode curl_multi_notify_enable(CURLM *m, unsigned int notification)
4043
0
{
4044
0
  struct Curl_multi *multi = m;
4045
4046
0
  if(!GOOD_MULTI_HANDLE(multi))
4047
0
    return CURLM_BAD_HANDLE;
4048
0
  return Curl_mntfy_enable(multi, notification);
4049
0
}
4050
4051
CURLMcode curl_multi_notify_disable(CURLM *m, unsigned int notification)
4052
0
{
4053
0
  struct Curl_multi *multi = m;
4054
4055
0
  if(!GOOD_MULTI_HANDLE(multi))
4056
0
    return CURLM_BAD_HANDLE;
4057
0
  return Curl_mntfy_disable(multi, notification);
4058
0
}
4059
4060
#ifdef DEBUGBUILD
4061
static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid,
4062
                            void *entry)
4063
{
4064
  struct Curl_easy *data = entry;
4065
4066
  (void)multi;
4067
  if(!data) {
4068
    curl_mfprintf(stderr, "mid=%u, entry=NULL, bug in xfer table?\n", mid);
4069
  }
4070
  else {
4071
    curl_mfprintf(stderr, "mid=%u, magic=%s, p=%p, id=%" FMT_OFF_T
4072
                  ", url=%s\n",
4073
                  mid,
4074
                  (data->magic == CURLEASY_MAGIC_NUMBER) ? "GOOD" : "BAD!",
4075
                  (void *)data, data->id, data->state.url);
4076
  }
4077
}
4078
4079
static void multi_xfer_tbl_dump(struct Curl_multi *multi)
4080
{
4081
  unsigned int mid;
4082
  void *entry;
4083
  curl_mfprintf(stderr, "=== multi xfer table (count=%u, capacity=%u\n",
4084
                Curl_uint_tbl_count(&multi->xfers),
4085
                Curl_uint_tbl_capacity(&multi->xfers));
4086
  if(Curl_uint_tbl_first(&multi->xfers, &mid, &entry)) {
4087
    multi_xfer_dump(multi, mid, entry);
4088
    while(Curl_uint_tbl_next(&multi->xfers, mid, &mid, &entry))
4089
      multi_xfer_dump(multi, mid, entry);
4090
  }
4091
  curl_mfprintf(stderr, "===\n");
4092
  fflush(stderr);
4093
}
4094
#endif /* DEBUGBUILD */