easy.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 /*
00026  * See comment in curl_memory.h for the explanation of this sanity check.
00027  */
00028 
00029 #ifdef CURLX_NO_MEMORY_CALLBACKS
00030 #error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined"
00031 #endif
00032 
00033 #ifdef HAVE_NETINET_IN_H
00034 #include <netinet/in.h>
00035 #endif
00036 #ifdef HAVE_NETDB_H
00037 #include <netdb.h>
00038 #endif
00039 #ifdef HAVE_ARPA_INET_H
00040 #include <arpa/inet.h>
00041 #endif
00042 #ifdef HAVE_NET_IF_H
00043 #include <net/if.h>
00044 #endif
00045 #ifdef HAVE_SYS_IOCTL_H
00046 #include <sys/ioctl.h>
00047 #endif
00048 
00049 #ifdef HAVE_SYS_PARAM_H
00050 #include <sys/param.h>
00051 #endif
00052 
00053 #include "urldata.h"
00054 #include <curl/curl.h>
00055 #include "transfer.h"
00056 #include "vtls/vtls.h"
00057 #include "url.h"
00058 #include "getinfo.h"
00059 #include "hostip.h"
00060 #include "share.h"
00061 #include "strdup.h"
00062 #include "progress.h"
00063 #include "easyif.h"
00064 #include "select.h"
00065 #include "sendf.h" /* for failf function prototype */
00066 #include "connect.h" /* for Curl_getconnectinfo */
00067 #include "slist.h"
00068 #include "amigaos.h"
00069 #include "non-ascii.h"
00070 #include "warnless.h"
00071 #include "conncache.h"
00072 #include "multiif.h"
00073 #include "sigpipe.h"
00074 #include "ssh.h"
00075 /* The last 3 #include files should be in this order */
00076 #include "curl_printf.h"
00077 #include "curl_memory.h"
00078 #include "memdebug.h"
00079 
00080 void Curl_version_init(void);
00081 
00082 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
00083    of win32_init() */
00084 static void win32_cleanup(void)
00085 {
00086 #ifdef USE_WINSOCK
00087   WSACleanup();
00088 #endif
00089 #ifdef USE_WINDOWS_SSPI
00090   Curl_sspi_global_cleanup();
00091 #endif
00092 }
00093 
00094 /* win32_init() performs win32 socket initialization to properly setup the
00095    stack to allow networking */
00096 static CURLcode win32_init(void)
00097 {
00098 #ifdef USE_WINSOCK
00099   WORD wVersionRequested;
00100   WSADATA wsaData;
00101   int res;
00102 
00103 #if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
00104   Error IPV6_requires_winsock2
00105 #endif
00106 
00107   wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
00108 
00109   res = WSAStartup(wVersionRequested, &wsaData);
00110 
00111   if(res != 0)
00112     /* Tell the user that we couldn't find a useable */
00113     /* winsock.dll.     */
00114     return CURLE_FAILED_INIT;
00115 
00116   /* Confirm that the Windows Sockets DLL supports what we need.*/
00117   /* Note that if the DLL supports versions greater */
00118   /* than wVersionRequested, it will still return */
00119   /* wVersionRequested in wVersion. wHighVersion contains the */
00120   /* highest supported version. */
00121 
00122   if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
00123      HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
00124     /* Tell the user that we couldn't find a useable */
00125 
00126     /* winsock.dll. */
00127     WSACleanup();
00128     return CURLE_FAILED_INIT;
00129   }
00130   /* The Windows Sockets DLL is acceptable. Proceed. */
00131 #elif defined(USE_LWIPSOCK)
00132   lwip_init();
00133 #endif
00134 
00135 #ifdef USE_WINDOWS_SSPI
00136   {
00137     CURLcode result = Curl_sspi_global_init();
00138     if(result)
00139       return result;
00140   }
00141 #endif
00142 
00143   return CURLE_OK;
00144 }
00145 
00146 /* true globals -- for curl_global_init() and curl_global_cleanup() */
00147 static unsigned int  initialized;
00148 static long          init_flags;
00149 
00150 /*
00151  * strdup (and other memory functions) is redefined in complicated
00152  * ways, but at this point it must be defined as the system-supplied strdup
00153  * so the callback pointer is initialized correctly.
00154  */
00155 #if defined(_WIN32_WCE)
00156 #define system_strdup _strdup
00157 #elif !defined(HAVE_STRDUP)
00158 #define system_strdup curlx_strdup
00159 #else
00160 #define system_strdup strdup
00161 #endif
00162 
00163 #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
00164 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
00165 #endif
00166 
00167 #ifndef __SYMBIAN32__
00168 /*
00169  * If a memory-using function (like curl_getenv) is used before
00170  * curl_global_init() is called, we need to have these pointers set already.
00171  */
00172 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
00173 curl_free_callback Curl_cfree = (curl_free_callback)free;
00174 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
00175 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
00176 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
00177 #if defined(WIN32) && defined(UNICODE)
00178 curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
00179 #endif
00180 #else
00181 /*
00182  * Symbian OS doesn't support initialization to code in writeable static data.
00183  * Initialization will occur in the curl_global_init() call.
00184  */
00185 curl_malloc_callback Curl_cmalloc;
00186 curl_free_callback Curl_cfree;
00187 curl_realloc_callback Curl_crealloc;
00188 curl_strdup_callback Curl_cstrdup;
00189 curl_calloc_callback Curl_ccalloc;
00190 #endif
00191 
00192 #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
00193 #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
00194 #endif
00195 
00200 static CURLcode global_init(long flags, bool memoryfuncs)
00201 {
00202   if(initialized++)
00203     return CURLE_OK;
00204 
00205   if(memoryfuncs) {
00206     /* Setup the default memory functions here (again) */
00207     Curl_cmalloc = (curl_malloc_callback)malloc;
00208     Curl_cfree = (curl_free_callback)free;
00209     Curl_crealloc = (curl_realloc_callback)realloc;
00210     Curl_cstrdup = (curl_strdup_callback)system_strdup;
00211     Curl_ccalloc = (curl_calloc_callback)calloc;
00212 #if defined(WIN32) && defined(UNICODE)
00213     Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
00214 #endif
00215   }
00216 
00217   if(flags & CURL_GLOBAL_SSL)
00218     if(!Curl_ssl_init()) {
00219       DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
00220       return CURLE_FAILED_INIT;
00221     }
00222 
00223   if(flags & CURL_GLOBAL_WIN32)
00224     if(win32_init()) {
00225       DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
00226       return CURLE_FAILED_INIT;
00227     }
00228 
00229 #ifdef __AMIGA__
00230   if(!Curl_amiga_init()) {
00231     DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
00232     return CURLE_FAILED_INIT;
00233   }
00234 #endif
00235 
00236 #ifdef NETWARE
00237   if(netware_init()) {
00238     DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
00239   }
00240 #endif
00241 
00242   if(Curl_resolver_global_init()) {
00243     DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
00244     return CURLE_FAILED_INIT;
00245   }
00246 
00247   (void)Curl_ipv6works();
00248 
00249 #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT)
00250   if(libssh2_init(0)) {
00251     DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
00252     return CURLE_FAILED_INIT;
00253   }
00254 #endif
00255 
00256   if(flags & CURL_GLOBAL_ACK_EINTR)
00257     Curl_ack_eintr = 1;
00258 
00259   init_flags = flags;
00260 
00261   Curl_version_init();
00262 
00263   return CURLE_OK;
00264 }
00265 
00266 
00271 CURLcode curl_global_init(long flags)
00272 {
00273   return global_init(flags, TRUE);
00274 }
00275 
00276 /*
00277  * curl_global_init_mem() globally initializes curl and also registers the
00278  * user provided callback routines.
00279  */
00280 CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
00281                               curl_free_callback f, curl_realloc_callback r,
00282                               curl_strdup_callback s, curl_calloc_callback c)
00283 {
00284   /* Invalid input, return immediately */
00285   if(!m || !f || !r || !s || !c)
00286     return CURLE_FAILED_INIT;
00287 
00288   if(initialized) {
00289     /* Already initialized, don't do it again, but bump the variable anyway to
00290        work like curl_global_init() and require the same amount of cleanup
00291        calls. */
00292     initialized++;
00293     return CURLE_OK;
00294   }
00295 
00296   /* set memory functions before global_init() in case it wants memory
00297      functions */
00298   Curl_cmalloc = m;
00299   Curl_cfree = f;
00300   Curl_cstrdup = s;
00301   Curl_crealloc = r;
00302   Curl_ccalloc = c;
00303 
00304   /* Call the actual init function, but without setting */
00305   return global_init(flags, FALSE);
00306 }
00307 
00312 void curl_global_cleanup(void)
00313 {
00314   if(!initialized)
00315     return;
00316 
00317   if(--initialized)
00318     return;
00319 
00320   Curl_global_host_cache_dtor();
00321 
00322   if(init_flags & CURL_GLOBAL_SSL)
00323     Curl_ssl_cleanup();
00324 
00325   Curl_resolver_global_cleanup();
00326 
00327   if(init_flags & CURL_GLOBAL_WIN32)
00328     win32_cleanup();
00329 
00330   Curl_amiga_cleanup();
00331 
00332 #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT)
00333   (void)libssh2_exit();
00334 #endif
00335 
00336   init_flags  = 0;
00337 }
00338 
00339 /*
00340  * curl_easy_init() is the external interface to alloc, setup and init an
00341  * easy handle that is returned. If anything goes wrong, NULL is returned.
00342  */
00343 struct Curl_easy *curl_easy_init(void)
00344 {
00345   CURLcode result;
00346   struct Curl_easy *data;
00347 
00348   /* Make sure we inited the global SSL stuff */
00349   if(!initialized) {
00350     result = curl_global_init(CURL_GLOBAL_DEFAULT);
00351     if(result) {
00352       /* something in the global init failed, return nothing */
00353       DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
00354       return NULL;
00355     }
00356   }
00357 
00358   /* We use curl_open() with undefined URL so far */
00359   result = Curl_open(&data);
00360   if(result) {
00361     DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
00362     return NULL;
00363   }
00364 
00365   return data;
00366 }
00367 
00368 /*
00369  * curl_easy_setopt() is the external interface for setting options on an
00370  * easy handle.
00371  */
00372 
00373 #undef curl_easy_setopt
00374 CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
00375 {
00376   va_list arg;
00377   CURLcode result;
00378 
00379   if(!data)
00380     return CURLE_BAD_FUNCTION_ARGUMENT;
00381 
00382   va_start(arg, tag);
00383 
00384   result = Curl_setopt(data, tag, arg);
00385 
00386   va_end(arg);
00387   return result;
00388 }
00389 
00390 #ifdef CURLDEBUG
00391 
00392 struct socketmonitor {
00393   struct socketmonitor *next; /* the next node in the list or NULL */
00394   struct pollfd socket; /* socket info of what to monitor */
00395 };
00396 
00397 struct events {
00398   long ms;              /* timeout, run the timeout function when reached */
00399   bool msbump;          /* set TRUE when timeout is set by callback */
00400   int num_sockets;      /* number of nodes in the monitor list */
00401   struct socketmonitor *list; /* list of sockets to monitor */
00402   int running_handles;  /* store the returned number */
00403 };
00404 
00405 /* events_timer
00406  *
00407  * Callback that gets called with a new value when the timeout should be
00408  * updated.
00409  */
00410 
00411 static int events_timer(struct Curl_multi *multi,    /* multi handle */
00412                         long timeout_ms, /* see above */
00413                         void *userp)    /* private callback pointer */
00414 {
00415   struct events *ev = userp;
00416   (void)multi;
00417   if(timeout_ms == -1)
00418     /* timeout removed */
00419     timeout_ms = 0;
00420   else if(timeout_ms == 0)
00421     /* timeout is already reached! */
00422     timeout_ms = 1; /* trigger asap */
00423 
00424   ev->ms = timeout_ms;
00425   ev->msbump = TRUE;
00426   return 0;
00427 }
00428 
00429 
00430 /* poll2cselect
00431  *
00432  * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
00433  */
00434 static int poll2cselect(int pollmask)
00435 {
00436   int omask=0;
00437   if(pollmask & POLLIN)
00438     omask |= CURL_CSELECT_IN;
00439   if(pollmask & POLLOUT)
00440     omask |= CURL_CSELECT_OUT;
00441   if(pollmask & POLLERR)
00442     omask |= CURL_CSELECT_ERR;
00443   return omask;
00444 }
00445 
00446 
00447 /* socketcb2poll
00448  *
00449  * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
00450  */
00451 static short socketcb2poll(int pollmask)
00452 {
00453   short omask=0;
00454   if(pollmask & CURL_POLL_IN)
00455     omask |= POLLIN;
00456   if(pollmask & CURL_POLL_OUT)
00457     omask |= POLLOUT;
00458   return omask;
00459 }
00460 
00461 /* events_socket
00462  *
00463  * Callback that gets called with information about socket activity to
00464  * monitor.
00465  */
00466 static int events_socket(struct Curl_easy *easy,      /* easy handle */
00467                          curl_socket_t s, /* socket */
00468                          int what,        /* see above */
00469                          void *userp,     /* private callback
00470                                              pointer */
00471                          void *socketp)   /* private socket
00472                                              pointer */
00473 {
00474   struct events *ev = userp;
00475   struct socketmonitor *m;
00476   struct socketmonitor *prev=NULL;
00477 
00478 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
00479   (void) easy;
00480 #endif
00481   (void)socketp;
00482 
00483   m = ev->list;
00484   while(m) {
00485     if(m->socket.fd == s) {
00486 
00487       if(what == CURL_POLL_REMOVE) {
00488         struct socketmonitor *nxt = m->next;
00489         /* remove this node from the list of monitored sockets */
00490         if(prev)
00491           prev->next = nxt;
00492         else
00493           ev->list = nxt;
00494         free(m);
00495         m = nxt;
00496         infof(easy, "socket cb: socket %d REMOVED\n", s);
00497       }
00498       else {
00499         /* The socket 's' is already being monitored, update the activity
00500            mask. Convert from libcurl bitmask to the poll one. */
00501         m->socket.events = socketcb2poll(what);
00502         infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
00503               what&CURL_POLL_IN?"IN":"",
00504               what&CURL_POLL_OUT?"OUT":"");
00505       }
00506       break;
00507     }
00508     prev = m;
00509     m = m->next; /* move to next node */
00510   }
00511   if(!m) {
00512     if(what == CURL_POLL_REMOVE) {
00513       /* this happens a bit too often, libcurl fix perhaps? */
00514       /* fprintf(stderr,
00515          "%s: socket %d asked to be REMOVED but not present!\n",
00516                  __func__, s); */
00517     }
00518     else {
00519       m = malloc(sizeof(struct socketmonitor));
00520       if(m) {
00521         m->next = ev->list;
00522         m->socket.fd = s;
00523         m->socket.events = socketcb2poll(what);
00524         m->socket.revents = 0;
00525         ev->list = m;
00526         infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
00527               what&CURL_POLL_IN?"IN":"",
00528               what&CURL_POLL_OUT?"OUT":"");
00529       }
00530       else
00531         return CURLE_OUT_OF_MEMORY;
00532     }
00533   }
00534 
00535   return 0;
00536 }
00537 
00538 
00539 /*
00540  * events_setup()
00541  *
00542  * Do the multi handle setups that only event-based transfers need.
00543  */
00544 static void events_setup(struct Curl_multi *multi, struct events *ev)
00545 {
00546   /* timer callback */
00547   curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
00548   curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
00549 
00550   /* socket callback */
00551   curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
00552   curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
00553 }
00554 
00555 
00556 /* wait_or_timeout()
00557  *
00558  * waits for activity on any of the given sockets, or the timeout to trigger.
00559  */
00560 
00561 static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
00562 {
00563   bool done = FALSE;
00564   CURLMcode mcode;
00565   CURLcode result = CURLE_OK;
00566 
00567   while(!done) {
00568     CURLMsg *msg;
00569     struct socketmonitor *m;
00570     struct pollfd *f;
00571     struct pollfd fds[4];
00572     int numfds=0;
00573     int pollrc;
00574     int i;
00575     struct timeval before;
00576     struct timeval after;
00577 
00578     /* populate the fds[] array */
00579     for(m = ev->list, f=&fds[0]; m; m = m->next) {
00580       f->fd = m->socket.fd;
00581       f->events = m->socket.events;
00582       f->revents = 0;
00583       /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
00584       f++;
00585       numfds++;
00586     }
00587 
00588     /* get the time stamp to use to figure out how long poll takes */
00589     before = curlx_tvnow();
00590 
00591     /* wait for activity or timeout */
00592     pollrc = Curl_poll(fds, numfds, (int)ev->ms);
00593 
00594     after = curlx_tvnow();
00595 
00596     ev->msbump = FALSE; /* reset here */
00597 
00598     if(0 == pollrc) {
00599       /* timeout! */
00600       ev->ms = 0;
00601       /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
00602       mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
00603                                        &ev->running_handles);
00604     }
00605     else if(pollrc > 0) {
00606       /* loop over the monitored sockets to see which ones had activity */
00607       for(i = 0; i< numfds; i++) {
00608         if(fds[i].revents) {
00609           /* socket activity, tell libcurl */
00610           int act = poll2cselect(fds[i].revents); /* convert */
00611           infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n",
00612                 fds[i].fd);
00613           mcode = curl_multi_socket_action(multi, fds[i].fd, act,
00614                                            &ev->running_handles);
00615         }
00616       }
00617 
00618       if(!ev->msbump)
00619         /* If nothing updated the timeout, we decrease it by the spent time.
00620          * If it was updated, it has the new timeout time stored already.
00621          */
00622         ev->ms += curlx_tvdiff(after, before);
00623 
00624     }
00625     else
00626       return CURLE_RECV_ERROR;
00627 
00628     if(mcode)
00629       return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */
00630 
00631     /* we don't really care about the "msgs_in_queue" value returned in the
00632        second argument */
00633     msg = curl_multi_info_read(multi, &pollrc);
00634     if(msg) {
00635       result = msg->data.result;
00636       done = TRUE;
00637     }
00638   }
00639 
00640   return result;
00641 }
00642 
00643 
00644 /* easy_events()
00645  *
00646  * Runs a transfer in a blocking manner using the events-based API
00647  */
00648 static CURLcode easy_events(struct Curl_multi *multi)
00649 {
00650   struct events evs= {2, FALSE, 0, NULL, 0};
00651 
00652   /* if running event-based, do some further multi inits */
00653   events_setup(multi, &evs);
00654 
00655   return wait_or_timeout(multi, &evs);
00656 }
00657 #else /* CURLDEBUG */
00658 /* when not built with debug, this function doesn't exist */
00659 #define easy_events(x) CURLE_NOT_BUILT_IN
00660 #endif
00661 
00662 static CURLcode easy_transfer(struct Curl_multi *multi)
00663 {
00664   bool done = FALSE;
00665   CURLMcode mcode = CURLM_OK;
00666   CURLcode result = CURLE_OK;
00667   struct timeval before;
00668   int without_fds = 0;  /* count number of consecutive returns from
00669                            curl_multi_wait() without any filedescriptors */
00670 
00671   while(!done && !mcode) {
00672     int still_running = 0;
00673     int rc;
00674 
00675     before = curlx_tvnow();
00676     mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc);
00677 
00678     if(!mcode) {
00679       if(!rc) {
00680         struct timeval after = curlx_tvnow();
00681 
00682         /* If it returns without any filedescriptor instantly, we need to
00683            avoid busy-looping during periods where it has nothing particular
00684            to wait for */
00685         if(curlx_tvdiff(after, before) <= 10) {
00686           without_fds++;
00687           if(without_fds > 2) {
00688             int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000;
00689             Curl_wait_ms(sleep_ms);
00690           }
00691         }
00692         else
00693           /* it wasn't "instant", restart counter */
00694           without_fds = 0;
00695       }
00696       else
00697         /* got file descriptor, restart counter */
00698         without_fds = 0;
00699 
00700       mcode = curl_multi_perform(multi, &still_running);
00701     }
00702 
00703     /* only read 'still_running' if curl_multi_perform() return OK */
00704     if(!mcode && !still_running) {
00705       CURLMsg *msg = curl_multi_info_read(multi, &rc);
00706       if(msg) {
00707         result = msg->data.result;
00708         done = TRUE;
00709       }
00710     }
00711   }
00712 
00713   /* Make sure to return some kind of error if there was a multi problem */
00714   if(mcode) {
00715     result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
00716               /* The other multi errors should never happen, so return
00717                  something suitably generic */
00718               CURLE_BAD_FUNCTION_ARGUMENT;
00719   }
00720 
00721   return result;
00722 }
00723 
00724 
00725 /*
00726  * easy_perform() is the external interface that performs a blocking
00727  * transfer as previously setup.
00728  *
00729  * CONCEPT: This function creates a multi handle, adds the easy handle to it,
00730  * runs curl_multi_perform() until the transfer is done, then detaches the
00731  * easy handle, destroys the multi handle and returns the easy handle's return
00732  * code.
00733  *
00734  * REALITY: it can't just create and destroy the multi handle that easily. It
00735  * needs to keep it around since if this easy handle is used again by this
00736  * function, the same multi handle must be re-used so that the same pools and
00737  * caches can be used.
00738  *
00739  * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
00740  * instead of curl_multi_perform() and use curl_multi_socket_action().
00741  */
00742 static CURLcode easy_perform(struct Curl_easy *data, bool events)
00743 {
00744   struct Curl_multi *multi;
00745   CURLMcode mcode;
00746   CURLcode result = CURLE_OK;
00747   SIGPIPE_VARIABLE(pipe_st);
00748 
00749   if(!data)
00750     return CURLE_BAD_FUNCTION_ARGUMENT;
00751 
00752   if(data->multi) {
00753     failf(data, "easy handle already used in multi handle");
00754     return CURLE_FAILED_INIT;
00755   }
00756 
00757   if(data->multi_easy)
00758     multi = data->multi_easy;
00759   else {
00760     /* this multi handle will only ever have a single easy handled attached
00761        to it, so make it use minimal hashes */
00762     multi = Curl_multi_handle(1, 3);
00763     if(!multi)
00764       return CURLE_OUT_OF_MEMORY;
00765     data->multi_easy = multi;
00766   }
00767 
00768   /* Copy the MAXCONNECTS option to the multi handle */
00769   curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
00770 
00771   mcode = curl_multi_add_handle(multi, data);
00772   if(mcode) {
00773     curl_multi_cleanup(multi);
00774     if(mcode == CURLM_OUT_OF_MEMORY)
00775       return CURLE_OUT_OF_MEMORY;
00776     else
00777       return CURLE_FAILED_INIT;
00778   }
00779 
00780   sigpipe_ignore(data, &pipe_st);
00781 
00782   /* assign this after curl_multi_add_handle() since that function checks for
00783      it and rejects this handle otherwise */
00784   data->multi = multi;
00785 
00786   /* run the transfer */
00787   result = events ? easy_events(multi) : easy_transfer(multi);
00788 
00789   /* ignoring the return code isn't nice, but atm we can't really handle
00790      a failure here, room for future improvement! */
00791   (void)curl_multi_remove_handle(multi, data);
00792 
00793   sigpipe_restore(&pipe_st);
00794 
00795   /* The multi handle is kept alive, owned by the easy handle */
00796   return result;
00797 }
00798 
00799 
00800 /*
00801  * curl_easy_perform() is the external interface that performs a blocking
00802  * transfer as previously setup.
00803  */
00804 CURLcode curl_easy_perform(struct Curl_easy *data)
00805 {
00806   return easy_perform(data, FALSE);
00807 }
00808 
00809 #ifdef CURLDEBUG
00810 /*
00811  * curl_easy_perform_ev() is the external interface that performs a blocking
00812  * transfer using the event-based API internally.
00813  */
00814 CURLcode curl_easy_perform_ev(struct Curl_easy *data)
00815 {
00816   return easy_perform(data, TRUE);
00817 }
00818 
00819 #endif
00820 
00821 /*
00822  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
00823  * easy handle.
00824  */
00825 void curl_easy_cleanup(struct Curl_easy *data)
00826 {
00827   SIGPIPE_VARIABLE(pipe_st);
00828 
00829   if(!data)
00830     return;
00831 
00832   sigpipe_ignore(data, &pipe_st);
00833   Curl_close(data);
00834   sigpipe_restore(&pipe_st);
00835 }
00836 
00837 /*
00838  * curl_easy_getinfo() is an external interface that allows an app to retrieve
00839  * information from a performed transfer and similar.
00840  */
00841 #undef curl_easy_getinfo
00842 CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
00843 {
00844   va_list arg;
00845   void *paramp;
00846   CURLcode result;
00847 
00848   va_start(arg, info);
00849   paramp = va_arg(arg, void *);
00850 
00851   result = Curl_getinfo(data, info, paramp);
00852 
00853   va_end(arg);
00854   return result;
00855 }
00856 
00857 /*
00858  * curl_easy_duphandle() is an external interface to allow duplication of a
00859  * given input easy handle. The returned handle will be a new working handle
00860  * with all options set exactly as the input source handle.
00861  */
00862 struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
00863 {
00864   struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
00865   if(NULL == outcurl)
00866     goto fail;
00867 
00868   /*
00869    * We setup a few buffers we need. We should probably make them
00870    * get setup on-demand in the code, as that would probably decrease
00871    * the likeliness of us forgetting to init a buffer here in the future.
00872    */
00873   outcurl->state.headerbuff = malloc(HEADERSIZE);
00874   if(!outcurl->state.headerbuff)
00875     goto fail;
00876   outcurl->state.headersize = HEADERSIZE;
00877 
00878   /* copy all userdefined values */
00879   if(Curl_dupset(outcurl, data))
00880     goto fail;
00881 
00882   /* the connection cache is setup on demand */
00883   outcurl->state.conn_cache = NULL;
00884 
00885   outcurl->state.lastconnect = NULL;
00886 
00887   outcurl->progress.flags    = data->progress.flags;
00888   outcurl->progress.callback = data->progress.callback;
00889 
00890   if(data->cookies) {
00891     /* If cookies are enabled in the parent handle, we enable them
00892        in the clone as well! */
00893     outcurl->cookies = Curl_cookie_init(data,
00894                                         data->cookies->filename,
00895                                         outcurl->cookies,
00896                                         data->set.cookiesession);
00897     if(!outcurl->cookies)
00898       goto fail;
00899   }
00900 
00901   /* duplicate all values in 'change' */
00902   if(data->change.cookielist) {
00903     outcurl->change.cookielist =
00904       Curl_slist_duplicate(data->change.cookielist);
00905     if(!outcurl->change.cookielist)
00906       goto fail;
00907   }
00908 
00909   if(data->change.url) {
00910     outcurl->change.url = strdup(data->change.url);
00911     if(!outcurl->change.url)
00912       goto fail;
00913     outcurl->change.url_alloc = TRUE;
00914   }
00915 
00916   if(data->change.referer) {
00917     outcurl->change.referer = strdup(data->change.referer);
00918     if(!outcurl->change.referer)
00919       goto fail;
00920     outcurl->change.referer_alloc = TRUE;
00921   }
00922 
00923   /* Clone the resolver handle, if present, for the new handle */
00924   if(Curl_resolver_duphandle(&outcurl->state.resolver,
00925                              data->state.resolver))
00926     goto fail;
00927 
00928   Curl_convert_setup(outcurl);
00929 
00930   Curl_initinfo(outcurl);
00931 
00932   outcurl->magic = CURLEASY_MAGIC_NUMBER;
00933 
00934   /* we reach this point and thus we are OK */
00935 
00936   return outcurl;
00937 
00938   fail:
00939 
00940   if(outcurl) {
00941     curl_slist_free_all(outcurl->change.cookielist);
00942     outcurl->change.cookielist = NULL;
00943     Curl_safefree(outcurl->state.headerbuff);
00944     Curl_safefree(outcurl->change.url);
00945     Curl_safefree(outcurl->change.referer);
00946     Curl_freeset(outcurl);
00947     free(outcurl);
00948   }
00949 
00950   return NULL;
00951 }
00952 
00953 /*
00954  * curl_easy_reset() is an external interface that allows an app to re-
00955  * initialize a session handle to the default values.
00956  */
00957 void curl_easy_reset(struct Curl_easy *data)
00958 {
00959   Curl_safefree(data->state.pathbuffer);
00960 
00961   data->state.path = NULL;
00962 
00963   Curl_free_request_state(data);
00964 
00965   /* zero out UserDefined data: */
00966   Curl_freeset(data);
00967   memset(&data->set, 0, sizeof(struct UserDefined));
00968   (void)Curl_init_userdefined(&data->set);
00969 
00970   /* zero out Progress data: */
00971   memset(&data->progress, 0, sizeof(struct Progress));
00972 
00973   /* zero out PureInfo data: */
00974   Curl_initinfo(data);
00975 
00976   data->progress.flags |= PGRS_HIDE;
00977   data->state.current_speed = -1; /* init to negative == impossible */
00978 }
00979 
00980 /*
00981  * curl_easy_pause() allows an application to pause or unpause a specific
00982  * transfer and direction. This function sets the full new state for the
00983  * current connection this easy handle operates on.
00984  *
00985  * NOTE: if you have the receiving paused and you call this function to remove
00986  * the pausing, you may get your write callback called at this point.
00987  *
00988  * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
00989  */
00990 CURLcode curl_easy_pause(struct Curl_easy *data, int action)
00991 {
00992   struct SingleRequest *k = &data->req;
00993   CURLcode result = CURLE_OK;
00994 
00995   /* first switch off both pause bits */
00996   int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
00997 
00998   /* set the new desired pause bits */
00999   newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
01000     ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
01001 
01002   /* put it back in the keepon */
01003   k->keepon = newstate;
01004 
01005   if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) {
01006     /* we have a buffer for sending that we now seem to be able to deliver
01007        since the receive pausing is lifted! */
01008 
01009     /* get the pointer in local copy since the function may return PAUSE
01010        again and then we'll get a new copy allocted and stored in
01011        the tempwrite variables */
01012     char *tempwrite = data->state.tempwrite;
01013 
01014     data->state.tempwrite = NULL;
01015     result = Curl_client_chop_write(data->easy_conn, data->state.tempwritetype,
01016                                     tempwrite, data->state.tempwritesize);
01017     free(tempwrite);
01018   }
01019 
01020   /* if there's no error and we're not pausing both directions, we want
01021      to have this handle checked soon */
01022   if(!result &&
01023      ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
01024       (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) )
01025     Curl_expire(data, 0); /* get this handle going again */
01026 
01027   return result;
01028 }
01029 
01030 
01031 static CURLcode easy_connection(struct Curl_easy *data,
01032                                 curl_socket_t *sfd,
01033                                 struct connectdata **connp)
01034 {
01035   if(data == NULL)
01036     return CURLE_BAD_FUNCTION_ARGUMENT;
01037 
01038   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
01039   if(!data->set.connect_only) {
01040     failf(data, "CONNECT_ONLY is required!");
01041     return CURLE_UNSUPPORTED_PROTOCOL;
01042   }
01043 
01044   *sfd = Curl_getconnectinfo(data, connp);
01045 
01046   if(*sfd == CURL_SOCKET_BAD) {
01047     failf(data, "Failed to get recent socket");
01048     return CURLE_UNSUPPORTED_PROTOCOL;
01049   }
01050 
01051   return CURLE_OK;
01052 }
01053 
01054 /*
01055  * Receives data from the connected socket. Use after successful
01056  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
01057  * Returns CURLE_OK on success, error code on error.
01058  */
01059 CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
01060                         size_t *n)
01061 {
01062   curl_socket_t sfd;
01063   CURLcode result;
01064   ssize_t n1;
01065   struct connectdata *c;
01066 
01067   result = easy_connection(data, &sfd, &c);
01068   if(result)
01069     return result;
01070 
01071   *n = 0;
01072   result = Curl_read(c, sfd, buffer, buflen, &n1);
01073 
01074   if(result)
01075     return result;
01076 
01077   *n = (size_t)n1;
01078 
01079   return CURLE_OK;
01080 }
01081 
01082 /*
01083  * Sends data over the connected socket. Use after successful
01084  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
01085  */
01086 CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
01087                         size_t buflen, size_t *n)
01088 {
01089   curl_socket_t sfd;
01090   CURLcode result;
01091   ssize_t n1;
01092   struct connectdata *c = NULL;
01093 
01094   result = easy_connection(data, &sfd, &c);
01095   if(result)
01096     return result;
01097 
01098   *n = 0;
01099   result = Curl_write(c, sfd, buffer, buflen, &n1);
01100 
01101   if(n1 == -1)
01102     return CURLE_SEND_ERROR;
01103 
01104   /* detect EAGAIN */
01105   if(!result && !n1)
01106     return CURLE_AGAIN;
01107 
01108   *n = (size_t)n1;
01109 
01110   return result;
01111 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02