Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/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
0
#define global_init_lock() curl_simple_lock_lock(&s_lock)
93
0
#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
0
#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
0
{
146
0
  if(initialized++)
147
0
    return CURLE_OK;
148
149
0
  if(memoryfuncs) {
150
    /* Setup the default memory functions here (again) */
151
0
    Curl_cmalloc = (curl_malloc_callback)malloc;
152
0
    Curl_cfree = (curl_free_callback)free;
153
0
    Curl_crealloc = (curl_realloc_callback)realloc;
154
0
    Curl_cstrdup = (curl_strdup_callback)system_strdup;
155
0
    Curl_ccalloc = (curl_calloc_callback)calloc;
156
#if defined(_WIN32) && defined(UNICODE)
157
    Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
158
#endif
159
0
  }
160
161
0
  if(Curl_trc_init()) {
162
0
    DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n"));
163
0
    goto fail;
164
0
  }
165
166
0
  if(!Curl_ssl_init()) {
167
0
    DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
168
0
    goto fail;
169
0
  }
170
171
0
  if(Curl_win32_init(flags)) {
172
0
    DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
173
0
    goto fail;
174
0
  }
175
176
0
  if(Curl_amiga_init()) {
177
0
    DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
178
0
    goto fail;
179
0
  }
180
181
0
  if(Curl_macos_init()) {
182
0
    DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n"));
183
0
    goto fail;
184
0
  }
185
186
0
  if(Curl_resolver_global_init()) {
187
0
    DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
188
0
    goto fail;
189
0
  }
190
191
0
  if(Curl_ssh_init()) {
192
0
    DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n"));
193
0
    goto fail;
194
0
  }
195
196
0
  easy_init_flags = flags;
197
198
#ifdef DEBUGBUILD
199
  if(getenv("CURL_GLOBAL_INIT"))
200
    /* alloc data that will leak if *cleanup() is not called! */
201
    leakpointer = malloc(1);
202
#endif
203
204
0
  return CURLE_OK;
205
206
0
fail:
207
0
  initialized--; /* undo the increase */
208
0
  return CURLE_FAILED_INIT;
209
0
}
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
#ifdef DEBUGBUILD
299
  free(leakpointer);
300
#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
0
{
350
0
  CURLcode result;
351
0
  struct Curl_easy *data;
352
353
  /* Make sure we inited the global SSL stuff */
354
0
  global_init_lock();
355
356
0
  if(!initialized) {
357
0
    result = global_init(CURL_GLOBAL_DEFAULT, TRUE);
358
0
    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
0
  }
365
0
  global_init_unlock();
366
367
  /* We use curl_open() with undefined URL so far */
368
0
  result = Curl_open(&data);
369
0
  if(result) {
370
0
    DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
371
0
    return NULL;
372
0
  }
373
374
0
  return data;
375
0
}
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
{
402
  struct events *ev = userp;
403
  (void)multi;
404
  if(timeout_ms == -1)
405
    /* timeout removed */
406
    timeout_ms = 0;
407
  else if(timeout_ms == 0)
408
    /* timeout is already reached! */
409
    timeout_ms = 1; /* trigger asap */
410
411
  ev->ms = timeout_ms;
412
  ev->msbump = TRUE;
413
  return 0;
414
}
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
{
423
  int omask = 0;
424
  if(pollmask & POLLIN)
425
    omask |= CURL_CSELECT_IN;
426
  if(pollmask & POLLOUT)
427
    omask |= CURL_CSELECT_OUT;
428
  if(pollmask & POLLERR)
429
    omask |= CURL_CSELECT_ERR;
430
  return omask;
431
}
432
433
434
/* socketcb2poll
435
 *
436
 * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
437
 */
