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