Coverage Report

Created: 2023-12-08 06:48

/src/curl/lib/easy.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
#ifdef HAVE_NETINET_IN_H
28
#include <netinet/in.h>
29
#endif
30
#ifdef HAVE_NETDB_H
31
#include <netdb.h>
32
#endif
33
#ifdef HAVE_ARPA_INET_H
34
#include <arpa/inet.h>
35
#endif
36
#ifdef HAVE_NET_IF_H
37
#include <net/if.h>
38
#endif
39
#ifdef HAVE_SYS_IOCTL_H
40
#include <sys/ioctl.h>
41
#endif
42
43
#ifdef HAVE_SYS_PARAM_H
44
#include <sys/param.h>
45
#endif
46
47
#include "urldata.h"
48
#include <curl/curl.h>
49
#include "transfer.h"
50
#include "vtls/vtls.h"
51
#include "url.h"
52
#include "getinfo.h"
53
#include "hostip.h"
54
#include "share.h"
55
#include "strdup.h"
56
#include "progress.h"
57
#include "easyif.h"
58
#include "multiif.h"
59
#include "select.h"
60
#include "cfilters.h"
61
#include "sendf.h" /* for failf function prototype */
62
#include "connect.h" /* for Curl_getconnectinfo */
63
#include "slist.h"
64
#include "mime.h"
65
#include "amigaos.h"
66
#include "macos.h"
67
#include "warnless.h"
68
#include "sigpipe.h"
69
#include "vssh/ssh.h"
70
#include "setopt.h"
71
#include "http_digest.h"
72
#include "system_win32.h"
73
#include "http2.h"
74
#include "dynbuf.h"
75
#include "altsvc.h"
76
#include "hsts.h"
77
78
#include "easy_lock.h"
79
80
/* The last 3 #include files should be in this order */
81
#include "curl_printf.h"
82
#include "curl_memory.h"
83
#include "memdebug.h"
84
85
/* true globals -- for curl_global_init() and curl_global_cleanup() */
86
static unsigned int  initialized;
87
static long          easy_init_flags;
88
89
#ifdef GLOBAL_INIT_IS_THREADSAFE
90
91
static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
92
1.17k
#define global_init_lock() curl_simple_lock_lock(&s_lock)
93
1.17k
#define global_init_unlock() curl_simple_lock_unlock(&s_lock)
94
95
#else
96
97
#define global_init_lock()
98
#define global_init_unlock()
99
100
#endif
101
102
/*
103
 * strdup (and other memory functions) is redefined in complicated
104
 * ways, but at this point it must be defined as the system-supplied strdup
105
 * so the callback pointer is initialized correctly.
106
 */
107
#if defined(_WIN32_WCE)
108
#define system_strdup _strdup
109
#elif !defined(HAVE_STRDUP)
110
#define system_strdup Curl_strdup
111
#else
112
1
#define system_strdup strdup
113
#endif
114
115
#if defined(_MSC_VER) && defined(_DLL)
116
#  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
117
#endif
118
119
/*
120
 * If a memory-using function (like curl_getenv) is used before
121
 * curl_global_init() is called, we need to have these pointers set already.
122
 */
123
curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
124
curl_free_callback Curl_cfree = (curl_free_callback)free;
125
curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
126
curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
127
curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
128
#if defined(_WIN32) && defined(UNICODE)
129
curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
130
#endif
131
132
#if defined(_MSC_VER) && defined(_DLL)
133
#  pragma warning(default:4232) /* MSVC extension, dllimport identity */
134
#endif
135
136
#ifdef DEBUGBUILD
137
static char *leakpointer;
138
#endif
139
140
/**
141
 * curl_global_init() globally initializes curl given a bitwise set of the
142
 * different features of what to initialize.
143
 */
144
static CURLcode global_init(long flags, bool memoryfuncs)
145
1
{
146
1
  if(initialized++)
147
0
    return CURLE_OK;
148
149
1
  if(memoryfuncs) {
150
    /* Setup the default memory functions here (again) */
151
1
    Curl_cmalloc = (curl_malloc_callback)malloc;
152
1
    Curl_cfree = (curl_free_callback)free;
153
1
    Curl_crealloc = (curl_realloc_callback)realloc;
154
1
    Curl_cstrdup = (curl_strdup_callback)system_strdup;
155
1
    Curl_ccalloc = (curl_calloc_callback)calloc;
156
#if defined(_WIN32) && defined(UNICODE)
157
    Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
158
#endif
159
1
  }
160
161
1
  if(Curl_trc_init()) {
162
0
    DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n"));
163
0
    goto fail;
164
0
  }
165
166
1
  if(!Curl_ssl_init()) {
167
0
    DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
168
0
    goto fail;
169
0
  }
170
171
1
  if(Curl_win32_init(flags)) {
172
0
    DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
173
0
    goto fail;
174
0
  }
175
176
1
  if(Curl_amiga_init()) {
177
0
    DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
178
0
    goto fail;
179
0
  }
180
181
1
  if(Curl_macos_init()) {
182
0
    DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n"));
183
0
    goto fail;
184
0
  }
185
186
1
  if(Curl_resolver_global_init()) {
187
0
    DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
188
0
    goto fail;
189
0
  }
190
191
1
  if(Curl_ssh_init()) {
192
0
    DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n"));
193
0
    goto fail;
194
0
  }
195
196
1
  easy_init_flags = flags;
197
198
1
#ifdef DEBUGBUILD
199
1
  if(getenv("CURL_GLOBAL_INIT"))
200
    /* alloc data that will leak if *cleanup() is not called! */
201
0
    leakpointer = malloc(1);
202
1
#endif
203
204
1
  return CURLE_OK;
205
206
0
fail:
207
0
  initialized--; /* undo the increase */
208
0
  return CURLE_FAILED_INIT;
209
1
}
210
211
212
/**
213
 * curl_global_init() globally initializes curl given a bitwise set of the
214
 * different features of what to initialize.
215
 */