438
static short socketcb2poll(int pollmask)
439
{
440
  short omask = 0;
441
  if(pollmask & CURL_POLL_IN)
442
    omask |= POLLIN;
443
  if(pollmask & CURL_POLL_OUT)
444
    omask |= POLLOUT;
445
  return omask;
446
}
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
{
461
  struct events *ev = userp;
462
  struct socketmonitor *m;
463
  struct socketmonitor *prev = NULL;
464
465
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
466
  (void) easy;
467
#endif
468
  (void)socketp;
469
470
  m = ev->list;
471
  while(m) {
472
    if(m->socket.fd == s) {
473
474
      if(what == CURL_POLL_REMOVE) {
475
        struct socketmonitor *nxt = m->next;
476
        /* remove this node from the list of monitored sockets */
477
        if(prev)
478
          prev->next = nxt;
479
        else
480
          ev->list = nxt;
481
        free(m);
482
        m = nxt;
483
        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
484
              " REMOVED", s);
485
      }
486
      else {
487
        /* The socket 's' is already being monitored, update the activity
488
           mask. Convert from libcurl bitmask to the poll one. */
489
        m->socket.events = socketcb2poll(what);
490
        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
491
              " UPDATED as %s%s", s,
492
              (what&CURL_POLL_IN)?"IN":"",
493
              (what&CURL_POLL_OUT)?"OUT":"");
494
      }
495
      break;
496
    }
497
    prev = m;
498
    m = m->next; /* move to next node */
499
  }
500
  if(!m) {
501
    if(what == CURL_POLL_REMOVE) {
502
      /* this happens a bit too often, libcurl fix perhaps? */
503
      /* fprintf(stderr,
504
         "%s: socket %d asked to be REMOVED but not present!\n",
505
                 __func__, s); */
506
    }
507
    else {
508
      m = malloc(sizeof(struct socketmonitor));
509
      if(m) {
510
        m->next = ev->list;
511
        m->socket.fd = s;
512
        m->socket.events = socketcb2poll(what);
513
        m->socket.revents = 0;
514
        ev->list = m;
515
        infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
516
              " ADDED as %s%s", s,
517
              (what&CURL_POLL_IN)?"IN":"",
518
              (what&CURL_POLL_OUT)?"OUT":"");
519
      }
520
      else
521
        return CURLE_OUT_OF_MEMORY;
522
    }
523
  }
524
525
  return 0;
526
}
527
528
529
/*
530
 * events_setup()
531
 *
532
 * Do the multi handle setups that only event-based transfers need.
533
 */
534
static void events_setup(struct Curl_multi *multi, struct events *ev)
535
{
536
  /* timer callback */
537
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
538
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
539
540
  /* socket callback */
541
  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
542
  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
543
}
544
545
546
/* wait_or_timeout()
547
 *
548
 * waits for activity on any of the given sockets, or the timeout to trigger.
549
 */
550
551
static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
552
{
553
  bool done = FALSE;
554
  CURLMcode mcode = CURLM_OK;
555
  CURLcode result = CURLE_OK;
556
557
  while(!done) {
558
    CURLMsg *msg;
559
    struct socketmonitor *m;
560
    struct pollfd *f;
561
    struct pollfd fds[4];
562
    int numfds = 0;
563
    int pollrc;
564
    int i;
565
    struct curltime before;
566
    struct curltime after;
567
568
    /* populate the fds[] array */
569
    for(m = ev->list, f = &fds[0]; m; m = m->next) {
570
      f->fd = m->socket.fd;
571
      f->events = m->socket.events;
572
      f->revents = 0;
573
      /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
574
      f++;
575
      numfds++;
576
    }
577
578
    /* get the time stamp to use to figure out how long poll takes */
579
    before = Curl_now();
580
581
    /* wait for activity or timeout */
582
    pollrc = Curl_poll(fds, numfds, ev->ms);
583
    if(pollrc < 0)
584
      return CURLE_UNRECOVERABLE_POLL;
585
586
    after = Curl_now();
587
588
    ev->msbump = FALSE; /* reset here */
589
590
    if(!pollrc) {
591
      /* timeout! */
592
      ev->ms = 0;
593
      /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
594
      mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
595
                                       &ev->running_handles);
596
    }
597
    else {
598
      /* here pollrc is > 0 */
599
600
      /* loop over the monitored sockets to see which ones had activity */
601
      for(i = 0; i< numfds; i++) {
602
        if(fds[i].revents) {
603
          /* socket activity, tell libcurl */
604
          int act = poll2cselect(fds[i].revents); /* convert */
605
          infof(multi->easyp,
606
                "call curl_multi_socket_action(socket "
607
                "%" CURL_FORMAT_SOCKET_T ")", fds[i].fd);
608
          mcode = curl_multi_socket_action(multi, fds[i].fd, act,
609
                                           &ev->running_handles);
610
        }
611
      }
612
613
      if(!ev->msbump) {
614
        /* If nothing updated the timeout, we decrease it by the spent time.
615
         * If it was updated, it has the new timeout time stored already.
616
         */
617
        timediff_t timediff = Curl_timediff(after, before);
618
        if(timediff > 0) {
619
          if(timediff > ev->ms)
620
            ev->ms = 0;
621
          else
622
            ev->ms -= (long)timediff;
623
        }
624
      }
625
    }
626
627
    if(mcode)
628
      return CURLE_URL_MALFORMAT;
629
630
    /* we don't really care about the "msgs_in_queue" value returned in the
631
       second argument */
632
    msg = curl_multi_info_read(multi, &pollrc);
633
    if(msg) {
634
      result = msg->data.result;
635
      done = TRUE;
636
    }
637
  }
