Coverage Report

Created: 2026-06-15 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmcurl/lib/asyn-base.c
Line
Count
Source
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
#include "curl_setup.h"
25
26
#ifdef HAVE_NETINET_IN_H
27
#include <netinet/in.h>
28
#endif
29
#ifdef HAVE_NETDB_H
30
#include <netdb.h>
31
#endif
32
#ifdef HAVE_ARPA_INET_H
33
#include <arpa/inet.h>
34
#endif
35
#ifdef __VMS
36
#include <in.h>
37
#include <inet.h>
38
#endif
39
40
#ifdef USE_ARES
41
#include <ares.h>
42
#endif
43
44
#include "urldata.h"
45
#include "connect.h"
46
#include "curl_trc.h"
47
#include "hostip.h"
48
#include "multiif.h"
49
#include "progress.h"
50
#include "select.h"
51
#include "url.h"
52
53
/***********************************************************************
54
 * Only for builds using asynchronous name resolves
55
 **********************************************************************/
56
#ifdef CURLRES_ASYNCH
57
58
timediff_t Curl_async_timeleft_ms(struct Curl_easy *data,
59
                                  struct Curl_resolv_async *async)
60
{
61
  if(async->timeout_ms) {
62
    timediff_t elapsed_ms =
63
      curlx_ptimediff_ms(Curl_pgrs_now(data), &async->start);
64
    return async->timeout_ms - elapsed_ms;
65
  }
66
  return Curl_timeleft_ms(data);
67
}
68
69
#ifdef USE_ARES
70
71
#if ARES_VERSION < 0x011000
72
#error "requires c-ares 1.16.0 or newer"
73
#endif
74
75
/*
76
 * Curl_ares_pollset() is called when the outside world (using
77
 * curl_multi_fdset()) wants to get our fd_set setup and we are talking with
78
 * ares. The caller must make sure that this function is only called when we
79
 * have a working ares channel.
80
 *
81
 * Returns: sockets-in-use-bitmap
82
 */
83
CURLcode Curl_ares_pollset(struct Curl_easy *data,
84
                           ares_channel channel,
85
                           struct easy_pollset *ps)
86
{
87
  curl_socket_t sockets[16];  /* ARES documented limit */
88
  unsigned int bitmap, i;
89
  CURLcode result = CURLE_OK;
90
91
  DEBUGASSERT(channel);
92
  if(!channel)
93
    return CURLE_FAILED_INIT;
94
95
  bitmap = ares_getsock(channel, (ares_socket_t *)sockets,
96
                        CURL_ARRAYSIZE(sockets));
97
  for(i = 0; i < CURL_ARRAYSIZE(sockets); ++i) {
98
    int flags = 0;
99
    if(ARES_GETSOCK_READABLE(bitmap, i))
100
      flags |= CURL_POLL_IN;
101
    if(ARES_GETSOCK_WRITABLE(bitmap, i))
102
      flags |= CURL_POLL_OUT;
103
    if(!flags)
104
      break;
105
    result = Curl_pollset_change(data, ps, sockets[i], flags, 0);
106
    if(result)
107
      return result;
108
  }
109
  return result;
110
}
111
112
timediff_t Curl_ares_timeout_ms(struct Curl_easy *data,
113
                                struct Curl_resolv_async *async,
114
                                ares_channel channel)
115
{
116
  timediff_t async_timeout_ms;
117
118
  DEBUGASSERT(channel);
119
  if(!channel)
120
    return -1;
121
122
  async_timeout_ms = Curl_async_timeleft_ms(data, async);
123
  if((async_timeout_ms > 0) && (async_timeout_ms < INT_MAX)) {
124
    struct timeval timebuf;
125
    struct timeval *timeout;
126
    struct timeval end = { (int)async_timeout_ms / 1000,
127
                           ((int)async_timeout_ms % 1000) * 1000 };
128
129
    timeout = ares_timeout(channel, &end, &timebuf);
130
    if(timeout)
131
      return curlx_tvtoms(timeout);
132
  }
133
  return async_timeout_ms;
134
}
135
136
/*
137
 * Curl_ares_perform()
138
 *
139
 * 1) Ask ares what sockets it currently plays with, then
140
 * 2) wait for the timeout period to check for action on ares' sockets.
141
 * 3) tell ares to act on all the sockets marked as "with action"
142
 *
143
 * return number of sockets it worked on, or -1 on error
144
 */
