source: UsbWattMeter/trunk/curl-7.47.1/lib/easy.c@ 164

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

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

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