638
639
  return result;
640
}
641
642
643
/* easy_events()
644
 *
645
 * Runs a transfer in a blocking manner using the events-based API
646
 */
647
static CURLcode easy_events(struct Curl_multi *multi)
648
{
649
  /* this struct is made static to allow it to be used after this function
650
     returns and curl_multi_remove_handle() is called */
651
  static struct events evs = {2, FALSE, 0, NULL, 0};
652
653
  /* if running event-based, do some further multi inits */
654
  events_setup(multi, &evs);
655
656
  return wait_or_timeout(multi, &evs);
657
}
658
#else /* CURLDEBUG */
659
/* when not built with debug, this function doesn't exist */
660
0
#define easy_events(x) CURLE_NOT_BUILT_IN
661
#endif
662
663
static CURLcode easy_transfer(struct Curl_multi *multi)
664
0
{
665
0
  bool done = FALSE;
666
0
  CURLMcode mcode = CURLM_OK;
667
0
  CURLcode result = CURLE_OK;
668
669
0
  while(!done && !mcode) {
670
0
    int still_running = 0;
671
672
0
    mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
673
674
0
    if(!mcode)
675
0
      mcode = curl_multi_perform(multi, &still_running);
676
677
    /* only read 'still_running' if curl_multi_perform() return OK */
678
0
    if(!mcode && !still_running) {
679
0
      int rc;
680
0
      CURLMsg *msg = curl_multi_info_read(multi, &rc);
681
0
      if(msg) {
682
0
        result = msg->data.result;
683
0
        done = TRUE;
684
0
      }
685
0
    }
686
0
  }
687
688
  /* Make sure to return some kind of error if there was a multi problem */
689
0
  if(mcode) {
690
0
    result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
691
      /* The other multi errors should never happen, so return
692
         something suitably generic */
693
0
      CURLE_BAD_FUNCTION_ARGUMENT;
694
0
  }
695
696
0
  return result;
697
0
}
698
699
700
/*
701
 * easy_perform() is the external interface that performs a blocking
702
 * transfer as previously setup.
703
 *
704
 * CONCEPT: This function creates a multi handle, adds the easy handle to it,
705
 * runs curl_multi_perform() until the transfer is done, then detaches the
706
 * easy handle, destroys the multi handle and returns the easy handle's return
707
 * code.
708
 *
709
 * REALITY: it can't just create and destroy the multi handle that easily. It
710
 * needs to keep it around since if this easy handle is used again by this
711
 * function, the same multi handle must be reused so that the same pools and
712
 * caches can be used.
713
 *
714
 * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
715
 * instead of curl_multi_perform() and use curl_multi_socket_action().
716
 */
717
static CURLcode easy_perform(struct Curl_easy *data, bool events)
718
0
{
719
0
  struct Curl_multi *multi;
720
0
  CURLMcode mcode;
721
0
  CURLcode result = CURLE_OK;
722
0
  SIGPIPE_VARIABLE(pipe_st);
723
724
0
  if(!data)
725
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
726
727
0
  if(data->set.errorbuffer)
728
    /* clear this as early as possible */
729
0
    data->set.errorbuffer[0] = 0;
730
731
0
  if(data->multi) {
732
0
    failf(data, "easy handle already used in multi handle");
733
0
    return CURLE_FAILED_INIT;
734
0
  }
735
736
0
  if(data->multi_easy)
737
0
    multi = data->multi_easy;
738
0
  else {
739
    /* this multi handle will only ever have a single easy handled attached
740
       to it, so make it use minimal hashes */
741
0
    multi = Curl_multi_handle(1, 3, 7);
742
0
    if(!multi)
743
0
      return CURLE_OUT_OF_MEMORY;
744
0
    data->multi_easy = multi;
745
0
  }
746
747
0
  if(multi->in_callback)
748
0
    return CURLE_RECURSIVE_API_CALL;
749
750
  /* Copy the MAXCONNECTS option to the multi handle */
751
0
  curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects);
