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