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

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

ファイルディスクリプタ処理を更新

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