216
CURLcode curl_global_init(long flags)
217
0
{
218
0
  CURLcode result;
219
0
  global_init_lock();
220
221
0
  result = global_init(flags, TRUE);
222
223
0
  global_init_unlock();
224
225
0
  return result;
226
0
}
227
228
/*
229
 * curl_global_init_mem() globally initializes curl and also registers the
230
 * user provided callback routines.
231
 */
232
CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
233
                              curl_free_callback f, curl_realloc_callback r,
234
                              curl_strdup_callback s, curl_calloc_callback c)
235
0
{
236
0
  CURLcode result;
237
238
  /* Invalid input, return immediately */
239
0
  if(!m || !f || !r || !s || !c)
240
0
    return CURLE_FAILED_INIT;
241
242
0
  global_init_lock();
243
244
0
  if(initialized) {
245
    /* Already initialized, don't do it again, but bump the variable anyway to
246
       work like curl_global_init() and require the same amount of cleanup
247
       calls. */
248
0
    initialized++;
249
0
    global_init_unlock();
250
0
    return CURLE_OK;
251
0
  }
252
253
  /* set memory functions before global_init() in case it wants memory
254
     functions */
255
0
  Curl_cmalloc = m;
256
0
  Curl_cfree = f;
257
0
  Curl_cstrdup = s;
258
0
  Curl_crealloc = r;
259
0
  Curl_ccalloc = c;
260
261
  /* Call the actual init function, but without setting */
262
0
  result = global_init(flags, FALSE);
263
264
0
  global_init_unlock();
265
266
0
  return result;
267
0
}
268
269
/**
270
 * curl_global_cleanup() globally cleanups curl, uses the value of
271
 * "easy_init_flags" to determine what needs to be cleaned up and what doesn't.
272
 */
273
void curl_global_cleanup(void)
274
0
{
275
0
  global_init_lock();
276
277
0
  if(!initialized) {
278
0
    global_init_unlock();
279
0
    return;
280
0
  }
281
282
0
  if(--initialized) {
283
0
    global_init_unlock();
284
0
    return;
285
0
  }
286
287
0
  Curl_ssl_cleanup();
288
0
  Curl_resolver_global_cleanup();
289
290
#ifdef _WIN32
291
  Curl_win32_cleanup(easy_init_flags);
292
#endif
293
294
0
  Curl_amiga_cleanup();
295
296
0
  Curl_ssh_cleanup();
297
298
0
#ifdef DEBUGBUILD
299
0
  free(leakpointer);
300
0
#endif
301
302
0
  easy_init_flags = 0;
303
304
0
  global_init_unlock();
305
0
}
306
307
/**
308
 * curl_global_trace() globally initializes curl logging.
309
 */
310
CURLcode curl_global_trace(const char *config)
311
0
{
312
0
#ifndef CURL_DISABLE_VERBOSE_STRINGS
313
0
  CURLcode result;
314
0
  global_init_lock();
315
316
0
  result = Curl_trc_opt(config);
317
318
0
  global_init_unlock();
319
320
0
  return result;
321
#else
322
  (void)config;
323
  return CURLE_OK;
324
#endif
325
0
}
326
327
/*
328
 * curl_global_sslset() globally initializes the SSL backend to use.
329
 */
330
CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
331
                              const curl_ssl_backend ***avail)
332
0
{
333
0
  CURLsslset rc;
334
335
0
  global_init_lock();
336
337
0
  rc = Curl_init_sslset_nolock(id, name, avail);
338
339
0
  global_init_unlock();
340
341
0
  return rc;
342
0
}
343
344
/*
345
 * curl_easy_init() is the external interface to alloc, setup and init an
346
 * easy handle that is returned. If anything goes wrong, NULL is returned.
347
 */
348
struct Curl_easy *curl_easy_init(void)
349
1.17k
{
350
1.17k
  CURLcode result;
351
1.17k
  struct Curl_easy *data;
352
353
  /* Make sure we inited the global SSL stuff */
354
1.17k
  global_init_lock();
355
356
1.17k
  if(!initialized) {
357
1
    result = global_init(CURL_GLOBAL_DEFAULT, TRUE);
358
1
    if(result) {
359
      /* something in the global init failed, return nothing */
360
0
      DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
361
0
      global_init_unlock();
362
0
      return NULL;
363
0
    }
364
1
  }
365
1.17k
  global_init_unlock();
366
367
  /* We use curl_open() with undefined URL so far */
368
1.17k
  result = Curl_open(&data);
369
1.17k
  if(result) {
370
0
    DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
371
0
    return NULL;
372
0
  }
373
374
1.17k
  return data;
375
1.17k
}
376
377
#ifdef CURLDEBUG
378
379
struct socketmonitor {
380
  struct socketmonitor *next; /* the next node in the list or NULL */
381
  struct pollfd socket; /* socket info of what to monitor */
382
};
383
384
struct events {
385
  long ms;              /* timeout, run the timeout function when reached */
386
  bool msbump;          /* set TRUE when timeout is set by callback */
387
  int num_sockets;      /* number of nodes in the monitor list */
388
  struct socketmonitor *list; /* list of sockets to monitor */
389
  int running_handles;  /* store the returned number */
390
};
391
392
/* events_timer
393
 *
394
 * Callback that gets called with a new value when the timeout should be
395
 * updated.
396
 */