145
int Curl_ares_perform(ares_channel channel, timediff_t timeout_ms)
146
{
147
  int nfds;
148
  int bitmask;
149
  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
150
  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
151
  int i;
152
  int num = 0;
153
154
  if(!channel)
155
    return 0;
156
157
  bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
158
159
  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
160
    pfd[i].events = 0;
161
    pfd[i].revents = 0;
162
    if(ARES_GETSOCK_READABLE(bitmask, i)) {
163
      pfd[i].fd = socks[i];
164
      pfd[i].events |= POLLRDNORM | POLLIN;
165
    }
166
    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
167
      pfd[i].fd = socks[i];
168
      pfd[i].events |= POLLWRNORM | POLLOUT;
169
    }
170
    if(pfd[i].events)
171
      num++;
172
    else
173
      break;
174
  }
175
176
  if(num) {
177
    nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
178
    if(nfds < 0)
179
      return -1;
180
  }
181
  else
182
    nfds = 0;
183
184
  if(!nfds)
185
    /* Call ares_process() unconditionally here, even if we timed out
186
       above, as otherwise the ares name resolve will not timeout! */
187
    ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
188
  else {
189
    /* move through the descriptors and ask for processing on them */
190
    for(i = 0; i < num; i++)
191
      ares_process_fd(channel,
192
                      (pfd[i].revents & (POLLRDNORM | POLLIN)) ?
193
                      pfd[i].fd : ARES_SOCKET_BAD,
194
                      (pfd[i].revents & (POLLWRNORM | POLLOUT)) ?
195
                      pfd[i].fd : ARES_SOCKET_BAD);
196
  }
197
  return nfds;
198
}
199
200
#endif /* USE_ARES */
201
202
#endif /* CURLRES_ASYNCH */
203
204
#ifdef USE_CURL_ASYNC
205
206
#include "doh.h"
207
208
void Curl_async_shutdown(struct Curl_easy *data,
209
                         struct Curl_resolv_async *async)
210
0
{
211
0
  if(async) {
212
0
    CURL_TRC_DNS(data, "[%u] shutdown async", async->id);
213
0
    async->shutdown = TRUE;
214
#ifdef USE_RESOLV_ARES
215
    Curl_async_ares_shutdown(data, async);
216
#endif
217
#ifdef USE_RESOLV_THREADED
218
    Curl_async_thrdd_shutdown(data, async);
219
#endif
220
0
#ifndef CURL_DISABLE_DOH
221
0
    Curl_doh_cleanup(data, async);
222
0
#endif
223
0
  }
224
0
}
225
226
void Curl_async_destroy(struct Curl_easy *data,
227
                        struct Curl_resolv_async *async)
228
0
{
229
0
  if(async) {
230
0
    CURL_TRC_DNS(data, "[%u] destroy async", async->id);
231
0
    async->shutdown = TRUE;
232
#ifdef USE_RESOLV_ARES
233
    Curl_async_ares_destroy(data, async);
234
#endif
235
#ifdef USE_RESOLV_THREADED
236
    Curl_async_thrdd_destroy(data, async);
237
#endif
238
0
#ifndef CURL_DISABLE_DOH
239
0
    Curl_doh_cleanup(data, async);
240
0
#endif
241
0
    curlx_safefree(async);
242
0
  }
243
0
}
244
245
CURLcode Curl_async_failed(struct Curl_easy *data,
246
                           struct Curl_resolv_async *async,
247
                           const char *detail)
248
0
{
249
0
  const char *host_or_proxy = "host";
250
0
  CURLcode result = CURLE_COULDNT_RESOLVE_HOST;
251
252
0
#ifndef CURL_DISABLE_PROXY
253
0
  if(async->for_proxy) {
254
0
    host_or_proxy = "proxy";
255
0
    result = CURLE_COULDNT_RESOLVE_PROXY;
256
0
  }
257
0
#endif
258
259
0
  failf(data, "Could not resolve %s: %s%s%s%s",
260
0
        host_or_proxy, async->hostname,
261
0
        detail ? " (" : "", detail ? detail : "", detail ? ")" : "");
262
0
  return result;
263
0
}
264
265
#endif /* USE_CURL_ASYNC */