Coverage Report

Created: 2023-06-07 07:02

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