397
398
static int events_timer(struct Curl_multi *multi,    /* multi handle */
399
                        long timeout_ms, /* see above */
400
                        void *userp)    /* private callback pointer */
401
0
{
402
0
  struct events *ev = userp;
403
0
  (void)multi;
404
0
  if(timeout_ms == -1)
405
    /* timeout removed */
406
0
    timeout_ms = 0;
407
0
  else if(timeout_ms == 0)
408
    /* timeout is already reached! */
409
0
    timeout_ms = 1; /* trigger asap */
410
411
0
  ev->ms = timeout_ms;
412
0
  ev->msbump = TRUE;
413
0
  return 0;
414
0
}
415
416
417
/* poll2cselect
418
 *
419
 * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
420
 */
421
static int poll2cselect(int pollmask)
422
0
{
423
0
  int omask = 0;
424
0
  if(pollmask & POLLIN)
425
0
    omask |= CURL_CSELECT_IN;
426
0
  if(pollmask & POLLOUT)
427
0
    omask |= CURL_CSELECT_OUT;
428
0
  if(pollmask & POLLERR)
429
0
    omask |= CURL_CSELECT_ERR;
430
0
  return omask;
431
0
}
432
433
434
/* socketcb2poll
435
 *
436
 * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
437
 */
438
static short socketcb2poll(int pollmask)
439
0
{
440
0
  short omask = 0;
441
0
  if(pollmask & CURL_POLL_IN)
442
0
    omask |= POLLIN;
443
0
  if(pollmask & CURL_POLL_OUT)
444
0
    omask |= POLLOUT;
445
0
  return omask;
446
0
}
447
448
/* events_socket
449
 *
450
 * Callback that gets called with information about socket activity to
451
 * monitor.
452
 */
453
static int events_socket(struct Curl_easy *easy,      /* easy handle */
454
                         curl_socket_t s, /* socket */
455
                         int what,        /* see above */
456
                         void *userp,     /* private callback
457
                                             pointer */
458
                         void *socketp)   /* private socket
459
                                             pointer */
460
0
{
461
0
  struct events *ev = userp;
462
0
  struct socketmonitor *m;
463
0
  struct socketmonitor *prev = NULL;
464
465
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
466
  (void) easy;
467
#endif
468
0
  (void)socketp;
469
470
0
  m = ev->list;
471
0
  while(m) {
472
0
    if(m->socket.fd == s) {
473
474
0
      if(what == CURL_POLL_REMOVE) {
475
0
        struct socketmonitor *nxt = m->next;
476
        /* remove this node from the list of monitored sockets */
477
0
        if(prev)
478
0
          prev->next = nxt;
479
0
        else
480
0
          ev->list = nxt;
481
0
        free(m);
482
0
        m = nxt;
483
0
        infof(easy, "socket cb: socket %d REMOVED", s);
484
0
      }
485
0
      else {
486
        /* The socket 's' is already being monitored, update the activity
487
           mask. Convert from libcurl bitmask to the poll one. */
488
0
        m->socket.events = socketcb2poll(what);
489
0
        infof(easy, "socket cb: socket %d UPDATED as %s%s", s,
490
0
              (what&CURL_POLL_IN)?"IN":"",
491
0
              (what&CURL_POLL_OUT)?"OUT":"");
492
0
      }
493
0
      break;
494
0
    }
495
0
    prev = m;
496
0
    m = m->next; /* move to next node */
497
0
  }
498
0
  if(!m) {
499
0
    if(what == CURL_POLL_REMOVE) {
500
      /* this happens a bit too often, libcurl fix perhaps? */
501
      /* fprintf(stderr,
502
         "%s: socket %d asked to be REMOVED but not present!\n",
503
                 __func__, s); */
504
0
    }
505
0
    else {
506
0
      m = malloc(sizeof(struct socketmonitor));
507
0
      if(m) {
508
0
        m->next = ev->list;
509
0
        m->socket.fd = s;
510
0
        m->socket.events = socketcb2poll(what);
511
0
        m->socket.revents = 0;
512
0
        ev->list = m;
513
0
        infof(easy, "socket cb: socket %d ADDED as %s%s", s,
514
0
              (what&CURL_POLL_IN)?"IN":"",
515
0
              (what&CURL_POLL_OUT)?"OUT":"");
516
0
      }
517
0
      else
518
0
        return CURLE_OUT_OF_MEMORY;
519
0
    }
520
0
  }
521
522
0
  return 0;
523
0
}
524
525
526
/*
527
 * events_setup()
528
 *
529
 * Do the multi handle setups that only event-based transfers need.
530
 */
531
static void events_setup(struct Curl_multi *multi, struct events *ev)
532
0
{
533
  /* timer callback */
534
0
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
535
0
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
536
537
  /* socket callback */
538
0
  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
539
0
  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
540
0
}
541
542
543
/* wait_or_timeout()
544
 *
545
 * waits for activity on any of the given sockets, or the timeout to trigger.
546
 */
