VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/easy.c@ 106542

最後變更 在這個檔案從106542是 104083,由 vboxsync 提交於 11 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette