asyn-base.c (5230B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "curl_setup.h" 26 27 #ifdef HAVE_NETINET_IN_H 28 #include <netinet/in.h> 29 #endif 30 #ifdef HAVE_NETDB_H 31 #include <netdb.h> 32 #endif 33 #ifdef HAVE_ARPA_INET_H 34 #include <arpa/inet.h> 35 #endif 36 #ifdef __VMS 37 #include <in.h> 38 #include <inet.h> 39 #endif 40 41 #ifdef USE_ARES 42 #include <ares.h> 43 #include <ares_version.h> /* really old c-ares did not include this by 44 itself */ 45 #endif 46 47 #include "urldata.h" 48 #include "asyn.h" 49 #include "sendf.h" 50 #include "hostip.h" 51 #include "hash.h" 52 #include "multiif.h" 53 #include "select.h" 54 #include "share.h" 55 #include "url.h" 56 #include "curl_memory.h" 57 /* The last #include file should be: */ 58 #include "memdebug.h" 59 60 /*********************************************************************** 61 * Only for builds using asynchronous name resolves 62 **********************************************************************/ 63 #ifdef CURLRES_ASYNCH 64 65 66 #ifdef USE_ARES 67 68 #if ARES_VERSION < 0x010600 69 #error "requires c-ares 1.6.0 or newer" 70 #endif 71 72 /* 73 * Curl_ares_getsock() is called when the outside world (using 74 * curl_multi_fdset()) wants to get our fd_set setup and we are talking with 75 * ares. The caller must make sure that this function is only called when we 76 * have a working ares channel. 77 * 78 * Returns: sockets-in-use-bitmap 79 */ 80 81 int Curl_ares_getsock(struct Curl_easy *data, 82 ares_channel channel, 83 curl_socket_t *socks) 84 { 85 struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 }; 86 struct timeval timebuf; 87 int max = ares_getsock(channel, 88 (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); 89 struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf); 90 timediff_t milli = curlx_tvtoms(timeout); 91 Curl_expire(data, milli, EXPIRE_ASYNC_NAME); 92 return max; 93 } 94 95 /* 96 * Curl_ares_perform() 97 * 98 * 1) Ask ares what sockets it currently plays with, then 99 * 2) wait for the timeout period to check for action on ares' sockets. 100 * 3) tell ares to act on all the sockets marked as "with action" 101 * 102 * return number of sockets it worked on, or -1 on error 103 */ 104 int Curl_ares_perform(ares_channel channel, 105 timediff_t timeout_ms) 106 { 107 int nfds; 108 int bitmask; 109 ares_socket_t socks[ARES_GETSOCK_MAXNUM]; 110 struct pollfd pfd[ARES_GETSOCK_MAXNUM]; 111 int i; 112 int num = 0; 113 114 if(!channel) 115 return 0; 116 117 bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM); 118 119 for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { 120 pfd[i].events = 0; 121 pfd[i].revents = 0; 122 if(ARES_GETSOCK_READABLE(bitmask, i)) { 123 pfd[i].fd = socks[i]; 124 pfd[i].events |= POLLRDNORM|POLLIN; 125 } 126 if(ARES_GETSOCK_WRITABLE(bitmask, i)) { 127 pfd[i].fd = socks[i]; 128 pfd[i].events |= POLLWRNORM|POLLOUT; 129 } 130 if(pfd[i].events) 131 num++; 132 else 133 break; 134 } 135 136 if(num) { 137 nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms); 138 if(nfds < 0) 139 return -1; 140 } 141 else 142 nfds = 0; 143 144 if(!nfds) 145 /* Call ares_process() unconditionally here, even if we simply timed out 146 above, as otherwise the ares name resolve will not timeout! */ 147 ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); 148 else { 149 /* move through the descriptors and ask for processing on them */ 150 for(i = 0; i < num; i++) 151 ares_process_fd(channel, 152 (pfd[i].revents & (POLLRDNORM|POLLIN)) ? 153 pfd[i].fd : ARES_SOCKET_BAD, 154 (pfd[i].revents & (POLLWRNORM|POLLOUT)) ? 155 pfd[i].fd : ARES_SOCKET_BAD); 156 } 157 return nfds; 158 } 159 160 #endif 161 162 #endif /* CURLRES_ASYNCH */ 163 164 #ifdef USE_CURL_ASYNC 165 166 #include "doh.h" 167 168 void Curl_async_shutdown(struct Curl_easy *data) 169 { 170 #ifdef CURLRES_ARES 171 Curl_async_ares_shutdown(data); 172 #endif 173 #ifdef CURLRES_THREADED 174 Curl_async_thrdd_shutdown(data); 175 #endif 176 #ifndef CURL_DISABLE_DOH 177 Curl_doh_cleanup(data); 178 #endif 179 Curl_safefree(data->state.async.hostname); 180 } 181 182 void Curl_async_destroy(struct Curl_easy *data) 183 { 184 #ifdef CURLRES_ARES 185 Curl_async_ares_destroy(data); 186 #endif 187 #ifdef CURLRES_THREADED 188 Curl_async_thrdd_destroy(data); 189 #endif 190 #ifndef CURL_DISABLE_DOH 191 Curl_doh_cleanup(data); 192 #endif 193 Curl_safefree(data->state.async.hostname); 194 } 195 196 #endif /* USE_CURL_ASYNC */