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