752
753
0
  mcode = curl_multi_add_handle(multi, data);
754
0
  if(mcode) {
755
0
    curl_multi_cleanup(multi);
756
0
    data->multi_easy = NULL;
757
0
    if(mcode == CURLM_OUT_OF_MEMORY)
758
0
      return CURLE_OUT_OF_MEMORY;
759
0
    return CURLE_FAILED_INIT;
760
0
  }
761
762
0
  sigpipe_ignore(data, &pipe_st);
763
764
  /* run the transfer */
765
0
  result = events ? easy_events(multi) : easy_transfer(multi);
766
767
  /* ignoring the return code isn't nice, but atm we can't really handle
768
     a failure here, room for future improvement! */
769
0
  (void)curl_multi_remove_handle(multi, data);
770
771
0
  sigpipe_restore(&pipe_st);
772
773
  /* The multi handle is kept alive, owned by the easy handle */
774
0
  return result;
775
0
}
776
777
778
/*
779
 * curl_easy_perform() is the external interface that performs a blocking
780
 * transfer as previously setup.
781
 */
782
CURLcode curl_easy_perform(struct Curl_easy *data)
783
0
{
784
0
  return easy_perform(data, FALSE);
785
0
}
786
787
#ifdef CURLDEBUG
788
/*
789
 * curl_easy_perform_ev() is the external interface that performs a blocking
790
 * transfer using the event-based API internally.
791
 */
792
CURLcode curl_easy_perform_ev(struct Curl_easy *data)
793
{
794
  return easy_perform(data, TRUE);
795
}
796
797
#endif
798
799
/*
800
 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
801
 * easy handle.
802
 */
803
void curl_easy_cleanup(struct Curl_easy *data)
804
0
{
805
0
  if(GOOD_EASY_HANDLE(data)) {
806
0
    SIGPIPE_VARIABLE(pipe_st);
807
0
    sigpipe_ignore(data, &pipe_st);
808
0
    Curl_close(&data);
809
0
    sigpipe_restore(&pipe_st);
810
0
  }
811
0
}
812
813
/*
814
 * curl_easy_getinfo() is an external interface that allows an app to retrieve
815
 * information from a performed transfer and similar.
816
 */
817
#undef curl_easy_getinfo
818
CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
819
0
{
820
0
  va_list arg;
821
0
  void *paramp;
822
0
  CURLcode result;
823
824
0
  va_start(arg, info);
825
0
  paramp = va_arg(arg, void *);
826
827
0
  result = Curl_getinfo(data, info, paramp);
828
829
0
  va_end(arg);
830
0
  return result;
831
0
}
832
833
static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
834
0
{
835
0
  CURLcode result = CURLE_OK;
836
0
  enum dupstring i;
837
0
  enum dupblob j;
838
839
  /* Copy src->set into dst->set first, then deal with the strings
840
     afterwards */
841
0
  dst->set = src->set;
842
0
  Curl_mime_initpart(&dst->set.mimepost);
843
844
  /* clear all dest string and blob pointers first, in case we error out
845
     mid-function */
846
0
  memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
847
0
  memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
848
849
  /* duplicate all strings */
850
0
  for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
851
0
    result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
852
0
    if(result)
853
0
      return result;
854
0
  }
855
856
  /* duplicate all blobs */
857
0
  for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
858
0
    result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
859
0
    if(result)
860
0
      return result;
861
0
  }
862
863
  /* duplicate memory areas pointed to */
864
0
  i = STRING_COPYPOSTFIELDS;
865
0
  if(src->set.str[i]) {
866
0
    if(src->set.postfieldsize == -1)
867
0
      dst->set.str[i] = strdup(src->set.str[i]);
868
0
    else
869
      /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
870
0
      dst->set.str[i] = Curl_memdup(src->set.str[i],
871
0
                                    curlx_sotouz(src->set.postfieldsize));
872
0
    if(!dst->set.str[i])
873
0
      return CURLE_OUT_OF_MEMORY;
874
    /* point to the new copy */
875
0
    dst->set.postfields = dst->set.str[i];
876
0
  }