547
548
static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
549
0
{
550
0
  bool done = FALSE;
551
0
  CURLMcode mcode = CURLM_OK;
552
0
  CURLcode result = CURLE_OK;
553
554
0
  while(!done) {
555
0
    CURLMsg *msg;
556
0
    struct socketmonitor *m;
557
0
    struct pollfd *f;
558
0
    struct pollfd fds[4];
559
0
    int numfds = 0;
560
0
    int pollrc;
561
0
    int i;
562
0
    struct curltime before;
563
0
    struct curltime after;
564
565
    /* populate the fds[] array */
566
0
    for(m = ev->list, f = &fds[0]; m; m = m->next) {
567
0
      f->fd = m->socket.fd;
568
0
      f->events = m->socket.events;
569
0
      f->revents = 0;
570
      /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
571
0
      f++;
572
0
      numfds++;
573
0
    }
574
575
    /* get the time stamp to use to figure out how long poll takes */
576
0
    before = Curl_now();
577
578
    /* wait for activity or timeout */
579
0
    pollrc = Curl_poll(fds, numfds, ev->ms);
580
0
    if(pollrc < 0)
581
0
      return CURLE_UNRECOVERABLE_POLL;
582
583
0
    after = Curl_now();
584
585
0
    ev->msbump = FALSE; /* reset here */
586
587
0
    if(!pollrc) {
588
      /* timeout! */
589
0
      ev->ms = 0;
590
      /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
591
0
      mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
592
0
                                       &ev->running_handles);
593
0
    }
594
0
    else {
595
      /* here pollrc is > 0 */
596
597
      /* loop over the monitored sockets to see which ones had activity */
598
0
      for(i = 0; i< numfds; i++) {
599
0
        if(fds[i].revents) {
600
          /* socket activity, tell libcurl */
601
0
          int act = poll2cselect(fds[i].revents); /* convert */
602
0
          infof(multi->easyp, "call curl_multi_socket_action(socket %d)",
603
0
                fds[i].fd);
604
0
          mcode = curl_multi_socket_action(multi, fds[i].fd, act,
605
0
                                           &ev->running_handles);
606
0
        }
607
0
      }
608
609
0
      if(!ev->msbump) {
610
        /* If nothing updated the timeout, we decrease it by the spent time.
611
         * If it was updated, it has the new timeout time stored already.
612
         */
613
0
        timediff_t timediff = Curl_timediff(after, before);
614
0
        if(timediff > 0) {
615
0
          if(timediff > ev->ms)
616
0
            ev->ms = 0;
617
0
          else
618
0
            ev->ms -= (long)timediff;
619
0
        }
620
0
      }
621
0
    }
622
623
0
    if(mcode)
624
0
      return CURLE_URL_MALFORMAT;
625
626
    /* we don't really care about the "msgs_in_queue" value returned in the
627
       second argument */
628
0
    msg = curl_multi_info_read(multi, &pollrc);
629
0
    if(msg) {
630
0
      result = msg->data.result;
631
0
      done = TRUE;
632
0
    }
633
0
  }
634
635
0
  return result;
636
0
}
637
638
639
/* easy_events()
640
 *
641
 * Runs a transfer in a blocking manner using the events-based API
642
 */
643
static CURLcode easy_events(struct Curl_multi *multi)
644
0
{
645
  /* this struct is made static to allow it to be used after this function
646
     returns and curl_multi_remove_handle() is called */
647
0
  static struct events evs = {2, FALSE, 0, NULL, 0};
648
649
  /* if running event-based, do some further multi inits */
650
0
  events_setup(multi, &evs);
651
652
0
  return wait_or_timeout(multi, &evs);
653
0
}
654
#else /* CURLDEBUG */
655
/* when not built with debug, this function doesn't exist */
656
#define easy_events(x) CURLE_NOT_BUILT_IN
657
#endif
658
659
static CURLcode easy_transfer(struct Curl_multi *multi)
660
0
{
661
0
  bool done = FALSE;
662
0
  CURLMcode mcode = CURLM_OK;
663
0
  CURLcode result = CURLE_OK;
664
665
0
  while(!done && !mcode) {
666
0
    int still_running = 0;
667
668
0
    mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
669
670
0
    if(!mcode)
671
0
      mcode = curl_multi_perform(multi, &still_running);
672
673
    /* only read 'still_running' if curl_multi_perform() return OK */
674
0
    if(!mcode && !still_running) {
675
0
      int rc;
676
0
      CURLMsg *msg = curl_multi_info_read(multi, &rc);
677
0
      if(msg) {
678
0
        result = msg->data.result;
679
0
        done = TRUE;
680
0
      }
681
0
    }
682
0
  }
683
684
  /* Make sure to return some kind of error if there was a multi problem */
685
0
  if(mcode) {
686
0
    result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
687
              /* The other multi errors should never happen, so return
688
                 something suitably generic */
689
0
              CURLE_BAD_FUNCTION_ARGUMENT;
690
0
  }
691
692
0
  return result;
693
0
}
694
695
696
/*
697
 * easy_perform() is the external interface that performs a blocking
698
 * transfer as previously setup.
699
 *
700
 * CONCEPT: This function creates a multi handle, adds the easy handle to it,
701
 * runs curl_multi_perform() until the transfer is done, then detaches the
702
 * easy handle, destroys the multi handle and returns the easy handle's return
703
 * code.
704
 *
705
 * REALITY: it can't just create and destroy the multi handle that easily. It
706
 * needs to keep it around since if this easy handle is used again by this
707
 * function, the same multi handle must be reused so that the same pools and
708
 * caches can be used.
709
 *
710
 * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
711
 * instead of curl_multi_perform() and use curl_multi_socket_action().
712
 */
