VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/easy.c@ 86643

Last change on this file since 86643 was 85671, checked in by vboxsync, 4 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

  • Property svn:eol-style set to native
File size: 32.2 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2019, 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.haxx.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 ***************************************************************************/
22
23#include "curl_setup.h"
24
25/*
26 * See comment in curl_memory.h for the explanation of this sanity check.
27 */
28
29#ifdef CURLX_NO_MEMORY_CALLBACKS
30#error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined"
31#endif
32
33#ifdef HAVE_NETINET_IN_H
34#include <netinet/in.h>
35#endif
36#ifdef HAVE_NETDB_H
37#include <netdb.h>
38#endif
39#ifdef HAVE_ARPA_INET_H
40#include <arpa/inet.h>
41#endif
42#ifdef HAVE_NET_IF_H
43#include <net/if.h>
44#endif
45#ifdef HAVE_SYS_IOCTL_H
46#include <sys/ioctl.h>
47#endif
48
49#ifdef HAVE_SYS_PARAM_H
50#include <sys/param.h>
51#endif
52
53#include "urldata.h"
54#include <curl/curl.h>
55#include "transfer.h"
56#include "vtls/vtls.h"
57#include "url.h"
58#include "getinfo.h"
59#include "hostip.h"
60#include "share.h"
61#include "strdup.h"
62#include "progress.h"
63#include "easyif.h"
64#include "multiif.h"
65#include "select.h"
66#include "sendf.h" /* for failf function prototype */
67#include "connect.h" /* for Curl_getconnectinfo */
68#include "slist.h"
69#include "mime.h"
70#include "amigaos.h"
71#include "non-ascii.h"
72#include "warnless.h"
73#include "multiif.h"
74#include "sigpipe.h"
75#include "ssh.h"
76#include "setopt.h"
77#include "http_digest.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
84void Curl_version_init(void);
85
86/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
87 of win32_init() */
88static void win32_cleanup(void)
89{
90#ifdef USE_WINSOCK
91 WSACleanup();
92#endif
93#ifdef USE_WINDOWS_SSPI
94 Curl_sspi_global_cleanup();
95#endif
96}
97
98/* win32_init() performs win32 socket initialization to properly setup the
99 stack to allow networking */
100static CURLcode win32_init(void)
101{
102#ifdef USE_WINSOCK
103 WORD wVersionRequested;
104 WSADATA wsaData;
105 int res;
106
107#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
108 Error IPV6_requires_winsock2
109#endif
110
111 wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
112
113 res = WSAStartup(wVersionRequested, &wsaData);
114
115 if(res != 0)
116 /* Tell the user that we couldn't find a usable */
117 /* winsock.dll. */
118 return CURLE_FAILED_INIT;
119
120 /* Confirm that the Windows Sockets DLL supports what we need.*/
121 /* Note that if the DLL supports versions greater */
122 /* than wVersionRequested, it will still return */
123 /* wVersionRequested in wVersion. wHighVersion contains the */
124 /* highest supported version. */
125
126 if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
127 HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
128 /* Tell the user that we couldn't find a usable */
129
130 /* winsock.dll. */
131 WSACleanup();
132 return CURLE_FAILED_INIT;
133 }
134 /* The Windows Sockets DLL is acceptable. Proceed. */
135#elif defined(USE_LWIPSOCK)
136 lwip_init();
137#endif
138
139#ifdef USE_WINDOWS_SSPI
140 {
141 CURLcode result = Curl_sspi_global_init();
142 if(result)
143 return result;
144 }
145#endif
146
147 return CURLE_OK;
148}
149
150/* true globals -- for curl_global_init() and curl_global_cleanup() */
151static unsigned int initialized;
152static long init_flags;
153
154/*
155 * strdup (and other memory functions) is redefined in complicated
156 * ways, but at this point it must be defined as the system-supplied strdup
157 * so the callback pointer is initialized correctly.
158 */
159#if defined(_WIN32_WCE)
160#define system_strdup _strdup
161#elif !defined(HAVE_STRDUP)
162#define system_strdup curlx_strdup
163#else
164#define system_strdup strdup
165#endif
166
167#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
168# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
169#endif
170
171#ifndef __SYMBIAN32__
172/*
173 * If a memory-using function (like curl_getenv) is used before
174 * curl_global_init() is called, we need to have these pointers set already.
175 */
176curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
177curl_free_callback Curl_cfree = (curl_free_callback)free;
178curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
179curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
180curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
181#if defined(WIN32) && defined(UNICODE)
182curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
183#endif
184#else
185/*
186 * Symbian OS doesn't support initialization to code in writable static data.
187 * Initialization will occur in the curl_global_init() call.
188 */
189curl_malloc_callback Curl_cmalloc;
190curl_free_callback Curl_cfree;
191curl_realloc_callback Curl_crealloc;
192curl_strdup_callback Curl_cstrdup;
193curl_calloc_callback Curl_ccalloc;
194#endif
195
196#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
197# pragma warning(default:4232) /* MSVC extension, dllimport identity */
198#endif
199
200/**
201 * curl_global_init() globally initializes curl given a bitwise set of the
202 * different features of what to initialize.
203 */
204static CURLcode global_init(long flags, bool memoryfuncs)
205{
206 if(initialized++)
207 return CURLE_OK;
208
209 if(memoryfuncs) {
210 /* Setup the default memory functions here (again) */
211 Curl_cmalloc = (curl_malloc_callback)malloc;
212 Curl_cfree = (curl_free_callback)free;
213 Curl_crealloc = (curl_realloc_callback)realloc;
214 Curl_cstrdup = (curl_strdup_callback)system_strdup;
215 Curl_ccalloc = (curl_calloc_callback)calloc;
216#if defined(WIN32) && defined(UNICODE)
217 Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
218#endif
219 }
220
221 if(!Curl_ssl_init()) {
222 DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
223 return CURLE_FAILED_INIT;
224 }
225
226 if(flags & CURL_GLOBAL_WIN32)
227 if(win32_init()) {
228 DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
229 return CURLE_FAILED_INIT;
230 }
231
232#ifdef __AMIGA__
233 if(!Curl_amiga_init()) {
234 DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
235 return CURLE_FAILED_INIT;
236 }
237#endif
238
239#ifdef NETWARE
240 if(netware_init()) {
241 DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
242 }
243#endif
244
245 if(Curl_resolver_global_init()) {
246 DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
247 return CURLE_FAILED_INIT;
248 }
249
250 (void)Curl_ipv6works();
251
252#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT)
253 if(libssh2_init(0)) {
254 DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
255 return CURLE_FAILED_INIT;
256 }
257#endif
258
259#if defined(USE_LIBSSH)
260 if(ssh_init()) {
261 DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
262 return CURLE_FAILED_INIT;
263 }
264#endif
265
266 if(flags & CURL_GLOBAL_ACK_EINTR)
267 Curl_ack_eintr = 1;
268
269 init_flags = flags;
270
271 Curl_version_init();
272
273 return CURLE_OK;
274}
275
276
277/**
278 * curl_global_init() globally initializes curl given a bitwise set of the
279 * different features of what to initialize.
280 */
281CURLcode curl_global_init(long flags)
282{
283 return global_init(flags, TRUE);
284}
285
286/*
287 * curl_global_init_mem() globally initializes curl and also registers the
288 * user provided callback routines.
289 */
290CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
291 curl_free_callback f, curl_realloc_callback r,
292 curl_strdup_callback s, curl_calloc_callback c)
293{
294 /* Invalid input, return immediately */
295 if(!m || !f || !r || !s || !c)
296 return CURLE_FAILED_INIT;
297
298 if(initialized) {
299 /* Already initialized, don't do it again, but bump the variable anyway to
300 work like curl_global_init() and require the same amount of cleanup
301 calls. */
302 initialized++;
303 return CURLE_OK;
304 }
305
306 /* set memory functions before global_init() in case it wants memory
307 functions */
308 Curl_cmalloc = m;
309 Curl_cfree = f;
310 Curl_cstrdup = s;
311 Curl_crealloc = r;
312 Curl_ccalloc = c;
313
314 /* Call the actual init function, but without setting */
315 return global_init(flags, FALSE);
316}
317
318/**
319 * curl_global_cleanup() globally cleanups curl, uses the value of
320 * "init_flags" to determine what needs to be cleaned up and what doesn't.
321 */
322void curl_global_cleanup(void)
323{
324 if(!initialized)
325 return;
326
327 if(--initialized)
328 return;
329
330 Curl_global_host_cache_dtor();
331 Curl_ssl_cleanup();
332 Curl_resolver_global_cleanup();
333
334 if(init_flags & CURL_GLOBAL_WIN32)
335 win32_cleanup();
336
337 Curl_amiga_cleanup();
338
339#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT)
340 (void)libssh2_exit();
341#endif
342
343#if defined(USE_LIBSSH)
344 (void)ssh_finalize();
345#endif
346
347 init_flags = 0;
348}
349
350/*
351 * curl_easy_init() is the external interface to alloc, setup and init an
352 * easy handle that is returned. If anything goes wrong, NULL is returned.
353 */
354struct Curl_easy *curl_easy_init(void)
355{
356 CURLcode result;
357 struct Curl_easy *data;
358
359 /* Make sure we inited the global SSL stuff */
360 if(!initialized) {
361 result = curl_global_init(CURL_GLOBAL_DEFAULT);
362 if(result) {
363 /* something in the global init failed, return nothing */
364 DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
365 return NULL;
366 }
367 }
368
369 /* We use curl_open() with undefined URL so far */
370 result = Curl_open(&data);
371 if(result) {
372 DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
373 return NULL;
374 }
375
376 return data;
377}
378
379#ifdef CURLDEBUG
380
381struct socketmonitor {
382 struct socketmonitor *next; /* the next node in the list or NULL */
383 struct pollfd socket; /* socket info of what to monitor */
384};
385
386struct events {
387 long ms; /* timeout, run the timeout function when reached */
388 bool msbump; /* set TRUE when timeout is set by callback */
389 int num_sockets; /* number of nodes in the monitor list */
390 struct socketmonitor *list; /* list of sockets to monitor */
391 int running_handles; /* store the returned number */
392};
393
394/* events_timer
395 *
396 * Callback that gets called with a new value when the timeout should be
397 * updated.
398 */
399
400static int events_timer(struct Curl_multi *multi, /* multi handle */
401 long timeout_ms, /* see above */
402 void *userp) /* private callback pointer */
403{
404 struct events *ev = userp;
405 (void)multi;
406 if(timeout_ms == -1)
407 /* timeout removed */
408 timeout_ms = 0;
409 else if(timeout_ms == 0)
410 /* timeout is already reached! */
411 timeout_ms = 1; /* trigger asap */
412
413 ev->ms = timeout_ms;
414 ev->msbump = TRUE;
415 return 0;
416}
417
418
419/* poll2cselect
420 *
421 * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
422 */
423static int poll2cselect(int pollmask)
424{
425 int omask = 0;
426 if(pollmask & POLLIN)
427 omask |= CURL_CSELECT_IN;
428 if(pollmask & POLLOUT)
429 omask |= CURL_CSELECT_OUT;
430 if(pollmask & POLLERR)
431 omask |= CURL_CSELECT_ERR;
432 return omask;
433}
434
435
436/* socketcb2poll
437 *
438 * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
439 */
440static short socketcb2poll(int pollmask)
441{
442 short omask = 0;
443 if(pollmask & CURL_POLL_IN)
444 omask |= POLLIN;
445 if(pollmask & CURL_POLL_OUT)
446 omask |= POLLOUT;
447 return omask;
448}
449
450/* events_socket
451 *
452 * Callback that gets called with information about socket activity to
453 * monitor.
454 */
455static int events_socket(struct Curl_easy *easy, /* easy handle */
456 curl_socket_t s, /* socket */
457 int what, /* see above */
458 void *userp, /* private callback
459 pointer */
460 void *socketp) /* private socket
461 pointer */
462{
463 struct events *ev = userp;
464 struct socketmonitor *m;
465 struct socketmonitor *prev = NULL;
466
467#if defined(CURL_DISABLE_VERBOSE_STRINGS)
468 (void) easy;
469#endif
470 (void)socketp;
471
472 m = ev->list;
473 while(m) {
474 if(m->socket.fd == s) {
475
476 if(what == CURL_POLL_REMOVE) {
477 struct socketmonitor *nxt = m->next;
478 /* remove this node from the list of monitored sockets */
479 if(prev)
480 prev->next = nxt;
481 else
482 ev->list = nxt;
483 free(m);
484 m = nxt;
485 infof(easy, "socket cb: socket %d REMOVED\n", 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 %d UPDATED as %s%s\n", 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 %d ADDED as %s%s\n", s,
516 what&CURL_POLL_IN?"IN":"",
517 what&CURL_POLL_OUT?"OUT":"");
518 }
519 else
520 return CURLE_OUT_OF_MEMORY;
521 }
522 }
523
524 return 0;
525}
526
527
528/*
529 * events_setup()
530 *
531 * Do the multi handle setups that only event-based transfers need.
532 */
533static void events_setup(struct Curl_multi *multi, struct events *ev)
534{
535 /* timer callback */
536 curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
537 curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
538
539 /* socket callback */
540 curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
541 curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
542}
543
544
545/* wait_or_timeout()
546 *
547 * waits for activity on any of the given sockets, or the timeout to trigger.
548 */
549
550static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
551{
552 bool done = FALSE;
553 CURLMcode mcode = CURLM_OK;
554 CURLcode result = CURLE_OK;
555
556 while(!done) {
557 CURLMsg *msg;
558 struct socketmonitor *m;
559 struct pollfd *f;
560 struct pollfd fds[4];
561 int numfds = 0;
562 int pollrc;
563 int i;
564 struct curltime before;
565 struct curltime after;
566
567 /* populate the fds[] array */
568 for(m = ev->list, f = &fds[0]; m; m = m->next) {
569 f->fd = m->socket.fd;
570 f->events = m->socket.events;
571 f->revents = 0;
572 /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
573 f++;
574 numfds++;
575 }
576
577 /* get the time stamp to use to figure out how long poll takes */
578 before = Curl_now();
579
580 /* wait for activity or timeout */
581 pollrc = Curl_poll(fds, numfds, (int)ev->ms);
582
583 after = Curl_now();
584
585 ev->msbump = FALSE; /* reset here */
586
587 if(0 == pollrc) {
588 /* timeout! */
589 ev->ms = 0;
590 /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
591 mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
592 &ev->running_handles);
593 }
594 else if(pollrc > 0) {
595 /* loop over the monitored sockets to see which ones had activity */
596 for(i = 0; i< numfds; i++) {
597 if(fds[i].revents) {
598 /* socket activity, tell libcurl */
599 int act = poll2cselect(fds[i].revents); /* convert */
600 infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n",
601 fds[i].fd);
602 mcode = curl_multi_socket_action(multi, fds[i].fd, act,
603 &ev->running_handles);
604 }
605 }
606
607 if(!ev->msbump) {
608 /* If nothing updated the timeout, we decrease it by the spent time.
609 * If it was updated, it has the new timeout time stored already.
610 */
611 timediff_t timediff = Curl_timediff(after, before);
612 if(timediff > 0) {
613 if(timediff > ev->ms)
614 ev->ms = 0;
615 else
616 ev->ms -= (long)timediff;
617 }
618 }
619 }
620 else
621 return CURLE_RECV_ERROR;
622
623 if(mcode)
624 return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */
625
626 /* we don't really care about the "msgs_in_queue" value returned in the
627 second argument */
628 msg = curl_multi_info_read(multi, &pollrc);
629 if(msg) {
630 result = msg->data.result;
631 done = TRUE;
632 }
633 }
634
635 return result;
636}
637
638
639/* easy_events()
640 *
641 * Runs a transfer in a blocking manner using the events-based API
642 */
643static CURLcode easy_events(struct Curl_multi *multi)
644{
645 /* this struct is made static to allow it to be used after this function
646 returns and curl_multi_remove_handle() is called */
647 static struct events evs = {2, FALSE, 0, NULL, 0};
648
649 /* if running event-based, do some further multi inits */
650 events_setup(multi, &evs);
651
652 return wait_or_timeout(multi, &evs);
653}
654#else /* CURLDEBUG */
655/* when not built with debug, this function doesn't exist */
656#define easy_events(x) CURLE_NOT_BUILT_IN
657#endif
658
659static CURLcode easy_transfer(struct Curl_multi *multi)
660{
661 bool done = FALSE;
662 CURLMcode mcode = CURLM_OK;
663 CURLcode result = CURLE_OK;
664
665 while(!done && !mcode) {
666 int still_running = 0;
667 bool gotsocket = FALSE;
668
669 mcode = Curl_multi_wait(multi, NULL, 0, 1000, NULL, &gotsocket);
670
671 if(!mcode) {
672 if(!gotsocket) {
673 long sleep_ms;
674
675 /* If it returns without any filedescriptor instantly, we need to
676 avoid busy-looping during periods where it has nothing particular
677 to wait for */
678 curl_multi_timeout(multi, &sleep_ms);
679 if(sleep_ms) {
680 if(sleep_ms > 1000)
681 sleep_ms = 1000;
682 Curl_wait_ms((int)sleep_ms);
683 }
684 }
685
686 mcode = curl_multi_perform(multi, &still_running);
687 }
688
689 /* only read 'still_running' if curl_multi_perform() return OK */
690 if(!mcode && !still_running) {
691 int rc;
692 CURLMsg *msg = curl_multi_info_read(multi, &rc);
693 if(msg) {
694 result = msg->data.result;
695 done = TRUE;
696 }
697 }
698 }
699
700 /* Make sure to return some kind of error if there was a multi problem */
701 if(mcode) {
702 result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
703 /* The other multi errors should never happen, so return
704 something suitably generic */
705 CURLE_BAD_FUNCTION_ARGUMENT;
706 }
707
708 return result;
709}
710
711
712/*
713 * easy_perform() is the external interface that performs a blocking
714 * transfer as previously setup.
715 *
716 * CONCEPT: This function creates a multi handle, adds the easy handle to it,
717 * runs curl_multi_perform() until the transfer is done, then detaches the
718 * easy handle, destroys the multi handle and returns the easy handle's return
719 * code.
720 *
721 * REALITY: it can't just create and destroy the multi handle that easily. It
722 * needs to keep it around since if this easy handle is used again by this
723 * function, the same multi handle must be re-used so that the same pools and
724 * caches can be used.
725 *
726 * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
727 * instead of curl_multi_perform() and use curl_multi_socket_action().
728 */
729static CURLcode easy_perform(struct Curl_easy *data, bool events)
730{
731 struct Curl_multi *multi;
732 CURLMcode mcode;
733 CURLcode result = CURLE_OK;
734 SIGPIPE_VARIABLE(pipe_st);
735
736 if(!data)
737 return CURLE_BAD_FUNCTION_ARGUMENT;
738
739 if(data->set.errorbuffer)
740 /* clear this as early as possible */
741 data->set.errorbuffer[0] = 0;
742
743 if(data->multi) {
744 failf(data, "easy handle already used in multi handle");
745 return CURLE_FAILED_INIT;
746 }
747
748 if(data->multi_easy)
749 multi = data->multi_easy;
750 else {
751 /* this multi handle will only ever have a single easy handled attached
752 to it, so make it use minimal hashes */
753 multi = Curl_multi_handle(1, 3);
754 if(!multi)
755 return CURLE_OUT_OF_MEMORY;
756 data->multi_easy = multi;
757 }
758
759 if(multi->in_callback)
760 return CURLE_RECURSIVE_API_CALL;
761
762 /* Copy the MAXCONNECTS option to the multi handle */
763 curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
764
765 mcode = curl_multi_add_handle(multi, data);
766 if(mcode) {
767 curl_multi_cleanup(multi);
768 if(mcode == CURLM_OUT_OF_MEMORY)
769 return CURLE_OUT_OF_MEMORY;
770 return CURLE_FAILED_INIT;
771 }
772
773 sigpipe_ignore(data, &pipe_st);
774
775 /* assign this after curl_multi_add_handle() since that function checks for
776 it and rejects this handle otherwise */
777 data->multi = multi;
778
779 /* run the transfer */
780 result = events ? easy_events(multi) : easy_transfer(multi);
781
782 /* ignoring the return code isn't nice, but atm we can't really handle
783 a failure here, room for future improvement! */
784 (void)curl_multi_remove_handle(multi, data);
785
786 sigpipe_restore(&pipe_st);
787
788 /* The multi handle is kept alive, owned by the easy handle */
789 return result;
790}
791
792
793/*
794 * curl_easy_perform() is the external interface that performs a blocking
795 * transfer as previously setup.
796 */
797CURLcode curl_easy_perform(struct Curl_easy *data)
798{
799 return easy_perform(data, FALSE);
800}
801
802#ifdef CURLDEBUG
803/*
804 * curl_easy_perform_ev() is the external interface that performs a blocking
805 * transfer using the event-based API internally.
806 */
807CURLcode curl_easy_perform_ev(struct Curl_easy *data)
808{
809 return easy_perform(data, TRUE);
810}
811
812#endif
813
814/*
815 * curl_easy_cleanup() is the external interface to cleaning/freeing the given
816 * easy handle.
817 */
818void curl_easy_cleanup(struct Curl_easy *data)
819{
820 SIGPIPE_VARIABLE(pipe_st);
821
822 if(!data)
823 return;
824
825 sigpipe_ignore(data, &pipe_st);
826 Curl_close(data);
827 sigpipe_restore(&pipe_st);
828}
829
830/*
831 * curl_easy_getinfo() is an external interface that allows an app to retrieve
832 * information from a performed transfer and similar.
833 */
834#undef curl_easy_getinfo
835CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
836{
837 va_list arg;
838 void *paramp;
839 CURLcode result;
840
841 va_start(arg, info);
842 paramp = va_arg(arg, void *);
843
844 result = Curl_getinfo(data, info, paramp);
845
846 va_end(arg);
847 return result;
848}
849
850static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
851{
852 CURLcode result = CURLE_OK;
853 enum dupstring i;
854
855 /* Copy src->set into dst->set first, then deal with the strings
856 afterwards */
857 dst->set = src->set;
858 Curl_mime_initpart(&dst->set.mimepost, dst);
859
860 /* clear all string pointers first */
861 memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
862
863 /* duplicate all strings */
864 for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
865 result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
866 if(result)
867 return result;
868 }
869
870 /* duplicate memory areas pointed to */
871 i = STRING_COPYPOSTFIELDS;
872 if(src->set.postfieldsize && src->set.str[i]) {
873 /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
874 dst->set.str[i] = Curl_memdup(src->set.str[i],
875 curlx_sotouz(src->set.postfieldsize));
876 if(!dst->set.str[i])
877 return CURLE_OUT_OF_MEMORY;
878 /* point to the new copy */
879 dst->set.postfields = dst->set.str[i];
880 }
881
882 /* Duplicate mime data. */
883 result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
884
885 if(src->set.resolve)
886 dst->change.resolve = dst->set.resolve;
887
888 return result;
889}
890
891/*
892 * curl_easy_duphandle() is an external interface to allow duplication of a
893 * given input easy handle. The returned handle will be a new working handle
894 * with all options set exactly as the input source handle.
895 */
896struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
897{
898 struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
899 if(NULL == outcurl)
900 goto fail;
901
902 /*
903 * We setup a few buffers we need. We should probably make them
904 * get setup on-demand in the code, as that would probably decrease
905 * the likeliness of us forgetting to init a buffer here in the future.
906 */
907 outcurl->set.buffer_size = data->set.buffer_size;
908 outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1);
909 if(!outcurl->state.buffer)
910 goto fail;
911
912 outcurl->state.headerbuff = malloc(HEADERSIZE);
913 if(!outcurl->state.headerbuff)
914 goto fail;
915 outcurl->state.headersize = HEADERSIZE;
916
917 /* copy all userdefined values */
918 if(dupset(outcurl, data))
919 goto fail;
920
921 /* the connection cache is setup on demand */
922 outcurl->state.conn_cache = NULL;
923
924 outcurl->state.lastconnect = NULL;
925
926 outcurl->progress.flags = data->progress.flags;
927 outcurl->progress.callback = data->progress.callback;
928
929 if(data->cookies) {
930 /* If cookies are enabled in the parent handle, we enable them
931 in the clone as well! */
932 outcurl->cookies = Curl_cookie_init(data,
933 data->cookies->filename,
934 outcurl->cookies,
935 data->set.cookiesession);
936 if(!outcurl->cookies)
937 goto fail;
938 }
939
940 /* duplicate all values in 'change' */
941 if(data->change.cookielist) {
942 outcurl->change.cookielist =
943 Curl_slist_duplicate(data->change.cookielist);
944 if(!outcurl->change.cookielist)
945 goto fail;
946 }
947
948 if(data->change.url) {
949 outcurl->change.url = strdup(data->change.url);
950 if(!outcurl->change.url)
951 goto fail;
952 outcurl->change.url_alloc = TRUE;
953 }
954
955 if(data->change.referer) {
956 outcurl->change.referer = strdup(data->change.referer);
957 if(!outcurl->change.referer)
958 goto fail;
959 outcurl->change.referer_alloc = TRUE;
960 }
961
962 /* Reinitialize an SSL engine for the new handle
963 * note: the engine name has already been copied by dupset */
964 if(outcurl->set.str[STRING_SSL_ENGINE]) {
965 if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
966 goto fail;
967 }
968
969 /* Clone the resolver handle, if present, for the new handle */
970 if(Curl_resolver_duphandle(outcurl,
971 &outcurl->state.resolver,
972 data->state.resolver))
973 goto fail;
974
975 Curl_convert_setup(outcurl);
976
977 Curl_initinfo(outcurl);
978
979 outcurl->magic = CURLEASY_MAGIC_NUMBER;
980
981 /* we reach this point and thus we are OK */
982
983 return outcurl;
984
985 fail:
986
987 if(outcurl) {
988 curl_slist_free_all(outcurl->change.cookielist);
989 outcurl->change.cookielist = NULL;
990 Curl_safefree(outcurl->state.buffer);
991 Curl_safefree(outcurl->state.headerbuff);
992 Curl_safefree(outcurl->change.url);
993 Curl_safefree(outcurl->change.referer);
994 Curl_freeset(outcurl);
995 free(outcurl);
996 }
997
998 return NULL;
999}
1000
1001/*
1002 * curl_easy_reset() is an external interface that allows an app to re-
1003 * initialize a session handle to the default values.
1004 */
1005void curl_easy_reset(struct Curl_easy *data)
1006{
1007 Curl_free_request_state(data);
1008
1009 /* zero out UserDefined data: */
1010 Curl_freeset(data);
1011 memset(&data->set, 0, sizeof(struct UserDefined));
1012 (void)Curl_init_userdefined(data);
1013
1014 /* zero out Progress data: */
1015 memset(&data->progress, 0, sizeof(struct Progress));
1016
1017 /* zero out PureInfo data: */
1018 Curl_initinfo(data);
1019
1020 data->progress.flags |= PGRS_HIDE;
1021 data->state.current_speed = -1; /* init to negative == impossible */
1022
1023 /* zero out authentication data: */
1024 memset(&data->state.authhost, 0, sizeof(struct auth));
1025 memset(&data->state.authproxy, 0, sizeof(struct auth));
1026 Curl_digest_cleanup(data);
1027}
1028
1029/*
1030 * curl_easy_pause() allows an application to pause or unpause a specific
1031 * transfer and direction. This function sets the full new state for the
1032 * current connection this easy handle operates on.
1033 *
1034 * NOTE: if you have the receiving paused and you call this function to remove
1035 * the pausing, you may get your write callback called at this point.
1036 *
1037 * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
1038 *
1039 * NOTE: This is one of few API functions that are allowed to be called from
1040 * within a callback.
1041 */
1042CURLcode curl_easy_pause(struct Curl_easy *data, int action)
1043{
1044 struct SingleRequest *k = &data->req;
1045 CURLcode result = CURLE_OK;
1046
1047 /* first switch off both pause bits */
1048 int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
1049
1050 /* set the new desired pause bits */
1051 newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
1052 ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
1053
1054 /* put it back in the keepon */
1055 k->keepon = newstate;
1056
1057 if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) {
1058 /* there are buffers for sending that can be delivered as the receive
1059 pausing is lifted! */
1060 unsigned int i;
1061 unsigned int count = data->state.tempcount;
1062 struct tempbuf writebuf[3]; /* there can only be three */
1063 struct connectdata *conn = data->conn;
1064 struct Curl_easy *saved_data = NULL;
1065
1066 /* copy the structs to allow for immediate re-pausing */
1067 for(i = 0; i < data->state.tempcount; i++) {
1068 writebuf[i] = data->state.tempwrite[i];
1069 data->state.tempwrite[i].buf = NULL;
1070 }
1071 data->state.tempcount = 0;
1072
1073 /* set the connection's current owner */
1074 if(conn->data != data) {
1075 saved_data = conn->data;
1076 conn->data = data;
1077 }
1078
1079 for(i = 0; i < count; i++) {
1080 /* even if one function returns error, this loops through and frees all
1081 buffers */
1082 if(!result)
1083 result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
1084 writebuf[i].len);
1085 free(writebuf[i].buf);
1086 }
1087
1088 /* recover previous owner of the connection */
1089 if(saved_data)
1090 conn->data = saved_data;
1091
1092 if(result)
1093 return result;
1094 }
1095
1096 /* if there's no error and we're not pausing both directions, we want
1097 to have this handle checked soon */
1098 if(!result &&
1099 ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
1100 (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) )
1101 Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
1102
1103 /* This transfer may have been moved in or out of the bundle, update
1104 the corresponding socket callback, if used */
1105 Curl_updatesocket(data);
1106
1107 return result;
1108}
1109
1110
1111static CURLcode easy_connection(struct Curl_easy *data,
1112 curl_socket_t *sfd,
1113 struct connectdata **connp)
1114{
1115 if(data == NULL)
1116 return CURLE_BAD_FUNCTION_ARGUMENT;
1117
1118 /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
1119 if(!data->set.connect_only) {
1120 failf(data, "CONNECT_ONLY is required!");
1121 return CURLE_UNSUPPORTED_PROTOCOL;
1122 }
1123
1124 *sfd = Curl_getconnectinfo(data, connp);
1125
1126 if(*sfd == CURL_SOCKET_BAD) {
1127 failf(data, "Failed to get recent socket");
1128 return CURLE_UNSUPPORTED_PROTOCOL;
1129 }
1130
1131 return CURLE_OK;
1132}
1133
1134/*
1135 * Receives data from the connected socket. Use after successful
1136 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1137 * Returns CURLE_OK on success, error code on error.
1138 */
1139CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
1140 size_t *n)
1141{
1142 curl_socket_t sfd;
1143 CURLcode result;
1144 ssize_t n1;
1145 struct connectdata *c;
1146
1147 if(Curl_is_in_callback(data))
1148 return CURLE_RECURSIVE_API_CALL;
1149
1150 result = easy_connection(data, &sfd, &c);
1151 if(result)
1152 return result;
1153
1154 *n = 0;
1155 result = Curl_read(c, sfd, buffer, buflen, &n1);
1156
1157 if(result)
1158 return result;
1159
1160 *n = (size_t)n1;
1161
1162 return CURLE_OK;
1163}
1164
1165/*
1166 * Sends data over the connected socket. Use after successful
1167 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
1168 */
1169CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
1170 size_t buflen, size_t *n)
1171{
1172 curl_socket_t sfd;
1173 CURLcode result;
1174 ssize_t n1;
1175 struct connectdata *c = NULL;
1176
1177 if(Curl_is_in_callback(data))
1178 return CURLE_RECURSIVE_API_CALL;
1179
1180 result = easy_connection(data, &sfd, &c);
1181 if(result)
1182 return result;
1183
1184 *n = 0;
1185 result = Curl_write(c, sfd, buffer, buflen, &n1);
1186
1187 if(n1 == -1)
1188 return CURLE_SEND_ERROR;
1189
1190 /* detect EAGAIN */
1191 if(!result && !n1)
1192 return CURLE_AGAIN;
1193
1194 *n = (size_t)n1;
1195
1196 return result;
1197}
1198
1199/*
1200 * Performs connection upkeep for the given session handle.
1201 */
1202CURLcode curl_easy_upkeep(struct Curl_easy *data)
1203{
1204 /* Verify that we got an easy handle we can work with. */
1205 if(!GOOD_EASY_HANDLE(data))
1206 return CURLE_BAD_FUNCTION_ARGUMENT;
1207
1208 if(data->multi_easy) {
1209 /* Use the common function to keep connections alive. */
1210 return Curl_upkeep(&data->multi_easy->conn_cache, data);
1211 }
1212 else {
1213 /* No connections, so just return success */
1214 return CURLE_OK;
1215 }
1216}
Note: See TracBrowser for help on using the repository browser.

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