877
878
  /* Duplicate mime data. */
879
0
  result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost);
880
881
0
  if(src->set.resolve)
882
0
    dst->state.resolve = dst->set.resolve;
883
884
0
  return result;
885
0
}
886
887
/*
888
 * curl_easy_duphandle() is an external interface to allow duplication of a
889
 * given input easy handle. The returned handle will be a new working handle
890
 * with all options set exactly as the input source handle.
891
 */
892
struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
893
0
{
894
0
  struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
895
0
  if(!outcurl)
896
0
    goto fail;
897
898
  /*
899
   * We setup a few buffers we need. We should probably make them
900
   * get setup on-demand in the code, as that would probably decrease
901
   * the likeliness of us forgetting to init a buffer here in the future.
902
   */
903
0
  outcurl->set.buffer_size = data->set.buffer_size;
904
905
  /* copy all userdefined values */
906
0
  if(dupset(outcurl, data))
907
0
    goto fail;
908
909
0
  Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
910
911
  /* the connection cache is setup on demand */
912
0
  outcurl->state.conn_cache = NULL;
913
0
  outcurl->state.lastconnect_id = -1;
914
0
  outcurl->state.recent_conn_id = -1;
915
0
  outcurl->id = -1;
916
917
0
  outcurl->progress.flags    = data->progress.flags;
918
0
  outcurl->progress.callback = data->progress.callback;
919
920
0
#ifndef CURL_DISABLE_COOKIES
921
0
  outcurl->state.cookielist = NULL;
922
0
  if(data->cookies && data->state.cookie_engine) {
923
    /* If cookies are enabled in the parent handle, we enable them
924
       in the clone as well! */
925
0
    outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies,
926
0
                                        data->set.cookiesession);
927
0
    if(!outcurl->cookies)
928
0
      goto fail;
929
0
  }
930
931
0
  if(data->state.cookielist) {
932
0
    outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist);
933
0
    if(!outcurl->state.cookielist)
934
0
      goto fail;
935
0
  }
936
0
#endif
937
938
0
  if(data->state.url) {
939
0
    outcurl->state.url = strdup(data->state.url);
940
0
    if(!outcurl->state.url)
941
0
      goto fail;
942
0
    outcurl->state.url_alloc = TRUE;
943
0
  }
944
945
0
  if(data->state.referer) {
946
0
    outcurl->state.referer = strdup(data->state.referer);
947
0
    if(!outcurl->state.referer)
948
0
      goto fail;
949
0
    outcurl->state.referer_alloc = TRUE;
950
0
  }
951
952
  /* Reinitialize an SSL engine for the new handle
953
   * note: the engine name has already been copied by dupset */
954
0
  if(outcurl->set.str[STRING_SSL_ENGINE]) {
955
0
    if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
956
0
      goto fail;
957
0
  }
958
959
0
#ifndef CURL_DISABLE_ALTSVC
960
0
  if(data->asi) {
961
0
    outcurl->asi = Curl_altsvc_init();
962
0
    if(!outcurl->asi)
963
0
      goto fail;
964
0
    if(outcurl->set.str[STRING_ALTSVC])
965
0
      (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
966
0
  }
967
0
#endif
968
0
#ifndef CURL_DISABLE_HSTS
969
0
  if(data->hsts) {
970
0
    outcurl->hsts = Curl_hsts_init();
971
0
    if(!outcurl->hsts)
972
0
      goto fail;
973
0
    if(outcurl->set.str[STRING_HSTS])
974
0
      (void)Curl_hsts_loadfile(outcurl,
975
0
                               outcurl->hsts, outcurl->set.str[STRING_HSTS]);
976
0
    (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
977
0
  }
978
0
#endif
979
980
0
#ifdef CURLRES_ASYNCH
981
  /* Clone the resolver handle, if present, for the new handle */
982
0
  if(Curl_resolver_duphandle(outcurl,
983
0
                             &outcurl->state.async.resolver,
984
0
                             data->state.async.resolver))
985
0
    goto fail;
986
0
#endif
987
988
#ifdef USE_ARES
989
  {
990
    CURLcode rc;
991
992
    rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
993
    if(rc && rc != CURLE_NOT_BUILT_IN)
994
      goto fail;
995
996
    rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
997
    if(rc && rc != CURLE_NOT_BUILT_IN)
998
      goto fail;
999
1000
    rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
1001
    if(rc && rc != CURLE_NOT_BUILT_IN)
1002
      goto fail;
1003
1004
    rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
1005
    if(rc && rc != CURLE_NOT_BUILT_IN)
1006
      goto fail;
1007
  }
1008
#endif /* USE_ARES */
1009
1010
0
  Curl_initinfo(outcurl);
1011
1012
0
  outcurl->magic = CURLEASY_MAGIC_NUMBER;
1013
1014
  /* we reach this point and thus we are OK */
1015
1016
0
  return outcurl;
1017
1018
0
fail:
1019
1020
0
  if(outcurl) {
1021
0
#ifndef CURL_DISABLE_COOKIES
1022
0
    free(outcurl->cookies);
1023
0
#endif
1024
0
    Curl_dyn_free(&outcurl->state.headerb);
1025
0
    Curl_altsvc_cleanup(&outcurl->asi);
1026
0
    Curl_hsts_cleanup(&outcurl->hsts);
1027
0
    Curl_freeset(outcurl);
1028
0
    free(outcurl);
1029
0
  }
1030
1031
0
  return NULL;
1032
0
}
1033
1034
/*
1035
 * curl_easy_reset() is an external interface that allows an app to re-
1036
 * initialize a session handle to the default values.
1037
 */
1038
void curl_easy_reset(struct Curl_easy *data)
1039
0
{
1040
0
  Curl_free_request_state(data);
1041
1042
  /* zero out UserDefined data: */
1043
0
  Curl_freeset(data);
1044
0
  memset(&data->set, 0, sizeof(struct UserDefined));
1045
0
  (void)Curl_init_userdefined(data);
1046
1047
  /* zero out Progress data: */
1048
0
  memset(&data->progress, 0, sizeof(struct Progress));
1049
1050
  /* zero out PureInfo data: */
1051
0
  Curl_initinfo(data);
1052
1053
0
  data->progress.flags |= PGRS_HIDE;
1054
0
  data->state.current_speed = -1; /* init to negative == impossible */
1055
0
  data->state.retrycount = 0;     /* reset the retry counter */
1056
1057
  /* zero out authentication data: */
1058
0
  memset(&data->state.authhost, 0, sizeof(struct auth));
1059
0
  memset(&data->state.authproxy, 0, sizeof(struct auth));
1060
1061
0
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
1062
0
  Curl_http_auth_cleanup_digest(data);
1063
0
#endif
1064
0
}
1065
1066
/*
1067
 * curl_easy_pause() allows an application to pause or unpause a specific
1068
 * transfer and direction. This function sets the full new state for the
1069
 * current connection this easy handle operates on.
1070
 *
1071
 * NOTE: if you have the receiving paused and you call this function to remove
1072
 * the pausing, you may get your write callback called at this point.
1073
 *
1074
 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
1075
 *
1076
 * NOTE: This is one of few API functions that are allowed to be called from
1077
 * within a callback.
1078
 */
1079
CURLcode curl_easy_pause(struct Curl_easy *data, int action)
1080
0
{
1081
0
  struct SingleRequest *k;
1082
0
  CURLcode result = CURLE_OK;
1083
0
  int oldstate;
1084
0
  int newstate;
1085
0
  bool recursive = FALSE;
1086
1087
0
  if(!GOOD_EASY_HANDLE(data) || !data->conn)
1088
    /* crazy input, don't continue */
1089
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1090
1091
0
  if(Curl_is_in_callback(data))
1092
0
    recursive = TRUE;
1093
0
  k = &data->req;
1094
0
  oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
1095
1096
  /* first switch off both pause bits then set the new pause bits */
1097
0
  newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
1098
0
    ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
1099
0
    ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
1100
1101
0
  if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
1102
    /* Not changing any pause state, return */
1103
0
    DEBUGF(infof(data, "pause: no change, early return"));
1104
0
    return CURLE_OK;
1105
0
  }
1106
1107
  /* Unpause parts in active mime tree. */
1108
0
  if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
1109
0
     (data->mstate == MSTATE_PERFORMING ||
1110
0
      data->mstate == MSTATE_RATELIMITING) &&
1111
0
     data->state.fread_func == (curl_read_callback) Curl_mime_read) {
1112
0
    Curl_mime_unpause(data->state.in);
1113
0
  }