713
static CURLcode easy_perform(struct Curl_easy *data, bool events)
714
0
{
715
0
  struct Curl_multi *multi;
716
0
  CURLMcode mcode;
717
0
  CURLcode result = CURLE_OK;
718
0
  SIGPIPE_VARIABLE(pipe_st);
719
720
0
  if(!data)
721
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
722
723
0
  if(data->set.errorbuffer)
724
    /* clear this as early as possible */
725
0
    data->set.errorbuffer[0] = 0;
726
727
0
  if(data->multi) {
728
0
    failf(data, "easy handle already used in multi handle");
729
0
    return CURLE_FAILED_INIT;
730
0
  }
731
732
0
  if(data->multi_easy)
733
0
    multi = data->multi_easy;
734
0
  else {
735
    /* this multi handle will only ever have a single easy handled attached
736
       to it, so make it use minimal hashes */
737
0
    multi = Curl_multi_handle(1, 3, 7);
738
0
    if(!multi)
739
0
      return CURLE_OUT_OF_MEMORY;
740
0
    data->multi_easy = multi;
741
0
  }
742
743
0
  if(multi->in_callback)
744
0
    return CURLE_RECURSIVE_API_CALL;
745
746
  /* Copy the MAXCONNECTS option to the multi handle */
747
0
  curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects);
748
749
0
  mcode = curl_multi_add_handle(multi, data);
750
0
  if(mcode) {
751
0
    curl_multi_cleanup(multi);
752
0
    data->multi_easy = NULL;
753
0
    if(mcode == CURLM_OUT_OF_MEMORY)
754
0
      return CURLE_OUT_OF_MEMORY;
755
0
    return CURLE_FAILED_INIT;
756
0
  }
757
758
0
  sigpipe_ignore(data, &pipe_st);
759
760
  /* run the transfer */
761
0
  result = events ? easy_events(multi) : easy_transfer(multi);
762
763
  /* ignoring the return code isn't nice, but atm we can't really handle
764
     a failure here, room for future improvement! */
765
0
  (void)curl_multi_remove_handle(multi, data);
766
767
0
  sigpipe_restore(&pipe_st);
768
769
  /* The multi handle is kept alive, owned by the easy handle */
770
0
  return result;
771
0
}
772
773
774
/*
775
 * curl_easy_perform() is the external interface that performs a blocking
776
 * transfer as previously setup.
777
 */
778
CURLcode curl_easy_perform(struct Curl_easy *data)
779
0
{
780
0
  return easy_perform(data, FALSE);
781
0
}
782
783
#ifdef CURLDEBUG
784
/*
785
 * curl_easy_perform_ev() is the external interface that performs a blocking
786
 * transfer using the event-based API internally.
787
 */
788
CURLcode curl_easy_perform_ev(struct Curl_easy *data)
789
0
{
790
0
  return easy_perform(data, TRUE);
791
0
}
792
793
#endif
794
795
/*
796
 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
797
 * easy handle.
798
 */
799
void curl_easy_cleanup(struct Curl_easy *data)
800
1.17k
{
801
1.17k
  if(GOOD_EASY_HANDLE(data)) {
802
1.17k
    SIGPIPE_VARIABLE(pipe_st);
803
1.17k
    sigpipe_ignore(data, &pipe_st);
804
1.17k
    Curl_close(&data);
805
1.17k
    sigpipe_restore(&pipe_st);
806
1.17k
  }
807
1.17k
}
808
809
/*
810
 * curl_easy_getinfo() is an external interface that allows an app to retrieve
811
 * information from a performed transfer and similar.
812
 */
813
#undef curl_easy_getinfo
814
CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
815
0
{
816
0
  va_list arg;
817
0
  void *paramp;
818
0
  CURLcode result;
819
820
0
  va_start(arg, info);
821
0
  paramp = va_arg(arg, void *);
822
823
0
  result = Curl_getinfo(data, info, paramp);
824
825
0
  va_end(arg);
826
0
  return result;
827
0
}
828
829
static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
830
0
{
831
0
  CURLcode result = CURLE_OK;
832
0
  enum dupstring i;
833
0
  enum dupblob j;
834
835
  /* Copy src->set into dst->set first, then deal with the strings
836
     afterwards */
837
0
  dst->set = src->set;
838
0
  Curl_mime_initpart(&dst->set.mimepost);
839
840
  /* clear all dest string and blob pointers first, in case we error out
841
     mid-function */
842
0
  memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
843
0
  memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
844
845
  /* duplicate all strings */
846
0
  for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
847
0
    result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
848
0
    if(result)
849
0
      return result;
850
0
  }
851
852
  /* duplicate all blobs */
853
0
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
854
0
    result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
855
0
    if(result)
856
0
      return result;
857
0
  }
858
859
  /* duplicate memory areas pointed to */
860
0
  i = STRING_COPYPOSTFIELDS;
