113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 2813498266Sopenharmony_ci#include <netinet/in.h> 2913498266Sopenharmony_ci#endif 3013498266Sopenharmony_ci#ifdef HAVE_NETDB_H 3113498266Sopenharmony_ci#include <netdb.h> 3213498266Sopenharmony_ci#endif 3313498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 3413498266Sopenharmony_ci#include <arpa/inet.h> 3513498266Sopenharmony_ci#endif 3613498266Sopenharmony_ci#ifdef HAVE_NET_IF_H 3713498266Sopenharmony_ci#include <net/if.h> 3813498266Sopenharmony_ci#endif 3913498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 4013498266Sopenharmony_ci#include <sys/ioctl.h> 4113498266Sopenharmony_ci#endif 4213498266Sopenharmony_ci 4313498266Sopenharmony_ci#ifdef HAVE_SYS_PARAM_H 4413498266Sopenharmony_ci#include <sys/param.h> 4513498266Sopenharmony_ci#endif 4613498266Sopenharmony_ci 4713498266Sopenharmony_ci#include "urldata.h" 4813498266Sopenharmony_ci#include <curl/curl.h> 4913498266Sopenharmony_ci#include "transfer.h" 5013498266Sopenharmony_ci#include "vtls/vtls.h" 5113498266Sopenharmony_ci#include "url.h" 5213498266Sopenharmony_ci#include "getinfo.h" 5313498266Sopenharmony_ci#include "hostip.h" 5413498266Sopenharmony_ci#include "share.h" 5513498266Sopenharmony_ci#include "strdup.h" 5613498266Sopenharmony_ci#include "progress.h" 5713498266Sopenharmony_ci#include "easyif.h" 5813498266Sopenharmony_ci#include "multiif.h" 5913498266Sopenharmony_ci#include "select.h" 6013498266Sopenharmony_ci#include "cfilters.h" 6113498266Sopenharmony_ci#include "sendf.h" /* for failf function prototype */ 6213498266Sopenharmony_ci#include "connect.h" /* for Curl_getconnectinfo */ 6313498266Sopenharmony_ci#include "slist.h" 6413498266Sopenharmony_ci#include "mime.h" 6513498266Sopenharmony_ci#include "amigaos.h" 6613498266Sopenharmony_ci#include "macos.h" 6713498266Sopenharmony_ci#include "warnless.h" 6813498266Sopenharmony_ci#include "sigpipe.h" 6913498266Sopenharmony_ci#include "vssh/ssh.h" 7013498266Sopenharmony_ci#include "setopt.h" 7113498266Sopenharmony_ci#include "http_digest.h" 7213498266Sopenharmony_ci#include "system_win32.h" 7313498266Sopenharmony_ci#include "http2.h" 7413498266Sopenharmony_ci#include "dynbuf.h" 7513498266Sopenharmony_ci#include "altsvc.h" 7613498266Sopenharmony_ci#include "hsts.h" 7713498266Sopenharmony_ci 7813498266Sopenharmony_ci#include "easy_lock.h" 7913498266Sopenharmony_ci 8013498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 8113498266Sopenharmony_ci#include "curl_printf.h" 8213498266Sopenharmony_ci#include "curl_memory.h" 8313498266Sopenharmony_ci#include "memdebug.h" 8413498266Sopenharmony_ci 8513498266Sopenharmony_ci/* true globals -- for curl_global_init() and curl_global_cleanup() */ 8613498266Sopenharmony_cistatic unsigned int initialized; 8713498266Sopenharmony_cistatic long easy_init_flags; 8813498266Sopenharmony_ci 8913498266Sopenharmony_ci#ifdef GLOBAL_INIT_IS_THREADSAFE 9013498266Sopenharmony_ci 9113498266Sopenharmony_cistatic curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT; 9213498266Sopenharmony_ci#define global_init_lock() curl_simple_lock_lock(&s_lock) 9313498266Sopenharmony_ci#define global_init_unlock() curl_simple_lock_unlock(&s_lock) 9413498266Sopenharmony_ci 9513498266Sopenharmony_ci#else 9613498266Sopenharmony_ci 9713498266Sopenharmony_ci#define global_init_lock() 9813498266Sopenharmony_ci#define global_init_unlock() 9913498266Sopenharmony_ci 10013498266Sopenharmony_ci#endif 10113498266Sopenharmony_ci 10213498266Sopenharmony_ci/* 10313498266Sopenharmony_ci * strdup (and other memory functions) is redefined in complicated 10413498266Sopenharmony_ci * ways, but at this point it must be defined as the system-supplied strdup 10513498266Sopenharmony_ci * so the callback pointer is initialized correctly. 10613498266Sopenharmony_ci */ 10713498266Sopenharmony_ci#if defined(_WIN32_WCE) 10813498266Sopenharmony_ci#define system_strdup _strdup 10913498266Sopenharmony_ci#elif !defined(HAVE_STRDUP) 11013498266Sopenharmony_ci#define system_strdup Curl_strdup 11113498266Sopenharmony_ci#else 11213498266Sopenharmony_ci#define system_strdup strdup 11313498266Sopenharmony_ci#endif 11413498266Sopenharmony_ci 11513498266Sopenharmony_ci#if defined(_MSC_VER) && defined(_DLL) 11613498266Sopenharmony_ci# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ 11713498266Sopenharmony_ci#endif 11813498266Sopenharmony_ci 11913498266Sopenharmony_ci/* 12013498266Sopenharmony_ci * If a memory-using function (like curl_getenv) is used before 12113498266Sopenharmony_ci * curl_global_init() is called, we need to have these pointers set already. 12213498266Sopenharmony_ci */ 12313498266Sopenharmony_cicurl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; 12413498266Sopenharmony_cicurl_free_callback Curl_cfree = (curl_free_callback)free; 12513498266Sopenharmony_cicurl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; 12613498266Sopenharmony_cicurl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; 12713498266Sopenharmony_cicurl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; 12813498266Sopenharmony_ci#if defined(_WIN32) && defined(UNICODE) 12913498266Sopenharmony_cicurl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup; 13013498266Sopenharmony_ci#endif 13113498266Sopenharmony_ci 13213498266Sopenharmony_ci#if defined(_MSC_VER) && defined(_DLL) 13313498266Sopenharmony_ci# pragma warning(default:4232) /* MSVC extension, dllimport identity */ 13413498266Sopenharmony_ci#endif 13513498266Sopenharmony_ci 13613498266Sopenharmony_ci#ifdef DEBUGBUILD 13713498266Sopenharmony_cistatic char *leakpointer; 13813498266Sopenharmony_ci#endif 13913498266Sopenharmony_ci 14013498266Sopenharmony_ci/** 14113498266Sopenharmony_ci * curl_global_init() globally initializes curl given a bitwise set of the 14213498266Sopenharmony_ci * different features of what to initialize. 14313498266Sopenharmony_ci */ 14413498266Sopenharmony_cistatic CURLcode global_init(long flags, bool memoryfuncs) 14513498266Sopenharmony_ci{ 14613498266Sopenharmony_ci if(initialized++) 14713498266Sopenharmony_ci return CURLE_OK; 14813498266Sopenharmony_ci 14913498266Sopenharmony_ci if(memoryfuncs) { 15013498266Sopenharmony_ci /* Setup the default memory functions here (again) */ 15113498266Sopenharmony_ci Curl_cmalloc = (curl_malloc_callback)malloc; 15213498266Sopenharmony_ci Curl_cfree = (curl_free_callback)free; 15313498266Sopenharmony_ci Curl_crealloc = (curl_realloc_callback)realloc; 15413498266Sopenharmony_ci Curl_cstrdup = (curl_strdup_callback)system_strdup; 15513498266Sopenharmony_ci Curl_ccalloc = (curl_calloc_callback)calloc; 15613498266Sopenharmony_ci#if defined(_WIN32) && defined(UNICODE) 15713498266Sopenharmony_ci Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; 15813498266Sopenharmony_ci#endif 15913498266Sopenharmony_ci } 16013498266Sopenharmony_ci 16113498266Sopenharmony_ci if(Curl_trc_init()) { 16213498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n")); 16313498266Sopenharmony_ci goto fail; 16413498266Sopenharmony_ci } 16513498266Sopenharmony_ci 16613498266Sopenharmony_ci if(!Curl_ssl_init()) { 16713498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n")); 16813498266Sopenharmony_ci goto fail; 16913498266Sopenharmony_ci } 17013498266Sopenharmony_ci 17113498266Sopenharmony_ci if(Curl_win32_init(flags)) { 17213498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: win32_init failed\n")); 17313498266Sopenharmony_ci goto fail; 17413498266Sopenharmony_ci } 17513498266Sopenharmony_ci 17613498266Sopenharmony_ci if(Curl_amiga_init()) { 17713498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); 17813498266Sopenharmony_ci goto fail; 17913498266Sopenharmony_ci } 18013498266Sopenharmony_ci 18113498266Sopenharmony_ci if(Curl_macos_init()) { 18213498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n")); 18313498266Sopenharmony_ci goto fail; 18413498266Sopenharmony_ci } 18513498266Sopenharmony_ci 18613498266Sopenharmony_ci if(Curl_resolver_global_init()) { 18713498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); 18813498266Sopenharmony_ci goto fail; 18913498266Sopenharmony_ci } 19013498266Sopenharmony_ci 19113498266Sopenharmony_ci if(Curl_ssh_init()) { 19213498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: Curl_ssh_init failed\n")); 19313498266Sopenharmony_ci goto fail; 19413498266Sopenharmony_ci } 19513498266Sopenharmony_ci 19613498266Sopenharmony_ci easy_init_flags = flags; 19713498266Sopenharmony_ci 19813498266Sopenharmony_ci#ifdef DEBUGBUILD 19913498266Sopenharmony_ci if(getenv("CURL_GLOBAL_INIT")) 20013498266Sopenharmony_ci /* alloc data that will leak if *cleanup() is not called! */ 20113498266Sopenharmony_ci leakpointer = malloc(1); 20213498266Sopenharmony_ci#endif 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci return CURLE_OK; 20513498266Sopenharmony_ci 20613498266Sopenharmony_cifail: 20713498266Sopenharmony_ci initialized--; /* undo the increase */ 20813498266Sopenharmony_ci return CURLE_FAILED_INIT; 20913498266Sopenharmony_ci} 21013498266Sopenharmony_ci 21113498266Sopenharmony_ci 21213498266Sopenharmony_ci/** 21313498266Sopenharmony_ci * curl_global_init() globally initializes curl given a bitwise set of the 21413498266Sopenharmony_ci * different features of what to initialize. 21513498266Sopenharmony_ci */ 21613498266Sopenharmony_ciCURLcode curl_global_init(long flags) 21713498266Sopenharmony_ci{ 21813498266Sopenharmony_ci CURLcode result; 21913498266Sopenharmony_ci global_init_lock(); 22013498266Sopenharmony_ci 22113498266Sopenharmony_ci result = global_init(flags, TRUE); 22213498266Sopenharmony_ci 22313498266Sopenharmony_ci global_init_unlock(); 22413498266Sopenharmony_ci 22513498266Sopenharmony_ci return result; 22613498266Sopenharmony_ci} 22713498266Sopenharmony_ci 22813498266Sopenharmony_ci/* 22913498266Sopenharmony_ci * curl_global_init_mem() globally initializes curl and also registers the 23013498266Sopenharmony_ci * user provided callback routines. 23113498266Sopenharmony_ci */ 23213498266Sopenharmony_ciCURLcode curl_global_init_mem(long flags, curl_malloc_callback m, 23313498266Sopenharmony_ci curl_free_callback f, curl_realloc_callback r, 23413498266Sopenharmony_ci curl_strdup_callback s, curl_calloc_callback c) 23513498266Sopenharmony_ci{ 23613498266Sopenharmony_ci CURLcode result; 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci /* Invalid input, return immediately */ 23913498266Sopenharmony_ci if(!m || !f || !r || !s || !c) 24013498266Sopenharmony_ci return CURLE_FAILED_INIT; 24113498266Sopenharmony_ci 24213498266Sopenharmony_ci global_init_lock(); 24313498266Sopenharmony_ci 24413498266Sopenharmony_ci if(initialized) { 24513498266Sopenharmony_ci /* Already initialized, don't do it again, but bump the variable anyway to 24613498266Sopenharmony_ci work like curl_global_init() and require the same amount of cleanup 24713498266Sopenharmony_ci calls. */ 24813498266Sopenharmony_ci initialized++; 24913498266Sopenharmony_ci global_init_unlock(); 25013498266Sopenharmony_ci return CURLE_OK; 25113498266Sopenharmony_ci } 25213498266Sopenharmony_ci 25313498266Sopenharmony_ci /* set memory functions before global_init() in case it wants memory 25413498266Sopenharmony_ci functions */ 25513498266Sopenharmony_ci Curl_cmalloc = m; 25613498266Sopenharmony_ci Curl_cfree = f; 25713498266Sopenharmony_ci Curl_cstrdup = s; 25813498266Sopenharmony_ci Curl_crealloc = r; 25913498266Sopenharmony_ci Curl_ccalloc = c; 26013498266Sopenharmony_ci 26113498266Sopenharmony_ci /* Call the actual init function, but without setting */ 26213498266Sopenharmony_ci result = global_init(flags, FALSE); 26313498266Sopenharmony_ci 26413498266Sopenharmony_ci global_init_unlock(); 26513498266Sopenharmony_ci 26613498266Sopenharmony_ci return result; 26713498266Sopenharmony_ci} 26813498266Sopenharmony_ci 26913498266Sopenharmony_ci/** 27013498266Sopenharmony_ci * curl_global_cleanup() globally cleanups curl, uses the value of 27113498266Sopenharmony_ci * "easy_init_flags" to determine what needs to be cleaned up and what doesn't. 27213498266Sopenharmony_ci */ 27313498266Sopenharmony_civoid curl_global_cleanup(void) 27413498266Sopenharmony_ci{ 27513498266Sopenharmony_ci global_init_lock(); 27613498266Sopenharmony_ci 27713498266Sopenharmony_ci if(!initialized) { 27813498266Sopenharmony_ci global_init_unlock(); 27913498266Sopenharmony_ci return; 28013498266Sopenharmony_ci } 28113498266Sopenharmony_ci 28213498266Sopenharmony_ci if(--initialized) { 28313498266Sopenharmony_ci global_init_unlock(); 28413498266Sopenharmony_ci return; 28513498266Sopenharmony_ci } 28613498266Sopenharmony_ci 28713498266Sopenharmony_ci Curl_ssl_cleanup(); 28813498266Sopenharmony_ci Curl_resolver_global_cleanup(); 28913498266Sopenharmony_ci 29013498266Sopenharmony_ci#ifdef _WIN32 29113498266Sopenharmony_ci Curl_win32_cleanup(easy_init_flags); 29213498266Sopenharmony_ci#endif 29313498266Sopenharmony_ci 29413498266Sopenharmony_ci Curl_amiga_cleanup(); 29513498266Sopenharmony_ci 29613498266Sopenharmony_ci Curl_ssh_cleanup(); 29713498266Sopenharmony_ci 29813498266Sopenharmony_ci#ifdef DEBUGBUILD 29913498266Sopenharmony_ci free(leakpointer); 30013498266Sopenharmony_ci#endif 30113498266Sopenharmony_ci 30213498266Sopenharmony_ci easy_init_flags = 0; 30313498266Sopenharmony_ci 30413498266Sopenharmony_ci global_init_unlock(); 30513498266Sopenharmony_ci} 30613498266Sopenharmony_ci 30713498266Sopenharmony_ci/** 30813498266Sopenharmony_ci * curl_global_trace() globally initializes curl logging. 30913498266Sopenharmony_ci */ 31013498266Sopenharmony_ciCURLcode curl_global_trace(const char *config) 31113498266Sopenharmony_ci{ 31213498266Sopenharmony_ci#ifndef CURL_DISABLE_VERBOSE_STRINGS 31313498266Sopenharmony_ci CURLcode result; 31413498266Sopenharmony_ci global_init_lock(); 31513498266Sopenharmony_ci 31613498266Sopenharmony_ci result = Curl_trc_opt(config); 31713498266Sopenharmony_ci 31813498266Sopenharmony_ci global_init_unlock(); 31913498266Sopenharmony_ci 32013498266Sopenharmony_ci return result; 32113498266Sopenharmony_ci#else 32213498266Sopenharmony_ci (void)config; 32313498266Sopenharmony_ci return CURLE_OK; 32413498266Sopenharmony_ci#endif 32513498266Sopenharmony_ci} 32613498266Sopenharmony_ci 32713498266Sopenharmony_ci/* 32813498266Sopenharmony_ci * curl_global_sslset() globally initializes the SSL backend to use. 32913498266Sopenharmony_ci */ 33013498266Sopenharmony_ciCURLsslset curl_global_sslset(curl_sslbackend id, const char *name, 33113498266Sopenharmony_ci const curl_ssl_backend ***avail) 33213498266Sopenharmony_ci{ 33313498266Sopenharmony_ci CURLsslset rc; 33413498266Sopenharmony_ci 33513498266Sopenharmony_ci global_init_lock(); 33613498266Sopenharmony_ci 33713498266Sopenharmony_ci rc = Curl_init_sslset_nolock(id, name, avail); 33813498266Sopenharmony_ci 33913498266Sopenharmony_ci global_init_unlock(); 34013498266Sopenharmony_ci 34113498266Sopenharmony_ci return rc; 34213498266Sopenharmony_ci} 34313498266Sopenharmony_ci 34413498266Sopenharmony_ci/* 34513498266Sopenharmony_ci * curl_easy_init() is the external interface to alloc, setup and init an 34613498266Sopenharmony_ci * easy handle that is returned. If anything goes wrong, NULL is returned. 34713498266Sopenharmony_ci */ 34813498266Sopenharmony_cistruct Curl_easy *curl_easy_init(void) 34913498266Sopenharmony_ci{ 35013498266Sopenharmony_ci CURLcode result; 35113498266Sopenharmony_ci struct Curl_easy *data; 35213498266Sopenharmony_ci 35313498266Sopenharmony_ci /* Make sure we inited the global SSL stuff */ 35413498266Sopenharmony_ci global_init_lock(); 35513498266Sopenharmony_ci 35613498266Sopenharmony_ci if(!initialized) { 35713498266Sopenharmony_ci result = global_init(CURL_GLOBAL_DEFAULT, TRUE); 35813498266Sopenharmony_ci if(result) { 35913498266Sopenharmony_ci /* something in the global init failed, return nothing */ 36013498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); 36113498266Sopenharmony_ci global_init_unlock(); 36213498266Sopenharmony_ci return NULL; 36313498266Sopenharmony_ci } 36413498266Sopenharmony_ci } 36513498266Sopenharmony_ci global_init_unlock(); 36613498266Sopenharmony_ci 36713498266Sopenharmony_ci /* We use curl_open() with undefined URL so far */ 36813498266Sopenharmony_ci result = Curl_open(&data); 36913498266Sopenharmony_ci if(result) { 37013498266Sopenharmony_ci DEBUGF(fprintf(stderr, "Error: Curl_open failed\n")); 37113498266Sopenharmony_ci return NULL; 37213498266Sopenharmony_ci } 37313498266Sopenharmony_ci 37413498266Sopenharmony_ci return data; 37513498266Sopenharmony_ci} 37613498266Sopenharmony_ci 37713498266Sopenharmony_ci#ifdef CURLDEBUG 37813498266Sopenharmony_ci 37913498266Sopenharmony_cistruct socketmonitor { 38013498266Sopenharmony_ci struct socketmonitor *next; /* the next node in the list or NULL */ 38113498266Sopenharmony_ci struct pollfd socket; /* socket info of what to monitor */ 38213498266Sopenharmony_ci}; 38313498266Sopenharmony_ci 38413498266Sopenharmony_cistruct events { 38513498266Sopenharmony_ci long ms; /* timeout, run the timeout function when reached */ 38613498266Sopenharmony_ci bool msbump; /* set TRUE when timeout is set by callback */ 38713498266Sopenharmony_ci int num_sockets; /* number of nodes in the monitor list */ 38813498266Sopenharmony_ci struct socketmonitor *list; /* list of sockets to monitor */ 38913498266Sopenharmony_ci int running_handles; /* store the returned number */ 39013498266Sopenharmony_ci}; 39113498266Sopenharmony_ci 39213498266Sopenharmony_ci/* events_timer 39313498266Sopenharmony_ci * 39413498266Sopenharmony_ci * Callback that gets called with a new value when the timeout should be 39513498266Sopenharmony_ci * updated. 39613498266Sopenharmony_ci */ 39713498266Sopenharmony_ci 39813498266Sopenharmony_cistatic int events_timer(struct Curl_multi *multi, /* multi handle */ 39913498266Sopenharmony_ci long timeout_ms, /* see above */ 40013498266Sopenharmony_ci void *userp) /* private callback pointer */ 40113498266Sopenharmony_ci{ 40213498266Sopenharmony_ci struct events *ev = userp; 40313498266Sopenharmony_ci (void)multi; 40413498266Sopenharmony_ci if(timeout_ms == -1) 40513498266Sopenharmony_ci /* timeout removed */ 40613498266Sopenharmony_ci timeout_ms = 0; 40713498266Sopenharmony_ci else if(timeout_ms == 0) 40813498266Sopenharmony_ci /* timeout is already reached! */ 40913498266Sopenharmony_ci timeout_ms = 1; /* trigger asap */ 41013498266Sopenharmony_ci 41113498266Sopenharmony_ci ev->ms = timeout_ms; 41213498266Sopenharmony_ci ev->msbump = TRUE; 41313498266Sopenharmony_ci return 0; 41413498266Sopenharmony_ci} 41513498266Sopenharmony_ci 41613498266Sopenharmony_ci 41713498266Sopenharmony_ci/* poll2cselect 41813498266Sopenharmony_ci * 41913498266Sopenharmony_ci * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones 42013498266Sopenharmony_ci */ 42113498266Sopenharmony_cistatic int poll2cselect(int pollmask) 42213498266Sopenharmony_ci{ 42313498266Sopenharmony_ci int omask = 0; 42413498266Sopenharmony_ci if(pollmask & POLLIN) 42513498266Sopenharmony_ci omask |= CURL_CSELECT_IN; 42613498266Sopenharmony_ci if(pollmask & POLLOUT) 42713498266Sopenharmony_ci omask |= CURL_CSELECT_OUT; 42813498266Sopenharmony_ci if(pollmask & POLLERR) 42913498266Sopenharmony_ci omask |= CURL_CSELECT_ERR; 43013498266Sopenharmony_ci return omask; 43113498266Sopenharmony_ci} 43213498266Sopenharmony_ci 43313498266Sopenharmony_ci 43413498266Sopenharmony_ci/* socketcb2poll 43513498266Sopenharmony_ci * 43613498266Sopenharmony_ci * convert from libcurl' CURL_POLL_* bit definitions to poll()'s 43713498266Sopenharmony_ci */ 43813498266Sopenharmony_cistatic short socketcb2poll(int pollmask) 43913498266Sopenharmony_ci{ 44013498266Sopenharmony_ci short omask = 0; 44113498266Sopenharmony_ci if(pollmask & CURL_POLL_IN) 44213498266Sopenharmony_ci omask |= POLLIN; 44313498266Sopenharmony_ci if(pollmask & CURL_POLL_OUT) 44413498266Sopenharmony_ci omask |= POLLOUT; 44513498266Sopenharmony_ci return omask; 44613498266Sopenharmony_ci} 44713498266Sopenharmony_ci 44813498266Sopenharmony_ci/* events_socket 44913498266Sopenharmony_ci * 45013498266Sopenharmony_ci * Callback that gets called with information about socket activity to 45113498266Sopenharmony_ci * monitor. 45213498266Sopenharmony_ci */ 45313498266Sopenharmony_cistatic int events_socket(struct Curl_easy *easy, /* easy handle */ 45413498266Sopenharmony_ci curl_socket_t s, /* socket */ 45513498266Sopenharmony_ci int what, /* see above */ 45613498266Sopenharmony_ci void *userp, /* private callback 45713498266Sopenharmony_ci pointer */ 45813498266Sopenharmony_ci void *socketp) /* private socket 45913498266Sopenharmony_ci pointer */ 46013498266Sopenharmony_ci{ 46113498266Sopenharmony_ci struct events *ev = userp; 46213498266Sopenharmony_ci struct socketmonitor *m; 46313498266Sopenharmony_ci struct socketmonitor *prev = NULL; 46413498266Sopenharmony_ci 46513498266Sopenharmony_ci#if defined(CURL_DISABLE_VERBOSE_STRINGS) 46613498266Sopenharmony_ci (void) easy; 46713498266Sopenharmony_ci#endif 46813498266Sopenharmony_ci (void)socketp; 46913498266Sopenharmony_ci 47013498266Sopenharmony_ci m = ev->list; 47113498266Sopenharmony_ci while(m) { 47213498266Sopenharmony_ci if(m->socket.fd == s) { 47313498266Sopenharmony_ci 47413498266Sopenharmony_ci if(what == CURL_POLL_REMOVE) { 47513498266Sopenharmony_ci struct socketmonitor *nxt = m->next; 47613498266Sopenharmony_ci /* remove this node from the list of monitored sockets */ 47713498266Sopenharmony_ci if(prev) 47813498266Sopenharmony_ci prev->next = nxt; 47913498266Sopenharmony_ci else 48013498266Sopenharmony_ci ev->list = nxt; 48113498266Sopenharmony_ci free(m); 48213498266Sopenharmony_ci m = nxt; 48313498266Sopenharmony_ci infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T 48413498266Sopenharmony_ci " REMOVED", s); 48513498266Sopenharmony_ci } 48613498266Sopenharmony_ci else { 48713498266Sopenharmony_ci /* The socket 's' is already being monitored, update the activity 48813498266Sopenharmony_ci mask. Convert from libcurl bitmask to the poll one. */ 48913498266Sopenharmony_ci m->socket.events = socketcb2poll(what); 49013498266Sopenharmony_ci infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T 49113498266Sopenharmony_ci " UPDATED as %s%s", s, 49213498266Sopenharmony_ci (what&CURL_POLL_IN)?"IN":"", 49313498266Sopenharmony_ci (what&CURL_POLL_OUT)?"OUT":""); 49413498266Sopenharmony_ci } 49513498266Sopenharmony_ci break; 49613498266Sopenharmony_ci } 49713498266Sopenharmony_ci prev = m; 49813498266Sopenharmony_ci m = m->next; /* move to next node */ 49913498266Sopenharmony_ci } 50013498266Sopenharmony_ci if(!m) { 50113498266Sopenharmony_ci if(what == CURL_POLL_REMOVE) { 50213498266Sopenharmony_ci /* this happens a bit too often, libcurl fix perhaps? */ 50313498266Sopenharmony_ci /* fprintf(stderr, 50413498266Sopenharmony_ci "%s: socket %d asked to be REMOVED but not present!\n", 50513498266Sopenharmony_ci __func__, s); */ 50613498266Sopenharmony_ci } 50713498266Sopenharmony_ci else { 50813498266Sopenharmony_ci m = malloc(sizeof(struct socketmonitor)); 50913498266Sopenharmony_ci if(m) { 51013498266Sopenharmony_ci m->next = ev->list; 51113498266Sopenharmony_ci m->socket.fd = s; 51213498266Sopenharmony_ci m->socket.events = socketcb2poll(what); 51313498266Sopenharmony_ci m->socket.revents = 0; 51413498266Sopenharmony_ci ev->list = m; 51513498266Sopenharmony_ci infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T 51613498266Sopenharmony_ci " ADDED as %s%s", s, 51713498266Sopenharmony_ci (what&CURL_POLL_IN)?"IN":"", 51813498266Sopenharmony_ci (what&CURL_POLL_OUT)?"OUT":""); 51913498266Sopenharmony_ci } 52013498266Sopenharmony_ci else 52113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 52213498266Sopenharmony_ci } 52313498266Sopenharmony_ci } 52413498266Sopenharmony_ci 52513498266Sopenharmony_ci return 0; 52613498266Sopenharmony_ci} 52713498266Sopenharmony_ci 52813498266Sopenharmony_ci 52913498266Sopenharmony_ci/* 53013498266Sopenharmony_ci * events_setup() 53113498266Sopenharmony_ci * 53213498266Sopenharmony_ci * Do the multi handle setups that only event-based transfers need. 53313498266Sopenharmony_ci */ 53413498266Sopenharmony_cistatic void events_setup(struct Curl_multi *multi, struct events *ev) 53513498266Sopenharmony_ci{ 53613498266Sopenharmony_ci /* timer callback */ 53713498266Sopenharmony_ci curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); 53813498266Sopenharmony_ci curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev); 53913498266Sopenharmony_ci 54013498266Sopenharmony_ci /* socket callback */ 54113498266Sopenharmony_ci curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket); 54213498266Sopenharmony_ci curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev); 54313498266Sopenharmony_ci} 54413498266Sopenharmony_ci 54513498266Sopenharmony_ci 54613498266Sopenharmony_ci/* wait_or_timeout() 54713498266Sopenharmony_ci * 54813498266Sopenharmony_ci * waits for activity on any of the given sockets, or the timeout to trigger. 54913498266Sopenharmony_ci */ 55013498266Sopenharmony_ci 55113498266Sopenharmony_cistatic CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) 55213498266Sopenharmony_ci{ 55313498266Sopenharmony_ci bool done = FALSE; 55413498266Sopenharmony_ci CURLMcode mcode = CURLM_OK; 55513498266Sopenharmony_ci CURLcode result = CURLE_OK; 55613498266Sopenharmony_ci 55713498266Sopenharmony_ci while(!done) { 55813498266Sopenharmony_ci CURLMsg *msg; 55913498266Sopenharmony_ci struct socketmonitor *m; 56013498266Sopenharmony_ci struct pollfd *f; 56113498266Sopenharmony_ci struct pollfd fds[4]; 56213498266Sopenharmony_ci int numfds = 0; 56313498266Sopenharmony_ci int pollrc; 56413498266Sopenharmony_ci int i; 56513498266Sopenharmony_ci struct curltime before; 56613498266Sopenharmony_ci struct curltime after; 56713498266Sopenharmony_ci 56813498266Sopenharmony_ci /* populate the fds[] array */ 56913498266Sopenharmony_ci for(m = ev->list, f = &fds[0]; m; m = m->next) { 57013498266Sopenharmony_ci f->fd = m->socket.fd; 57113498266Sopenharmony_ci f->events = m->socket.events; 57213498266Sopenharmony_ci f->revents = 0; 57313498266Sopenharmony_ci /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */ 57413498266Sopenharmony_ci f++; 57513498266Sopenharmony_ci numfds++; 57613498266Sopenharmony_ci } 57713498266Sopenharmony_ci 57813498266Sopenharmony_ci /* get the time stamp to use to figure out how long poll takes */ 57913498266Sopenharmony_ci before = Curl_now(); 58013498266Sopenharmony_ci 58113498266Sopenharmony_ci /* wait for activity or timeout */ 58213498266Sopenharmony_ci pollrc = Curl_poll(fds, numfds, ev->ms); 58313498266Sopenharmony_ci if(pollrc < 0) 58413498266Sopenharmony_ci return CURLE_UNRECOVERABLE_POLL; 58513498266Sopenharmony_ci 58613498266Sopenharmony_ci after = Curl_now(); 58713498266Sopenharmony_ci 58813498266Sopenharmony_ci ev->msbump = FALSE; /* reset here */ 58913498266Sopenharmony_ci 59013498266Sopenharmony_ci if(!pollrc) { 59113498266Sopenharmony_ci /* timeout! */ 59213498266Sopenharmony_ci ev->ms = 0; 59313498266Sopenharmony_ci /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ 59413498266Sopenharmony_ci mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, 59513498266Sopenharmony_ci &ev->running_handles); 59613498266Sopenharmony_ci } 59713498266Sopenharmony_ci else { 59813498266Sopenharmony_ci /* here pollrc is > 0 */ 59913498266Sopenharmony_ci 60013498266Sopenharmony_ci /* loop over the monitored sockets to see which ones had activity */ 60113498266Sopenharmony_ci for(i = 0; i< numfds; i++) { 60213498266Sopenharmony_ci if(fds[i].revents) { 60313498266Sopenharmony_ci /* socket activity, tell libcurl */ 60413498266Sopenharmony_ci int act = poll2cselect(fds[i].revents); /* convert */ 60513498266Sopenharmony_ci infof(multi->easyp, 60613498266Sopenharmony_ci "call curl_multi_socket_action(socket " 60713498266Sopenharmony_ci "%" CURL_FORMAT_SOCKET_T ")", fds[i].fd); 60813498266Sopenharmony_ci mcode = curl_multi_socket_action(multi, fds[i].fd, act, 60913498266Sopenharmony_ci &ev->running_handles); 61013498266Sopenharmony_ci } 61113498266Sopenharmony_ci } 61213498266Sopenharmony_ci 61313498266Sopenharmony_ci if(!ev->msbump) { 61413498266Sopenharmony_ci /* If nothing updated the timeout, we decrease it by the spent time. 61513498266Sopenharmony_ci * If it was updated, it has the new timeout time stored already. 61613498266Sopenharmony_ci */ 61713498266Sopenharmony_ci timediff_t timediff = Curl_timediff(after, before); 61813498266Sopenharmony_ci if(timediff > 0) { 61913498266Sopenharmony_ci if(timediff > ev->ms) 62013498266Sopenharmony_ci ev->ms = 0; 62113498266Sopenharmony_ci else 62213498266Sopenharmony_ci ev->ms -= (long)timediff; 62313498266Sopenharmony_ci } 62413498266Sopenharmony_ci } 62513498266Sopenharmony_ci } 62613498266Sopenharmony_ci 62713498266Sopenharmony_ci if(mcode) 62813498266Sopenharmony_ci return CURLE_URL_MALFORMAT; 62913498266Sopenharmony_ci 63013498266Sopenharmony_ci /* we don't really care about the "msgs_in_queue" value returned in the 63113498266Sopenharmony_ci second argument */ 63213498266Sopenharmony_ci msg = curl_multi_info_read(multi, &pollrc); 63313498266Sopenharmony_ci if(msg) { 63413498266Sopenharmony_ci result = msg->data.result; 63513498266Sopenharmony_ci done = TRUE; 63613498266Sopenharmony_ci } 63713498266Sopenharmony_ci } 63813498266Sopenharmony_ci 63913498266Sopenharmony_ci return result; 64013498266Sopenharmony_ci} 64113498266Sopenharmony_ci 64213498266Sopenharmony_ci 64313498266Sopenharmony_ci/* easy_events() 64413498266Sopenharmony_ci * 64513498266Sopenharmony_ci * Runs a transfer in a blocking manner using the events-based API 64613498266Sopenharmony_ci */ 64713498266Sopenharmony_cistatic CURLcode easy_events(struct Curl_multi *multi) 64813498266Sopenharmony_ci{ 64913498266Sopenharmony_ci /* this struct is made static to allow it to be used after this function 65013498266Sopenharmony_ci returns and curl_multi_remove_handle() is called */ 65113498266Sopenharmony_ci static struct events evs = {2, FALSE, 0, NULL, 0}; 65213498266Sopenharmony_ci 65313498266Sopenharmony_ci /* if running event-based, do some further multi inits */ 65413498266Sopenharmony_ci events_setup(multi, &evs); 65513498266Sopenharmony_ci 65613498266Sopenharmony_ci return wait_or_timeout(multi, &evs); 65713498266Sopenharmony_ci} 65813498266Sopenharmony_ci#else /* CURLDEBUG */ 65913498266Sopenharmony_ci/* when not built with debug, this function doesn't exist */ 66013498266Sopenharmony_ci#define easy_events(x) CURLE_NOT_BUILT_IN 66113498266Sopenharmony_ci#endif 66213498266Sopenharmony_ci 66313498266Sopenharmony_cistatic CURLcode easy_transfer(struct Curl_multi *multi) 66413498266Sopenharmony_ci{ 66513498266Sopenharmony_ci bool done = FALSE; 66613498266Sopenharmony_ci CURLMcode mcode = CURLM_OK; 66713498266Sopenharmony_ci CURLcode result = CURLE_OK; 66813498266Sopenharmony_ci 66913498266Sopenharmony_ci while(!done && !mcode) { 67013498266Sopenharmony_ci int still_running = 0; 67113498266Sopenharmony_ci 67213498266Sopenharmony_ci mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL); 67313498266Sopenharmony_ci 67413498266Sopenharmony_ci if(!mcode) 67513498266Sopenharmony_ci mcode = curl_multi_perform(multi, &still_running); 67613498266Sopenharmony_ci 67713498266Sopenharmony_ci /* only read 'still_running' if curl_multi_perform() return OK */ 67813498266Sopenharmony_ci if(!mcode && !still_running) { 67913498266Sopenharmony_ci int rc; 68013498266Sopenharmony_ci CURLMsg *msg = curl_multi_info_read(multi, &rc); 68113498266Sopenharmony_ci if(msg) { 68213498266Sopenharmony_ci result = msg->data.result; 68313498266Sopenharmony_ci done = TRUE; 68413498266Sopenharmony_ci } 68513498266Sopenharmony_ci } 68613498266Sopenharmony_ci } 68713498266Sopenharmony_ci 68813498266Sopenharmony_ci /* Make sure to return some kind of error if there was a multi problem */ 68913498266Sopenharmony_ci if(mcode) { 69013498266Sopenharmony_ci result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY : 69113498266Sopenharmony_ci /* The other multi errors should never happen, so return 69213498266Sopenharmony_ci something suitably generic */ 69313498266Sopenharmony_ci CURLE_BAD_FUNCTION_ARGUMENT; 69413498266Sopenharmony_ci } 69513498266Sopenharmony_ci 69613498266Sopenharmony_ci return result; 69713498266Sopenharmony_ci} 69813498266Sopenharmony_ci 69913498266Sopenharmony_ci 70013498266Sopenharmony_ci/* 70113498266Sopenharmony_ci * easy_perform() is the external interface that performs a blocking 70213498266Sopenharmony_ci * transfer as previously setup. 70313498266Sopenharmony_ci * 70413498266Sopenharmony_ci * CONCEPT: This function creates a multi handle, adds the easy handle to it, 70513498266Sopenharmony_ci * runs curl_multi_perform() until the transfer is done, then detaches the 70613498266Sopenharmony_ci * easy handle, destroys the multi handle and returns the easy handle's return 70713498266Sopenharmony_ci * code. 70813498266Sopenharmony_ci * 70913498266Sopenharmony_ci * REALITY: it can't just create and destroy the multi handle that easily. It 71013498266Sopenharmony_ci * needs to keep it around since if this easy handle is used again by this 71113498266Sopenharmony_ci * function, the same multi handle must be reused so that the same pools and 71213498266Sopenharmony_ci * caches can be used. 71313498266Sopenharmony_ci * 71413498266Sopenharmony_ci * DEBUG: if 'events' is set TRUE, this function will use a replacement engine 71513498266Sopenharmony_ci * instead of curl_multi_perform() and use curl_multi_socket_action(). 71613498266Sopenharmony_ci */ 71713498266Sopenharmony_cistatic CURLcode easy_perform(struct Curl_easy *data, bool events) 71813498266Sopenharmony_ci{ 71913498266Sopenharmony_ci struct Curl_multi *multi; 72013498266Sopenharmony_ci CURLMcode mcode; 72113498266Sopenharmony_ci CURLcode result = CURLE_OK; 72213498266Sopenharmony_ci SIGPIPE_VARIABLE(pipe_st); 72313498266Sopenharmony_ci 72413498266Sopenharmony_ci if(!data) 72513498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 72613498266Sopenharmony_ci 72713498266Sopenharmony_ci if(data->set.errorbuffer) 72813498266Sopenharmony_ci /* clear this as early as possible */ 72913498266Sopenharmony_ci data->set.errorbuffer[0] = 0; 73013498266Sopenharmony_ci 73113498266Sopenharmony_ci if(data->multi) { 73213498266Sopenharmony_ci failf(data, "easy handle already used in multi handle"); 73313498266Sopenharmony_ci return CURLE_FAILED_INIT; 73413498266Sopenharmony_ci } 73513498266Sopenharmony_ci 73613498266Sopenharmony_ci if(data->multi_easy) 73713498266Sopenharmony_ci multi = data->multi_easy; 73813498266Sopenharmony_ci else { 73913498266Sopenharmony_ci /* this multi handle will only ever have a single easy handled attached 74013498266Sopenharmony_ci to it, so make it use minimal hashes */ 74113498266Sopenharmony_ci multi = Curl_multi_handle(1, 3, 7); 74213498266Sopenharmony_ci if(!multi) 74313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 74413498266Sopenharmony_ci data->multi_easy = multi; 74513498266Sopenharmony_ci } 74613498266Sopenharmony_ci 74713498266Sopenharmony_ci if(multi->in_callback) 74813498266Sopenharmony_ci return CURLE_RECURSIVE_API_CALL; 74913498266Sopenharmony_ci 75013498266Sopenharmony_ci /* Copy the MAXCONNECTS option to the multi handle */ 75113498266Sopenharmony_ci curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects); 75213498266Sopenharmony_ci 75313498266Sopenharmony_ci mcode = curl_multi_add_handle(multi, data); 75413498266Sopenharmony_ci if(mcode) { 75513498266Sopenharmony_ci curl_multi_cleanup(multi); 75613498266Sopenharmony_ci data->multi_easy = NULL; 75713498266Sopenharmony_ci if(mcode == CURLM_OUT_OF_MEMORY) 75813498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 75913498266Sopenharmony_ci return CURLE_FAILED_INIT; 76013498266Sopenharmony_ci } 76113498266Sopenharmony_ci 76213498266Sopenharmony_ci sigpipe_ignore(data, &pipe_st); 76313498266Sopenharmony_ci 76413498266Sopenharmony_ci /* run the transfer */ 76513498266Sopenharmony_ci result = events ? easy_events(multi) : easy_transfer(multi); 76613498266Sopenharmony_ci 76713498266Sopenharmony_ci /* ignoring the return code isn't nice, but atm we can't really handle 76813498266Sopenharmony_ci a failure here, room for future improvement! */ 76913498266Sopenharmony_ci (void)curl_multi_remove_handle(multi, data); 77013498266Sopenharmony_ci 77113498266Sopenharmony_ci sigpipe_restore(&pipe_st); 77213498266Sopenharmony_ci 77313498266Sopenharmony_ci /* The multi handle is kept alive, owned by the easy handle */ 77413498266Sopenharmony_ci return result; 77513498266Sopenharmony_ci} 77613498266Sopenharmony_ci 77713498266Sopenharmony_ci 77813498266Sopenharmony_ci/* 77913498266Sopenharmony_ci * curl_easy_perform() is the external interface that performs a blocking 78013498266Sopenharmony_ci * transfer as previously setup. 78113498266Sopenharmony_ci */ 78213498266Sopenharmony_ciCURLcode curl_easy_perform(struct Curl_easy *data) 78313498266Sopenharmony_ci{ 78413498266Sopenharmony_ci return easy_perform(data, FALSE); 78513498266Sopenharmony_ci} 78613498266Sopenharmony_ci 78713498266Sopenharmony_ci#ifdef CURLDEBUG 78813498266Sopenharmony_ci/* 78913498266Sopenharmony_ci * curl_easy_perform_ev() is the external interface that performs a blocking 79013498266Sopenharmony_ci * transfer using the event-based API internally. 79113498266Sopenharmony_ci */ 79213498266Sopenharmony_ciCURLcode curl_easy_perform_ev(struct Curl_easy *data) 79313498266Sopenharmony_ci{ 79413498266Sopenharmony_ci return easy_perform(data, TRUE); 79513498266Sopenharmony_ci} 79613498266Sopenharmony_ci 79713498266Sopenharmony_ci#endif 79813498266Sopenharmony_ci 79913498266Sopenharmony_ci/* 80013498266Sopenharmony_ci * curl_easy_cleanup() is the external interface to cleaning/freeing the given 80113498266Sopenharmony_ci * easy handle. 80213498266Sopenharmony_ci */ 80313498266Sopenharmony_civoid curl_easy_cleanup(struct Curl_easy *data) 80413498266Sopenharmony_ci{ 80513498266Sopenharmony_ci if(GOOD_EASY_HANDLE(data)) { 80613498266Sopenharmony_ci SIGPIPE_VARIABLE(pipe_st); 80713498266Sopenharmony_ci sigpipe_ignore(data, &pipe_st); 80813498266Sopenharmony_ci Curl_close(&data); 80913498266Sopenharmony_ci sigpipe_restore(&pipe_st); 81013498266Sopenharmony_ci } 81113498266Sopenharmony_ci} 81213498266Sopenharmony_ci 81313498266Sopenharmony_ci/* 81413498266Sopenharmony_ci * curl_easy_getinfo() is an external interface that allows an app to retrieve 81513498266Sopenharmony_ci * information from a performed transfer and similar. 81613498266Sopenharmony_ci */ 81713498266Sopenharmony_ci#undef curl_easy_getinfo 81813498266Sopenharmony_ciCURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...) 81913498266Sopenharmony_ci{ 82013498266Sopenharmony_ci va_list arg; 82113498266Sopenharmony_ci void *paramp; 82213498266Sopenharmony_ci CURLcode result; 82313498266Sopenharmony_ci 82413498266Sopenharmony_ci va_start(arg, info); 82513498266Sopenharmony_ci paramp = va_arg(arg, void *); 82613498266Sopenharmony_ci 82713498266Sopenharmony_ci result = Curl_getinfo(data, info, paramp); 82813498266Sopenharmony_ci 82913498266Sopenharmony_ci va_end(arg); 83013498266Sopenharmony_ci return result; 83113498266Sopenharmony_ci} 83213498266Sopenharmony_ci 83313498266Sopenharmony_cistatic CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src) 83413498266Sopenharmony_ci{ 83513498266Sopenharmony_ci CURLcode result = CURLE_OK; 83613498266Sopenharmony_ci enum dupstring i; 83713498266Sopenharmony_ci enum dupblob j; 83813498266Sopenharmony_ci 83913498266Sopenharmony_ci /* Copy src->set into dst->set first, then deal with the strings 84013498266Sopenharmony_ci afterwards */ 84113498266Sopenharmony_ci dst->set = src->set; 84213498266Sopenharmony_ci Curl_mime_initpart(&dst->set.mimepost); 84313498266Sopenharmony_ci 84413498266Sopenharmony_ci /* clear all dest string and blob pointers first, in case we error out 84513498266Sopenharmony_ci mid-function */ 84613498266Sopenharmony_ci memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); 84713498266Sopenharmony_ci memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *)); 84813498266Sopenharmony_ci 84913498266Sopenharmony_ci /* duplicate all strings */ 85013498266Sopenharmony_ci for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) { 85113498266Sopenharmony_ci result = Curl_setstropt(&dst->set.str[i], src->set.str[i]); 85213498266Sopenharmony_ci if(result) 85313498266Sopenharmony_ci return result; 85413498266Sopenharmony_ci } 85513498266Sopenharmony_ci 85613498266Sopenharmony_ci /* duplicate all blobs */ 85713498266Sopenharmony_ci for(j = (enum dupblob)0; j < BLOB_LAST; j++) { 85813498266Sopenharmony_ci result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]); 85913498266Sopenharmony_ci if(result) 86013498266Sopenharmony_ci return result; 86113498266Sopenharmony_ci } 86213498266Sopenharmony_ci 86313498266Sopenharmony_ci /* duplicate memory areas pointed to */ 86413498266Sopenharmony_ci i = STRING_COPYPOSTFIELDS; 86513498266Sopenharmony_ci if(src->set.str[i]) { 86613498266Sopenharmony_ci if(src->set.postfieldsize == -1) 86713498266Sopenharmony_ci dst->set.str[i] = strdup(src->set.str[i]); 86813498266Sopenharmony_ci else 86913498266Sopenharmony_ci /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */ 87013498266Sopenharmony_ci dst->set.str[i] = Curl_memdup(src->set.str[i], 87113498266Sopenharmony_ci curlx_sotouz(src->set.postfieldsize)); 87213498266Sopenharmony_ci if(!dst->set.str[i]) 87313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 87413498266Sopenharmony_ci /* point to the new copy */ 87513498266Sopenharmony_ci dst->set.postfields = dst->set.str[i]; 87613498266Sopenharmony_ci } 87713498266Sopenharmony_ci 87813498266Sopenharmony_ci /* Duplicate mime data. */ 87913498266Sopenharmony_ci result = Curl_mime_duppart(dst, &dst->set.mimepost, &src->set.mimepost); 88013498266Sopenharmony_ci 88113498266Sopenharmony_ci if(src->set.resolve) 88213498266Sopenharmony_ci dst->state.resolve = dst->set.resolve; 88313498266Sopenharmony_ci 88413498266Sopenharmony_ci return result; 88513498266Sopenharmony_ci} 88613498266Sopenharmony_ci 88713498266Sopenharmony_ci/* 88813498266Sopenharmony_ci * curl_easy_duphandle() is an external interface to allow duplication of a 88913498266Sopenharmony_ci * given input easy handle. The returned handle will be a new working handle 89013498266Sopenharmony_ci * with all options set exactly as the input source handle. 89113498266Sopenharmony_ci */ 89213498266Sopenharmony_cistruct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) 89313498266Sopenharmony_ci{ 89413498266Sopenharmony_ci struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); 89513498266Sopenharmony_ci if(!outcurl) 89613498266Sopenharmony_ci goto fail; 89713498266Sopenharmony_ci 89813498266Sopenharmony_ci /* 89913498266Sopenharmony_ci * We setup a few buffers we need. We should probably make them 90013498266Sopenharmony_ci * get setup on-demand in the code, as that would probably decrease 90113498266Sopenharmony_ci * the likeliness of us forgetting to init a buffer here in the future. 90213498266Sopenharmony_ci */ 90313498266Sopenharmony_ci outcurl->set.buffer_size = data->set.buffer_size; 90413498266Sopenharmony_ci 90513498266Sopenharmony_ci /* copy all userdefined values */ 90613498266Sopenharmony_ci if(dupset(outcurl, data)) 90713498266Sopenharmony_ci goto fail; 90813498266Sopenharmony_ci 90913498266Sopenharmony_ci Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER); 91013498266Sopenharmony_ci 91113498266Sopenharmony_ci /* the connection cache is setup on demand */ 91213498266Sopenharmony_ci outcurl->state.conn_cache = NULL; 91313498266Sopenharmony_ci outcurl->state.lastconnect_id = -1; 91413498266Sopenharmony_ci outcurl->state.recent_conn_id = -1; 91513498266Sopenharmony_ci outcurl->id = -1; 91613498266Sopenharmony_ci 91713498266Sopenharmony_ci outcurl->progress.flags = data->progress.flags; 91813498266Sopenharmony_ci outcurl->progress.callback = data->progress.callback; 91913498266Sopenharmony_ci 92013498266Sopenharmony_ci#ifndef CURL_DISABLE_COOKIES 92113498266Sopenharmony_ci outcurl->state.cookielist = NULL; 92213498266Sopenharmony_ci if(data->cookies && data->state.cookie_engine) { 92313498266Sopenharmony_ci /* If cookies are enabled in the parent handle, we enable them 92413498266Sopenharmony_ci in the clone as well! */ 92513498266Sopenharmony_ci outcurl->cookies = Curl_cookie_init(outcurl, NULL, outcurl->cookies, 92613498266Sopenharmony_ci data->set.cookiesession); 92713498266Sopenharmony_ci if(!outcurl->cookies) 92813498266Sopenharmony_ci goto fail; 92913498266Sopenharmony_ci } 93013498266Sopenharmony_ci 93113498266Sopenharmony_ci if(data->state.cookielist) { 93213498266Sopenharmony_ci outcurl->state.cookielist = Curl_slist_duplicate(data->state.cookielist); 93313498266Sopenharmony_ci if(!outcurl->state.cookielist) 93413498266Sopenharmony_ci goto fail; 93513498266Sopenharmony_ci } 93613498266Sopenharmony_ci#endif 93713498266Sopenharmony_ci 93813498266Sopenharmony_ci if(data->state.url) { 93913498266Sopenharmony_ci outcurl->state.url = strdup(data->state.url); 94013498266Sopenharmony_ci if(!outcurl->state.url) 94113498266Sopenharmony_ci goto fail; 94213498266Sopenharmony_ci outcurl->state.url_alloc = TRUE; 94313498266Sopenharmony_ci } 94413498266Sopenharmony_ci 94513498266Sopenharmony_ci if(data->state.referer) { 94613498266Sopenharmony_ci outcurl->state.referer = strdup(data->state.referer); 94713498266Sopenharmony_ci if(!outcurl->state.referer) 94813498266Sopenharmony_ci goto fail; 94913498266Sopenharmony_ci outcurl->state.referer_alloc = TRUE; 95013498266Sopenharmony_ci } 95113498266Sopenharmony_ci 95213498266Sopenharmony_ci /* Reinitialize an SSL engine for the new handle 95313498266Sopenharmony_ci * note: the engine name has already been copied by dupset */ 95413498266Sopenharmony_ci if(outcurl->set.str[STRING_SSL_ENGINE]) { 95513498266Sopenharmony_ci if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE])) 95613498266Sopenharmony_ci goto fail; 95713498266Sopenharmony_ci } 95813498266Sopenharmony_ci 95913498266Sopenharmony_ci#ifndef CURL_DISABLE_ALTSVC 96013498266Sopenharmony_ci if(data->asi) { 96113498266Sopenharmony_ci outcurl->asi = Curl_altsvc_init(); 96213498266Sopenharmony_ci if(!outcurl->asi) 96313498266Sopenharmony_ci goto fail; 96413498266Sopenharmony_ci if(outcurl->set.str[STRING_ALTSVC]) 96513498266Sopenharmony_ci (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]); 96613498266Sopenharmony_ci } 96713498266Sopenharmony_ci#endif 96813498266Sopenharmony_ci#ifndef CURL_DISABLE_HSTS 96913498266Sopenharmony_ci if(data->hsts) { 97013498266Sopenharmony_ci outcurl->hsts = Curl_hsts_init(); 97113498266Sopenharmony_ci if(!outcurl->hsts) 97213498266Sopenharmony_ci goto fail; 97313498266Sopenharmony_ci if(outcurl->set.str[STRING_HSTS]) 97413498266Sopenharmony_ci (void)Curl_hsts_loadfile(outcurl, 97513498266Sopenharmony_ci outcurl->hsts, outcurl->set.str[STRING_HSTS]); 97613498266Sopenharmony_ci (void)Curl_hsts_loadcb(outcurl, outcurl->hsts); 97713498266Sopenharmony_ci } 97813498266Sopenharmony_ci#endif 97913498266Sopenharmony_ci 98013498266Sopenharmony_ci#ifdef CURLRES_ASYNCH 98113498266Sopenharmony_ci /* Clone the resolver handle, if present, for the new handle */ 98213498266Sopenharmony_ci if(Curl_resolver_duphandle(outcurl, 98313498266Sopenharmony_ci &outcurl->state.async.resolver, 98413498266Sopenharmony_ci data->state.async.resolver)) 98513498266Sopenharmony_ci goto fail; 98613498266Sopenharmony_ci#endif 98713498266Sopenharmony_ci 98813498266Sopenharmony_ci#ifdef USE_ARES 98913498266Sopenharmony_ci { 99013498266Sopenharmony_ci CURLcode rc; 99113498266Sopenharmony_ci 99213498266Sopenharmony_ci rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]); 99313498266Sopenharmony_ci if(rc && rc != CURLE_NOT_BUILT_IN) 99413498266Sopenharmony_ci goto fail; 99513498266Sopenharmony_ci 99613498266Sopenharmony_ci rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]); 99713498266Sopenharmony_ci if(rc && rc != CURLE_NOT_BUILT_IN) 99813498266Sopenharmony_ci goto fail; 99913498266Sopenharmony_ci 100013498266Sopenharmony_ci rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]); 100113498266Sopenharmony_ci if(rc && rc != CURLE_NOT_BUILT_IN) 100213498266Sopenharmony_ci goto fail; 100313498266Sopenharmony_ci 100413498266Sopenharmony_ci rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]); 100513498266Sopenharmony_ci if(rc && rc != CURLE_NOT_BUILT_IN) 100613498266Sopenharmony_ci goto fail; 100713498266Sopenharmony_ci } 100813498266Sopenharmony_ci#endif /* USE_ARES */ 100913498266Sopenharmony_ci 101013498266Sopenharmony_ci Curl_initinfo(outcurl); 101113498266Sopenharmony_ci 101213498266Sopenharmony_ci outcurl->magic = CURLEASY_MAGIC_NUMBER; 101313498266Sopenharmony_ci 101413498266Sopenharmony_ci /* we reach this point and thus we are OK */ 101513498266Sopenharmony_ci 101613498266Sopenharmony_ci return outcurl; 101713498266Sopenharmony_ci 101813498266Sopenharmony_cifail: 101913498266Sopenharmony_ci 102013498266Sopenharmony_ci if(outcurl) { 102113498266Sopenharmony_ci#ifndef CURL_DISABLE_COOKIES 102213498266Sopenharmony_ci free(outcurl->cookies); 102313498266Sopenharmony_ci#endif 102413498266Sopenharmony_ci free(outcurl->state.buffer); 102513498266Sopenharmony_ci Curl_dyn_free(&outcurl->state.headerb); 102613498266Sopenharmony_ci Curl_altsvc_cleanup(&outcurl->asi); 102713498266Sopenharmony_ci Curl_hsts_cleanup(&outcurl->hsts); 102813498266Sopenharmony_ci Curl_freeset(outcurl); 102913498266Sopenharmony_ci free(outcurl); 103013498266Sopenharmony_ci } 103113498266Sopenharmony_ci 103213498266Sopenharmony_ci return NULL; 103313498266Sopenharmony_ci} 103413498266Sopenharmony_ci 103513498266Sopenharmony_ci/* 103613498266Sopenharmony_ci * curl_easy_reset() is an external interface that allows an app to re- 103713498266Sopenharmony_ci * initialize a session handle to the default values. 103813498266Sopenharmony_ci */ 103913498266Sopenharmony_civoid curl_easy_reset(struct Curl_easy *data) 104013498266Sopenharmony_ci{ 104113498266Sopenharmony_ci Curl_free_request_state(data); 104213498266Sopenharmony_ci 104313498266Sopenharmony_ci /* zero out UserDefined data: */ 104413498266Sopenharmony_ci Curl_freeset(data); 104513498266Sopenharmony_ci memset(&data->set, 0, sizeof(struct UserDefined)); 104613498266Sopenharmony_ci (void)Curl_init_userdefined(data); 104713498266Sopenharmony_ci 104813498266Sopenharmony_ci /* zero out Progress data: */ 104913498266Sopenharmony_ci memset(&data->progress, 0, sizeof(struct Progress)); 105013498266Sopenharmony_ci 105113498266Sopenharmony_ci /* zero out PureInfo data: */ 105213498266Sopenharmony_ci Curl_initinfo(data); 105313498266Sopenharmony_ci 105413498266Sopenharmony_ci data->progress.flags |= PGRS_HIDE; 105513498266Sopenharmony_ci data->state.current_speed = -1; /* init to negative == impossible */ 105613498266Sopenharmony_ci data->state.retrycount = 0; /* reset the retry counter */ 105713498266Sopenharmony_ci 105813498266Sopenharmony_ci /* zero out authentication data: */ 105913498266Sopenharmony_ci memset(&data->state.authhost, 0, sizeof(struct auth)); 106013498266Sopenharmony_ci memset(&data->state.authproxy, 0, sizeof(struct auth)); 106113498266Sopenharmony_ci 106213498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) 106313498266Sopenharmony_ci Curl_http_auth_cleanup_digest(data); 106413498266Sopenharmony_ci#endif 106513498266Sopenharmony_ci} 106613498266Sopenharmony_ci 106713498266Sopenharmony_ci/* 106813498266Sopenharmony_ci * curl_easy_pause() allows an application to pause or unpause a specific 106913498266Sopenharmony_ci * transfer and direction. This function sets the full new state for the 107013498266Sopenharmony_ci * current connection this easy handle operates on. 107113498266Sopenharmony_ci * 107213498266Sopenharmony_ci * NOTE: if you have the receiving paused and you call this function to remove 107313498266Sopenharmony_ci * the pausing, you may get your write callback called at this point. 107413498266Sopenharmony_ci * 107513498266Sopenharmony_ci * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h 107613498266Sopenharmony_ci * 107713498266Sopenharmony_ci * NOTE: This is one of few API functions that are allowed to be called from 107813498266Sopenharmony_ci * within a callback. 107913498266Sopenharmony_ci */ 108013498266Sopenharmony_ciCURLcode curl_easy_pause(struct Curl_easy *data, int action) 108113498266Sopenharmony_ci{ 108213498266Sopenharmony_ci struct SingleRequest *k; 108313498266Sopenharmony_ci CURLcode result = CURLE_OK; 108413498266Sopenharmony_ci int oldstate; 108513498266Sopenharmony_ci int newstate; 108613498266Sopenharmony_ci bool recursive = FALSE; 108713498266Sopenharmony_ci 108813498266Sopenharmony_ci if(!GOOD_EASY_HANDLE(data) || !data->conn) 108913498266Sopenharmony_ci /* crazy input, don't continue */ 109013498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 109113498266Sopenharmony_ci 109213498266Sopenharmony_ci if(Curl_is_in_callback(data)) 109313498266Sopenharmony_ci recursive = TRUE; 109413498266Sopenharmony_ci k = &data->req; 109513498266Sopenharmony_ci oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); 109613498266Sopenharmony_ci 109713498266Sopenharmony_ci /* first switch off both pause bits then set the new pause bits */ 109813498266Sopenharmony_ci newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) | 109913498266Sopenharmony_ci ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) | 110013498266Sopenharmony_ci ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0); 110113498266Sopenharmony_ci 110213498266Sopenharmony_ci if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) { 110313498266Sopenharmony_ci /* Not changing any pause state, return */ 110413498266Sopenharmony_ci DEBUGF(infof(data, "pause: no change, early return")); 110513498266Sopenharmony_ci return CURLE_OK; 110613498266Sopenharmony_ci } 110713498266Sopenharmony_ci 110813498266Sopenharmony_ci /* Unpause parts in active mime tree. */ 110913498266Sopenharmony_ci if((k->keepon & ~newstate & KEEP_SEND_PAUSE) && 111013498266Sopenharmony_ci (data->mstate == MSTATE_PERFORMING || 111113498266Sopenharmony_ci data->mstate == MSTATE_RATELIMITING) && 111213498266Sopenharmony_ci data->state.fread_func == (curl_read_callback) Curl_mime_read) { 111313498266Sopenharmony_ci Curl_mime_unpause(data->state.in); 111413498266Sopenharmony_ci } 111513498266Sopenharmony_ci 111613498266Sopenharmony_ci /* put it back in the keepon */ 111713498266Sopenharmony_ci k->keepon = newstate; 111813498266Sopenharmony_ci 111913498266Sopenharmony_ci if(!(newstate & KEEP_RECV_PAUSE)) { 112013498266Sopenharmony_ci Curl_conn_ev_data_pause(data, FALSE); 112113498266Sopenharmony_ci result = Curl_client_unpause(data); 112213498266Sopenharmony_ci if(result) 112313498266Sopenharmony_ci return result; 112413498266Sopenharmony_ci } 112513498266Sopenharmony_ci 112613498266Sopenharmony_ci#ifdef USE_HYPER 112713498266Sopenharmony_ci if(!(newstate & KEEP_SEND_PAUSE)) { 112813498266Sopenharmony_ci /* need to wake the send body waker */ 112913498266Sopenharmony_ci if(data->hyp.send_body_waker) { 113013498266Sopenharmony_ci hyper_waker_wake(data->hyp.send_body_waker); 113113498266Sopenharmony_ci data->hyp.send_body_waker = NULL; 113213498266Sopenharmony_ci } 113313498266Sopenharmony_ci } 113413498266Sopenharmony_ci#endif 113513498266Sopenharmony_ci 113613498266Sopenharmony_ci /* if there's no error and we're not pausing both directions, we want 113713498266Sopenharmony_ci to have this handle checked soon */ 113813498266Sopenharmony_ci if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != 113913498266Sopenharmony_ci (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) { 114013498266Sopenharmony_ci Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ 114113498266Sopenharmony_ci 114213498266Sopenharmony_ci /* reset the too-slow time keeper */ 114313498266Sopenharmony_ci data->state.keeps_speed.tv_sec = 0; 114413498266Sopenharmony_ci 114513498266Sopenharmony_ci if(!data->state.tempcount) 114613498266Sopenharmony_ci /* if not pausing again, force a recv/send check of this connection as 114713498266Sopenharmony_ci the data might've been read off the socket already */ 114813498266Sopenharmony_ci data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT; 114913498266Sopenharmony_ci if(data->multi) { 115013498266Sopenharmony_ci if(Curl_update_timer(data->multi)) 115113498266Sopenharmony_ci return CURLE_ABORTED_BY_CALLBACK; 115213498266Sopenharmony_ci } 115313498266Sopenharmony_ci } 115413498266Sopenharmony_ci 115513498266Sopenharmony_ci if(!data->state.done) 115613498266Sopenharmony_ci /* This transfer may have been moved in or out of the bundle, update the 115713498266Sopenharmony_ci corresponding socket callback, if used */ 115813498266Sopenharmony_ci result = Curl_updatesocket(data); 115913498266Sopenharmony_ci 116013498266Sopenharmony_ci if(recursive) 116113498266Sopenharmony_ci /* this might have called a callback recursively which might have set this 116213498266Sopenharmony_ci to false again on exit */ 116313498266Sopenharmony_ci Curl_set_in_callback(data, TRUE); 116413498266Sopenharmony_ci 116513498266Sopenharmony_ci return result; 116613498266Sopenharmony_ci} 116713498266Sopenharmony_ci 116813498266Sopenharmony_ci 116913498266Sopenharmony_cistatic CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, 117013498266Sopenharmony_ci struct connectdata **connp) 117113498266Sopenharmony_ci{ 117213498266Sopenharmony_ci if(!data) 117313498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 117413498266Sopenharmony_ci 117513498266Sopenharmony_ci /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */ 117613498266Sopenharmony_ci if(!data->set.connect_only) { 117713498266Sopenharmony_ci failf(data, "CONNECT_ONLY is required"); 117813498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 117913498266Sopenharmony_ci } 118013498266Sopenharmony_ci 118113498266Sopenharmony_ci *sfd = Curl_getconnectinfo(data, connp); 118213498266Sopenharmony_ci 118313498266Sopenharmony_ci if(*sfd == CURL_SOCKET_BAD) { 118413498266Sopenharmony_ci failf(data, "Failed to get recent socket"); 118513498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 118613498266Sopenharmony_ci } 118713498266Sopenharmony_ci 118813498266Sopenharmony_ci return CURLE_OK; 118913498266Sopenharmony_ci} 119013498266Sopenharmony_ci 119113498266Sopenharmony_ci/* 119213498266Sopenharmony_ci * Receives data from the connected socket. Use after successful 119313498266Sopenharmony_ci * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 119413498266Sopenharmony_ci * Returns CURLE_OK on success, error code on error. 119513498266Sopenharmony_ci */ 119613498266Sopenharmony_ciCURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, 119713498266Sopenharmony_ci size_t *n) 119813498266Sopenharmony_ci{ 119913498266Sopenharmony_ci curl_socket_t sfd; 120013498266Sopenharmony_ci CURLcode result; 120113498266Sopenharmony_ci ssize_t n1; 120213498266Sopenharmony_ci struct connectdata *c; 120313498266Sopenharmony_ci 120413498266Sopenharmony_ci if(Curl_is_in_callback(data)) 120513498266Sopenharmony_ci return CURLE_RECURSIVE_API_CALL; 120613498266Sopenharmony_ci 120713498266Sopenharmony_ci result = easy_connection(data, &sfd, &c); 120813498266Sopenharmony_ci if(result) 120913498266Sopenharmony_ci return result; 121013498266Sopenharmony_ci 121113498266Sopenharmony_ci if(!data->conn) 121213498266Sopenharmony_ci /* on first invoke, the transfer has been detached from the connection and 121313498266Sopenharmony_ci needs to be reattached */ 121413498266Sopenharmony_ci Curl_attach_connection(data, c); 121513498266Sopenharmony_ci 121613498266Sopenharmony_ci *n = 0; 121713498266Sopenharmony_ci result = Curl_read(data, sfd, buffer, buflen, &n1); 121813498266Sopenharmony_ci 121913498266Sopenharmony_ci if(result) 122013498266Sopenharmony_ci return result; 122113498266Sopenharmony_ci 122213498266Sopenharmony_ci *n = (size_t)n1; 122313498266Sopenharmony_ci return CURLE_OK; 122413498266Sopenharmony_ci} 122513498266Sopenharmony_ci 122613498266Sopenharmony_ci#ifdef USE_WEBSOCKETS 122713498266Sopenharmony_ciCURLcode Curl_connect_only_attach(struct Curl_easy *data) 122813498266Sopenharmony_ci{ 122913498266Sopenharmony_ci curl_socket_t sfd; 123013498266Sopenharmony_ci CURLcode result; 123113498266Sopenharmony_ci struct connectdata *c = NULL; 123213498266Sopenharmony_ci 123313498266Sopenharmony_ci result = easy_connection(data, &sfd, &c); 123413498266Sopenharmony_ci if(result) 123513498266Sopenharmony_ci return result; 123613498266Sopenharmony_ci 123713498266Sopenharmony_ci if(!data->conn) 123813498266Sopenharmony_ci /* on first invoke, the transfer has been detached from the connection and 123913498266Sopenharmony_ci needs to be reattached */ 124013498266Sopenharmony_ci Curl_attach_connection(data, c); 124113498266Sopenharmony_ci 124213498266Sopenharmony_ci return CURLE_OK; 124313498266Sopenharmony_ci} 124413498266Sopenharmony_ci#endif /* USE_WEBSOCKETS */ 124513498266Sopenharmony_ci 124613498266Sopenharmony_ci/* 124713498266Sopenharmony_ci * Sends data over the connected socket. 124813498266Sopenharmony_ci * 124913498266Sopenharmony_ci * This is the private internal version of curl_easy_send() 125013498266Sopenharmony_ci */ 125113498266Sopenharmony_ciCURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, 125213498266Sopenharmony_ci size_t buflen, ssize_t *n) 125313498266Sopenharmony_ci{ 125413498266Sopenharmony_ci curl_socket_t sfd; 125513498266Sopenharmony_ci CURLcode result; 125613498266Sopenharmony_ci ssize_t n1; 125713498266Sopenharmony_ci struct connectdata *c = NULL; 125813498266Sopenharmony_ci SIGPIPE_VARIABLE(pipe_st); 125913498266Sopenharmony_ci 126013498266Sopenharmony_ci result = easy_connection(data, &sfd, &c); 126113498266Sopenharmony_ci if(result) 126213498266Sopenharmony_ci return result; 126313498266Sopenharmony_ci 126413498266Sopenharmony_ci if(!data->conn) 126513498266Sopenharmony_ci /* on first invoke, the transfer has been detached from the connection and 126613498266Sopenharmony_ci needs to be reattached */ 126713498266Sopenharmony_ci Curl_attach_connection(data, c); 126813498266Sopenharmony_ci 126913498266Sopenharmony_ci *n = 0; 127013498266Sopenharmony_ci sigpipe_ignore(data, &pipe_st); 127113498266Sopenharmony_ci result = Curl_write(data, sfd, buffer, buflen, &n1); 127213498266Sopenharmony_ci sigpipe_restore(&pipe_st); 127313498266Sopenharmony_ci 127413498266Sopenharmony_ci if(n1 == -1) 127513498266Sopenharmony_ci return CURLE_SEND_ERROR; 127613498266Sopenharmony_ci 127713498266Sopenharmony_ci /* detect EAGAIN */ 127813498266Sopenharmony_ci if(!result && !n1) 127913498266Sopenharmony_ci return CURLE_AGAIN; 128013498266Sopenharmony_ci 128113498266Sopenharmony_ci *n = n1; 128213498266Sopenharmony_ci 128313498266Sopenharmony_ci return result; 128413498266Sopenharmony_ci} 128513498266Sopenharmony_ci 128613498266Sopenharmony_ci/* 128713498266Sopenharmony_ci * Sends data over the connected socket. Use after successful 128813498266Sopenharmony_ci * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 128913498266Sopenharmony_ci */ 129013498266Sopenharmony_ciCURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, 129113498266Sopenharmony_ci size_t buflen, size_t *n) 129213498266Sopenharmony_ci{ 129313498266Sopenharmony_ci ssize_t written = 0; 129413498266Sopenharmony_ci CURLcode result; 129513498266Sopenharmony_ci if(Curl_is_in_callback(data)) 129613498266Sopenharmony_ci return CURLE_RECURSIVE_API_CALL; 129713498266Sopenharmony_ci 129813498266Sopenharmony_ci result = Curl_senddata(data, buffer, buflen, &written); 129913498266Sopenharmony_ci *n = (size_t)written; 130013498266Sopenharmony_ci return result; 130113498266Sopenharmony_ci} 130213498266Sopenharmony_ci 130313498266Sopenharmony_ci/* 130413498266Sopenharmony_ci * Wrapper to call functions in Curl_conncache_foreach() 130513498266Sopenharmony_ci * 130613498266Sopenharmony_ci * Returns always 0. 130713498266Sopenharmony_ci */ 130813498266Sopenharmony_cistatic int conn_upkeep(struct Curl_easy *data, 130913498266Sopenharmony_ci struct connectdata *conn, 131013498266Sopenharmony_ci void *param) 131113498266Sopenharmony_ci{ 131213498266Sopenharmony_ci struct curltime *now = param; 131313498266Sopenharmony_ci 131413498266Sopenharmony_ci if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms) 131513498266Sopenharmony_ci return 0; 131613498266Sopenharmony_ci 131713498266Sopenharmony_ci /* briefly attach for action */ 131813498266Sopenharmony_ci Curl_attach_connection(data, conn); 131913498266Sopenharmony_ci if(conn->handler->connection_check) { 132013498266Sopenharmony_ci /* Do a protocol-specific keepalive check on the connection. */ 132113498266Sopenharmony_ci conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE); 132213498266Sopenharmony_ci } 132313498266Sopenharmony_ci else { 132413498266Sopenharmony_ci /* Do the generic action on the FIRSTSOCKE filter chain */ 132513498266Sopenharmony_ci Curl_conn_keep_alive(data, conn, FIRSTSOCKET); 132613498266Sopenharmony_ci } 132713498266Sopenharmony_ci Curl_detach_connection(data); 132813498266Sopenharmony_ci 132913498266Sopenharmony_ci conn->keepalive = *now; 133013498266Sopenharmony_ci return 0; /* continue iteration */ 133113498266Sopenharmony_ci} 133213498266Sopenharmony_ci 133313498266Sopenharmony_cistatic CURLcode upkeep(struct conncache *conn_cache, void *data) 133413498266Sopenharmony_ci{ 133513498266Sopenharmony_ci struct curltime now = Curl_now(); 133613498266Sopenharmony_ci /* Loop over every connection and make connection alive. */ 133713498266Sopenharmony_ci Curl_conncache_foreach(data, 133813498266Sopenharmony_ci conn_cache, 133913498266Sopenharmony_ci &now, 134013498266Sopenharmony_ci conn_upkeep); 134113498266Sopenharmony_ci return CURLE_OK; 134213498266Sopenharmony_ci} 134313498266Sopenharmony_ci 134413498266Sopenharmony_ci/* 134513498266Sopenharmony_ci * Performs connection upkeep for the given session handle. 134613498266Sopenharmony_ci */ 134713498266Sopenharmony_ciCURLcode curl_easy_upkeep(struct Curl_easy *data) 134813498266Sopenharmony_ci{ 134913498266Sopenharmony_ci /* Verify that we got an easy handle we can work with. */ 135013498266Sopenharmony_ci if(!GOOD_EASY_HANDLE(data)) 135113498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 135213498266Sopenharmony_ci 135313498266Sopenharmony_ci if(data->multi_easy) { 135413498266Sopenharmony_ci /* Use the common function to keep connections alive. */ 135513498266Sopenharmony_ci return upkeep(&data->multi_easy->conn_cache, data); 135613498266Sopenharmony_ci } 135713498266Sopenharmony_ci else { 135813498266Sopenharmony_ci /* No connections, so just return success */ 135913498266Sopenharmony_ci return CURLE_OK; 136013498266Sopenharmony_ci } 136113498266Sopenharmony_ci} 1362