Coverage Report

Created: 2025-07-11 06:33

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