861
0
  if(src->set.str[i]) {
862
0
    if(src->set.postfieldsize == -1)
863
0
      dst->set.str[i] = strdup(src->set.str[i]);
864
0
    else
865
      /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
866
0
      dst->set.str[i] = Curl_memdup(src->set.str[i],
867
0
                                    curlx_sotouz(src->set.postfieldsize));
868
0
    if(!dst->set.str[i])
869
0
      return CURLE_OUT_OF_MEMORY;
870
    /* point to the new copy */
871
0
    dst->set.postfields = dst->set.str[i];
872
0
  }
873
874
  /* Duplicate mime data. */
875
0
  result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost);
876
877
0
  if(src->set.resolve)
878
0
    dst->state.resolve = dst->set.resolve;
879
880
0
  return result;
881
0
}
882
883
/*
884
 * curl_easy_duphandle() is an external interface to allow duplication of a
885
 * given input easy handle. The returned handle will be a new working handle
886
 * with all options set exactly as the input source handle.
887
 */
888
struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
889
0
{
890
0
  struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
891
0
  if(!outcurl)
892
0
    goto fail;
893
894
  /*
895
   * We setup a few buffers we need. We should probably make them
896
   * get setup on-demand in the code, as that would probably decrease
897
   * the likeliness of us forgetting to init a buffer here in the future.
898
   */
899
0
  outcurl->set.buffer_size = data->set.buffer_size;
900
901
  /* copy all userdefined values */
902
0
  if(dupset(outcurl, data))
903
0
    goto fail;
904
905
0
  Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
906
907
  /* the connection cache is setup on demand */
908
0
  outcurl->state.conn_cache = NULL;
909
0
  outcurl->state.lastconnect_id = -1;
910
0
  outcurl->state.recent_conn_id = -1;
911
0
  outcurl->id = -1;
912
913
0
  outcurl->progress.flags    = data->progress.flags;
914
0
  outcurl->progress.callback = data->progress.callback;
915
916
0
#ifndef CURL_DISABLE_COOKIES
917
0
  outcurl->state.cookielist = NULL;
918
0
  if(data->cookies && data->state.cookie_engine) {
919
    /* If cookies are enabled in the parent handle, we enable them
920
       in the clone as well! */
921
0
    outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies,
922
0
                                        data->set.cookiesession);
923
0
    if(!outcurl->cookies)
924
0
      goto fail;
925
0
  }
926
927
0
  if(data->state.cookielist) {
928
0
    outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
929
0
    if(!outcurl->state.cookielist)
930
0
      goto fail;
931
0
  }
932
0
#endif
933
934
0
  if(data->state.url) {
935
0
    outcurl->state.url = strdup(data->state.url);
936
0
    if(!outcurl->state.url)
937
0
      goto fail;
938
0
    outcurl->state.url_alloc = TRUE;
939
0
  }
940
941
0
  if(data->state.referer) {
942
0
    outcurl->state.referer = strdup(data->state.referer);
943
0
    if(!outcurl->state.referer)
944
0
      goto fail;
945
0
    outcurl->state.referer_alloc = TRUE;
946
0
  }
947
948
  /* Reinitialize an SSL engine for the new handle
949
   * note: the engine name has already been copied by dupset */
950
0
  if(outcurl->set.str[STRING_SSL_ENGINE]) {
951
0
    if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
952
0
      goto fail;
953
0
  }
