source: asp3_tinet_ecnl_rx/trunk/curl-7.57.0/lib/easy.c@ 337

Last change on this file since 337 was 337, checked in by coas-nagasima, 6 years ago

ASP3版ECNLを追加

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