1114
1115
  /* put it back in the keepon */
1116
0
  k->keepon = newstate;
1117
1118
0
  if(!(newstate & KEEP_RECV_PAUSE)) {
1119
0
    Curl_conn_ev_data_pause(data, FALSE);
1120
0
    result = Curl_client_unpause(data);
1121
0
    if(result)
1122
0
      return result;
1123
0
  }
1124
1125
#ifdef USE_HYPER
1126
  if(!(newstate & KEEP_SEND_PAUSE)) {
1127
    /* need to wake the send body waker */
1128
    if(data->hyp.send_body_waker) {
1129
      hyper_waker_wake(data->hyp.send_body_waker);
1130
      data->hyp.send_body_waker = NULL;
1131
    }
1132
  }
1133
#endif
1134
1135
  /* if there's no error and we're not pausing both directions, we want
1136
     to have this handle checked soon */
1137
0
  if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
1138
0
     (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
1139
0
    Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
1140
1141
    /* reset the too-slow time keeper */
1142
0
    data->state.keeps_speed.tv_sec = 0;
1143
1144
0
    if(!data->state.tempcount)
1145
      /* if not pausing again, force a recv/send check of this connection as
1146
         the data might've been read off the socket already */
1147
0
      data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
1148
0
    if(data->multi) {
1149
0
      if(Curl_update_timer(data->multi))
1150
0
        return CURLE_ABORTED_BY_CALLBACK;
1151
0
    }
1152
0
  }
1153
1154
0
  if(!data->state.done)
1155
    /* This transfer may have been moved in or out of the bundle, update the
1156
       corresponding socket callback, if used */
1157
0
    result = Curl_updatesocket(data);
1158
1159
0
  if(recursive)
1160
    /* this might have called a callback recursively which might have set this
1161
       to false again on exit */
1162
0
    Curl_set_in_callback(data, TRUE);
1163
1164
0
  return result;
1165
0
}
1166
1167
1168
static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
1169
                                struct connectdata **connp)
1170
0
{
1171
0
  if(!data)
1172
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1173
1174
  /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1175
0
  if(!data->set.connect_only) {
1176
0
    failf(data, "CONNECT_ONLY is required");
1177
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1178
0
  }
1179
1180
0
  *sfd = Curl_getconnectinfo(data, connp);
1181
1182
0
  if(*sfd == CURL_SOCKET_BAD) {
1183
0
    failf(data, "Failed to get recent socket");
1184
0
    return CURLE_UNSUPPORTED_PROTOCOL;
1185
0
  }
1186
1187
0
  return CURLE_OK;
1188
0
}
1189
1190
/*
1191
 * Receives data from the connected socket. Use after successful
1192
 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1193
 * Returns CURLE_OK on success, error code on error.
1194
 */
1195
CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
1196
                        size_t *n)
1197
0
{
1198
0
  curl_socket_t sfd;
1199
0
  CURLcode result;
1200
0
  ssize_t n1;
1201
0
  struct connectdata *c;
1202
1203
0
  if(Curl_is_in_callback(data))
1204
0
    return CURLE_RECURSIVE_API_CALL;
1205
1206
0
  result = easy_connection(data, &sfd, &c);
1207
0
  if(result)
1208
0
    return result;
1209
1210
0
  if(!data->conn)
1211
    /* on first invoke, the transfer has been detached from the connection and
1212
       needs to be reattached */
1213
0
    Curl_attach_connection(data, c);
1214
1215
0
  *n = 0;
1216
0
  result = Curl_read(data, sfd, buffer, buflen, &n1);
1217
1218
0
  if(result)
1219
0
    return result;
1220
1221
0
  *n = (size_t)n1;
1222
0
  return CURLE_OK;
1223
0
}
1224
1225
#ifdef USE_WEBSOCKETS
1226
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
1227
{
1228
  curl_socket_t sfd;
1229
  CURLcode result;
1230
  struct connectdata *c = NULL;
1231
1232
  result = easy_connection(data, &sfd, &c);
1233
  if(result)
1234
    return result;
1235
1236
  if(!data->conn)
1237
    /* on first invoke, the transfer has been detached from the connection and
1238
       needs to be reattached */
1239
    Curl_attach_connection(data, c);
1240
1241
  return CURLE_OK;
1242
}
1243
#endif /* USE_WEBSOCKETS */
1244
1245
/*
1246
 * Sends data over the connected socket.
1247
 *
1248
 * This is the private internal version of curl_easy_send()
1249
 */
1250
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
1251
                       size_t buflen, ssize_t *n)
1252
0
{
1253
0
  curl_socket_t sfd;
1254
0
  CURLcode result;
1255
0
  ssize_t n1;
1256
0
  struct connectdata *c = NULL;
1257
0
  SIGPIPE_VARIABLE(pipe_st);
1258
1259
0
  result = easy_connection(data, &sfd, &c);
1260
0
  if(result)
1261
0
    return result;
1262
1263
0
  if(!data->conn)
1264
    /* on first invoke, the transfer has been detached from the connection and
1265
       needs to be reattached */
1266
0
    Curl_attach_connection(data, c);
1267
1268
0
  *n = 0;
1269
0
  sigpipe_ignore(data, &pipe_st);
1270
0
  result = Curl_write(data, sfd, buffer, buflen, &n1);
1271
0
  sigpipe_restore(&pipe_st);
1272
1273
0
  if(n1 == -1)
1274
0
    return CURLE_SEND_ERROR;
1275
1276
  /* detect EAGAIN */
1277
0
  if(!result && !n1)
1278
0
    return CURLE_AGAIN;
1279
1280
0
  *n = n1;
1281
1282
0
  return result;
1283
0
}
1284
1285
/*
1286
 * Sends data over the connected socket. Use after successful
1287
 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1288
 */
1289
CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
1290
                        size_t buflen, size_t *n)
1291
0
{
1292
0
  ssize_t written = 0;
1293
0
  CURLcode result;
1294
0
  if(Curl_is_in_callback(data))
1295
0
    return CURLE_RECURSIVE_API_CALL;
1296
1297
0
  result = Curl_senddata(data, buffer, buflen, &written);
1298
0
  *n = (size_t)written;
1299
0
  return result;
1300
0
}
1301
1302
/*
1303
 * Wrapper to call functions in Curl_conncache_foreach()
1304
 *
1305
 * Returns always 0.
1306
 */
1307
static int conn_upkeep(struct Curl_easy *data,
1308
                       struct connectdata *conn,
1309
                       void *param)
1310
0
{
1311
0
  struct curltime *now = param;
1312
1313
0
  if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
1314
0
    return 0;
1315
1316
  /* briefly attach for action */
1317
0
  Curl_attach_connection(data, conn);
1318
0
  if(conn->handler->connection_check) {
1319
    /* Do a protocol-specific keepalive check on the connection. */
1320
0
    conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
1321
0
  }
1322
0
  else {
1323
    /* Do the generic action on the FIRSTSOCKE filter chain */
1324
0
    Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
1325
0
  }
1326
0
  Curl_detach_connection(data);
1327
1328
0
  conn->keepalive = *now;
1329
0
  return 0; /* continue iteration */
1330
0
}
1331
1332
static CURLcode upkeep(struct conncache *conn_cache, void *data)
1333
0
{
1334
0
  struct curltime now = Curl_now();
1335
  /* Loop over every connection and make connection alive. */
1336
0
  Curl_conncache_foreach(data,
1337
0
                         conn_cache,
1338
0
                         &now,
1339
0
                         conn_upkeep);
1340
0
  return CURLE_OK;
1341
0
}
1342
1343
/*
1344
 * Performs connection upkeep for the given session handle.
1345
 */
1346
CURLcode curl_easy_upkeep(struct Curl_easy *data)
1347
0
{
1348
  /* Verify that we got an easy handle we can work with. */
1349
0
  if(!GOOD_EASY_HANDLE(data))
1350
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1351
1352
0
  if(data->multi_easy) {
1353
    /* Use the common function to keep connections alive. */
1354
0
    return upkeep(&data->multi_easy->conn_cache, data);
1355
0
  }
1356
0
  else {
1357
    /* No connections, so just return success */
1358
0
    return CURLE_OK;
1359
0
  }
1360
0
}