954
955
0
#ifndef CURL_DISABLE_ALTSVC
956
0
  if(data->asi) {
957
0
    outcurl->asi = Curl_altsvc_init();
958
0
    if(!outcurl->asi)
959
0
      goto fail;
960
0
    if(outcurl->set.str[STRING_ALTSVC])
961
0
      (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
962
0
  }
963
0
#endif
964
#ifndef CURL_DISABLE_HSTS
965
  if(data->hsts) {
966
    outcurl->hsts = Curl_hsts_init();
967
    if(!outcurl->hsts)
968
      goto fail;
969
    if(outcurl->set.str[STRING_HSTS])
970
      (void)Curl_hsts_loadfile(outcurl,
971
                               outcurl->hsts, outcurl->set.str[STRING_HSTS]);
972
    (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
973
  }
974
#endif
975
976
0
  Curl_initinfo(outcurl);
977
978
0
  outcurl->magic = CURLEASY_MAGIC_NUMBER;
979
980
  /* we reach this point and thus we are OK */
981
982
0
  return outcurl;
983
984
0
fail:
985
986
0
  if(outcurl) {
987
0
#ifndef CURL_DISABLE_COOKIES
988
0
    free(outcurl->cookies);
989
0
#endif
990
0
    free(outcurl->state.buffer);
991
0
    Curl_dyn_free(&outcurl->state.headerb);
992
0
    Curl_altsvc_cleanup(&outcurl->asi);
993
0
    Curl_hsts_cleanup(&outcurl->hsts);
994
0
    Curl_freeset(outcurl);
995
0
    free(outcurl);
996
0
  }
997
998
0
  return NULL;
999
0
}
1000
1001
/*
1002
 * curl_easy_reset() is an external interface that allows an app to re-
1003
 * initialize a session handle to the default values.
1004
 */
1005
void curl_easy_reset(struct Curl_easy *data)
1006
0
{
1007
0
  Curl_free_request_state(data);
1008
1009
  /* zero out UserDefined data: */
1010
0
  Curl_freeset(data);
1011
0
  memset(&data->set, 0, sizeof(struct UserDefined));
1012
0
  (void)Curl_init_userdefined(data);
1013
1014
  /* zero out Progress data: */
1015
0
  memset(&data->progress, 0, sizeof(struct Progress));
1016
1017
  /* zero out PureInfo data: */
1018
0
  Curl_initinfo(data);
1019
1020
0
  data->progress.flags |= PGRS_HIDE;
1021
0
  data->state.current_speed = -1; /* init to negative == impossible */
1022
0
  data->state.retrycount = 0;     /* reset the retry counter */
1023
1024
  /* zero out authentication data: */
1025
0
  memset(&data->state.authhost, 0, sizeof(struct auth));
1026
0
  memset(&data->state.authproxy, 0, sizeof(struct auth));
1027
1028
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
1029
0
  Curl_http_auth_cleanup_digest(data);
1030
0
#endif
1031
0
}
1032
1033
/*
1034
 * curl_easy_pause() allows an application to pause or unpause a specific
1035
 * transfer and direction. This function sets the full new state for the
1036
 * current connection this easy handle operates on.
1037
 *
1038
 * NOTE: if you have the receiving paused and you call this function to remove
1039
 * the pausing, you may get your write callback called at this point.
1040
 *
1041
 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
1042
 *
1043
 * NOTE: This is one of few API functions that are allowed to be called from
1044
 * within a callback.
1045
 */
1046
CURLcode curl_easy_pause(struct Curl_easy *data, int action)
1047
0
{
1048
0
  struct SingleRequest *k;
1049
0
  CURLcode result = CURLE_OK;
1050
0
  int oldstate;
1051
0
  int newstate;
1052
0
  bool recursive = FALSE;
1053
1054
0
  if(!GOOD_EASY_HANDLE(data) || !data->conn)
1055
    /* crazy input, don't continue */
1056
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1057
1058
0
  if(Curl_is_in_callback(data))
1059
0
    recursive = TRUE;
1060
0
  k = &data->req;
1061
0
  oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
1062
1063
  /* first switch off both pause bits then set the new pause bits */
1064
0
  newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
1065
0
    ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
1066
0
    ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
1067
1068
0
  if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
1069
    /* Not changing any pause state, return */
1070
0
    DEBUGF(infof(data, "pause: no change, early return"));
1071
0
    return CURLE_OK;
1072
0
  }
1073
1074
  /* Unpause parts in active mime tree. */
1075
0
  if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
1076
0
     (data->mstate == MSTATE_PERFORMING ||
1077
0
      data->mstate == MSTATE_RATELIMITING) &&
1078
0
     data->state.fread_func == (curl_read_callback) Curl_mime_read) {
1079
0
    Curl_mime_unpause(data->state.in);
1080
0
  }
1081
1082
  /* put it back in the keepon */
1083
0
  k->keepon = newstate;
1084
1085
0
  if(!(newstate & KEEP_RECV_PAUSE)) {
1086
0
    Curl_conn_ev_data_pause(data, FALSE);
1087
0
    result = Curl_client_unpause(data);
1088
0
    if(result)
1089
0
      return result;
1090
0
  }
1091
1092
#ifdef USE_HYPER
1093
  if(!(newstate & KEEP_SEND_PAUSE)) {
1094
    /* need to wake the send body waker */
1095
    if(data->hyp.send_body_waker) {
1096
      hyper_waker_wake(data->hyp.send_body_waker);
1097
      data->hyp.send_body_waker = NULL;
1098
    }
1099
  }
1100
#endif
1101
1102
  /* if there's no error and we're not pausing both directions, we want
1103
     to have this handle checked soon */
1104
0
  if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
1105
0
     (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
1106
0
    Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
1107
1108
    /* reset the too-slow time keeper */
1109
0
    data->state.keeps_speed.tv_sec = 0;
1110
1111
0
    if(!data->state.tempcount)
1112
      /* if not pausing again, force a recv/send check of this connection as
1113
         the data might've been read off the socket already */
1114
0
      data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
1115
0
    if(data->multi) {
1116
0
      if(Curl_update_timer(data->multi))
1117
0
        return CURLE_ABORTED_BY_CALLBACK;
1118
0
    }
1119
0
  }
1120
1121
0
  if(!data->state.done)
1122
    /* This transfer may have been moved in or out of the bundle, update the
1123
       corresponding socket callback, if used */
1124
0
    result = Curl_updatesocket(data);
1125
1126
0
  if(recursive)
1127
    /* this might have called a callback recursively which might have set this
1128
       to false again on exit */
1129
0
    Curl_set_in_callback(data, TRUE);
1130
1131
0
  return result;
1132
0
}
1133
1134
1135
static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
1136
                                struct connectdata **connp)
1137
0
{
1138
0
  if(!data)
1139
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1140
1141
  /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1142
0
  if(!data->set.connect_only) {
1143
0
    failf(data, "CONNECT_ONLY is required");
1144
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1145
0
  }
1146
1147
0
  *sfd = Curl_getconnectinfo(data, connp);
1148
1149
0
  if(*sfd == CURL_SOCKET_BAD) {
1150
0
    failf(data, "Failed to get recent socket");
1151
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1152
0
  }
1153
1154
0
  return CURLE_OK;
1155
0
}
1156
1157
/*
1158
 * Receives data from the connected socket. Use after successful
1159
 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1160
 * Returns CURLE_OK on success, error code on error.
1161
 */
1162
CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
1163
                        size_t *n)
1164
0
{
1165
0
  curl_socket_t sfd;
1166
0
  CURLcode result;
1167
0
  ssize_t n1;
1168
0
  struct connectdata *c;
1169
1170
0
  if(Curl_is_in_callback(data))
1171
0
    return CURLE_RECURSIVE_API_CALL;
1172
1173
0
  result = easy_connection(data, &sfd, &c);
1174
0
  if(result)
1175
0
    return result;
1176
1177
0
  if(!data->conn)
1178
    /* on first invoke, the transfer has been detached from the connection and
1179
       needs to be reattached */
1180
0
    Curl_attach_connection(data, c);
1181
1182
0
  *n = 0;
1183
0
  result = Curl_read(data, sfd, buffer, buflen, &n1);
1184
1185
0
  if(result)
1186
0
    return result;
1187
1188
0
  *n = (size_t)n1;
1189
0
  return CURLE_OK;
1190
0
}
1191
1192
#ifdef USE_WEBSOCKETS
1193
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
1194
0
{
1195
0
  curl_socket_t sfd;
1196
0
  CURLcode result;
1197
0
  struct connectdata *c = NULL;
1198
1199
0
  result = easy_connection(data, &sfd, &c);
1200
0
  if(result)
1201
0
    return result;
1202
1203
0
  if(!data->conn)
1204
    /* on first invoke, the transfer has been detached from the connection and
1205
       needs to be reattached */
1206
0
    Curl_attach_connection(data, c);
1207
1208
0
  return CURLE_OK;
1209
0
}
1210
#endif /* USE_WEBSOCKETS */
1211
1212
/*
1213
 * Sends data over the connected socket.
1214
 *
1215
 * This is the private internal version of curl_easy_send()
1216
 */
1217
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
1218
                       size_t buflen, ssize_t *n)
1219
0
{
1220
0
  curl_socket_t sfd;
1221
0
  CURLcode result;
1222
0
  ssize_t n1;
1223
0
  struct connectdata *c = NULL;
1224
0
  SIGPIPE_VARIABLE(pipe_st);
1225
1226
0
  result = easy_connection(data, &sfd, &c);
1227
0
  if(result)
1228
0
    return result;
1229
1230
0
  if(!data->conn)
1231
    /* on first invoke, the transfer has been detached from the connection and
1232
       needs to be reattached */
1233
0
    Curl_attach_connection(data, c);
1234
1235
0
  *n = 0;
1236
0
  sigpipe_ignore(data, &pipe_st);
1237
0
  result = Curl_write(data, sfd, buffer, buflen, &n1);
1238
0
  sigpipe_restore(&pipe_st);
1239
1240
0
  if(n1 == -1)
1241
0
    return CURLE_SEND_ERROR;
1242
1243
  /* detect EAGAIN */
1244
0
  if(!result && !n1)
1245
0
    return CURLE_AGAIN;
1246
1247
0
  *n = n1;
1248
1249
0
  return result;
1250
0
}
1251
1252
/*
1253
 * Sends data over the connected socket. Use after successful
1254
 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1255
 */
1256
CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
1257
                        size_t buflen, size_t *n)
1258
0
{
1259
0
  ssize_t written = 0;
1260
0
  CURLcode result;
1261
0
  if(Curl_is_in_callback(data))
1262
0
    return CURLE_RECURSIVE_API_CALL;
1263
1264
0
  result = Curl_senddata(data, buffer, buflen, &written);
1265
0
  *n = (size_t)written;
1266
0
  return result;
1267
0
}
1268
1269
/*
1270
 * Wrapper to call functions in Curl_conncache_foreach()
1271
 *
1272
 * Returns always 0.
1273
 */
1274
static int conn_upkeep(struct Curl_easy *data,
1275
                       struct connectdata *conn,
1276
                       void *param)
1277
0
{
1278
0
  struct curltime *now = param;
1279
1280
0
  if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
1281
0
    return 0;
1282
1283
  /* briefly attach for action */
1284
0
  Curl_attach_connection(data, conn);
1285
0
  if(conn->handler->connection_check) {
1286
    /* Do a protocol-specific keepalive check on the connection. */
1287
0
    conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
1288
0
  }
1289
0
  else {
1290
    /* Do the generic action on the FIRSTSOCKE filter chain */
1291
0
    Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
1292
0
  }
1293
0
  Curl_detach_connection(data);
1294
1295
0
  conn->keepalive = *now;
1296
0
  return 0; /* continue iteration */
1297
0
}
1298
1299
static CURLcode upkeep(struct conncache *conn_cache, void *data)
1300
0
{
1301
0
  struct curltime now = Curl_now();
1302
  /* Loop over every connection and make connection alive. */
1303
0
  Curl_conncache_foreach(data,
1304
0
                         conn_cache,
1305
0
                         &now,
1306
0
                         conn_upkeep);
1307
0
  return CURLE_OK;
1308
0
}
1309
1310
/*
1311
 * Performs connection upkeep for the given session handle.
1312
 */
1313
CURLcode curl_easy_upkeep(struct Curl_easy *data)
1314
0
{
1315
  /* Verify that we got an easy handle we can work with. */
1316
0
  if(!GOOD_EASY_HANDLE(data))
1317
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1318
1319
0
  if(data->multi_easy) {
1320
    /* Use the common function to keep connections alive. */
1321
0
    return upkeep(&data->multi_easy->conn_cache, data);
1322
0
  }
1323
0
  else {
1324
    /* No connections, so just return success */
1325
0
    return CURLE_OK;
1326
0
  }
1327
0
}