mirror of
https://github.com/curl/curl.git
synced 2026-04-14 18:11:40 +03:00
Replace the `volatile int dirty` with a reference counter protected by a mutex when available. Solve the problem of when to call application's lock function by adding a volatile flag that indicates a share has been added to easy handles in its lifetime. That flag ever goes from FALSE to TRUE, so volatile might work (in the absence of a mutex). (The problem is that the lock/unlock functions need 2-3 `curl_share_setopt()` invocations to become usable and there is no way of telling if the third will ever happen. Calling the lock function before the 3rd setopt may crash the application.) When removing a share from an easy handle (or replacing it with another share), detach the easy connection on a share with a connection pool. When cleaning up a share, allow this even if it is still used in easy handles. It will be destroyed when the reference count drops to 0. Closes #20870
215 lines
5.8 KiB
C
215 lines
5.8 KiB
C
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
* SPDX-License-Identifier: curl
|
|
*
|
|
***************************************************************************/
|
|
#include "curl_setup.h"
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
#ifdef HAVE_NETDB_H
|
|
#include <netdb.h>
|
|
#endif
|
|
#ifdef HAVE_ARPA_INET_H
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#ifdef __VMS
|
|
#include <in.h>
|
|
#include <inet.h>
|
|
#endif
|
|
|
|
#ifdef USE_ARES
|
|
#include <ares.h>
|
|
#include <ares_version.h> /* really old c-ares did not include it by itself */
|
|
#endif
|
|
|
|
#include "urldata.h"
|
|
#include "curl_trc.h"
|
|
#include "hostip.h"
|
|
#include "multiif.h"
|
|
#include "select.h"
|
|
#include "url.h"
|
|
|
|
/***********************************************************************
|
|
* Only for builds using asynchronous name resolves
|
|
**********************************************************************/
|
|
#ifdef CURLRES_ASYNCH
|
|
|
|
#ifdef USE_ARES
|
|
|
|
#if ARES_VERSION < 0x010600
|
|
#error "requires c-ares 1.6.0 or newer"
|
|
#endif
|
|
|
|
/*
|
|
* Curl_ares_pollset() is called when the outside world (using
|
|
* curl_multi_fdset()) wants to get our fd_set setup and we are talking with
|
|
* ares. The caller must make sure that this function is only called when we
|
|
* have a working ares channel.
|
|
*
|
|
* Returns: sockets-in-use-bitmap
|
|
*/
|
|
CURLcode Curl_ares_pollset(struct Curl_easy *data,
|
|
ares_channel channel,
|
|
struct easy_pollset *ps)
|
|
{
|
|
struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
|
|
struct timeval timebuf;
|
|
curl_socket_t sockets[16]; /* ARES documented limit */
|
|
unsigned int bitmap, i;
|
|
struct timeval *timeout;
|
|
timediff_t milli;
|
|
CURLcode result = CURLE_OK;
|
|
|
|
DEBUGASSERT(channel);
|
|
if(!channel)
|
|
return CURLE_FAILED_INIT;
|
|
|
|
bitmap = ares_getsock(channel, (ares_socket_t *)sockets,
|
|
CURL_ARRAYSIZE(sockets));
|
|
for(i = 0; i < CURL_ARRAYSIZE(sockets); ++i) {
|
|
int flags = 0;
|
|
if(ARES_GETSOCK_READABLE(bitmap, i))
|
|
flags |= CURL_POLL_IN;
|
|
if(ARES_GETSOCK_WRITABLE(bitmap, i))
|
|
flags |= CURL_POLL_OUT;
|
|
if(!flags)
|
|
break;
|
|
result = Curl_pollset_change(data, ps, sockets[i], flags, 0);
|
|
if(result)
|
|
return result;
|
|
}
|
|
|
|
timeout = ares_timeout(channel, &maxtime, &timebuf);
|
|
if(!timeout)
|
|
timeout = &maxtime;
|
|
milli = curlx_tvtoms(timeout);
|
|
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Curl_ares_perform()
|
|
*
|
|
* 1) Ask ares what sockets it currently plays with, then
|
|
* 2) wait for the timeout period to check for action on ares' sockets.
|
|
* 3) tell ares to act on all the sockets marked as "with action"
|
|
*
|
|
* return number of sockets it worked on, or -1 on error
|
|
*/
|
|
int Curl_ares_perform(ares_channel channel, timediff_t timeout_ms)
|
|
{
|
|
int nfds;
|
|
int bitmask;
|
|
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
|
|
struct pollfd pfd[ARES_GETSOCK_MAXNUM];
|
|
int i;
|
|
int num = 0;
|
|
|
|
if(!channel)
|
|
return 0;
|
|
|
|
bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
|
|
|
|
for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
|
|
pfd[i].events = 0;
|
|
pfd[i].revents = 0;
|
|
if(ARES_GETSOCK_READABLE(bitmask, i)) {
|
|
pfd[i].fd = socks[i];
|
|
pfd[i].events |= POLLRDNORM | POLLIN;
|
|
}
|
|
if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
|
|
pfd[i].fd = socks[i];
|
|
pfd[i].events |= POLLWRNORM | POLLOUT;
|
|
}
|
|
if(pfd[i].events)
|
|
num++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if(num) {
|
|
nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
|
|
if(nfds < 0)
|
|
return -1;
|
|
}
|
|
else
|
|
nfds = 0;
|
|
|
|
if(!nfds)
|
|
/* Call ares_process() unconditionally here, even if we timed out
|
|
above, as otherwise the ares name resolve will not timeout! */
|
|
ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
|
|
else {
|
|
/* move through the descriptors and ask for processing on them */
|
|
for(i = 0; i < num; i++)
|
|
ares_process_fd(channel,
|
|
(pfd[i].revents & (POLLRDNORM | POLLIN)) ?
|
|
pfd[i].fd : ARES_SOCKET_BAD,
|
|
(pfd[i].revents & (POLLWRNORM | POLLOUT)) ?
|
|
pfd[i].fd : ARES_SOCKET_BAD);
|
|
}
|
|
return nfds;
|
|
}
|
|
|
|
#endif /* USE_ARES */
|
|
|
|
#endif /* CURLRES_ASYNCH */
|
|
|
|
#ifdef USE_CURL_ASYNC
|
|
|
|
#include "doh.h"
|
|
|
|
void Curl_async_shutdown(struct Curl_easy *data)
|
|
{
|
|
if(data->state.async) {
|
|
CURL_TRC_DNS(data, "shutdown async");
|
|
#ifdef USE_RESOLV_ARES
|
|
Curl_async_ares_shutdown(data, data->state.async);
|
|
#endif
|
|
#ifdef USE_RESOLV_THREADED
|
|
Curl_async_thrdd_shutdown(data, data->state.async);
|
|
#endif
|
|
#ifndef CURL_DISABLE_DOH
|
|
Curl_doh_cleanup(data, data->state.async);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Curl_async_destroy(struct Curl_easy *data)
|
|
{
|
|
if(data->state.async) {
|
|
CURL_TRC_DNS(data, "destroy async");
|
|
#ifdef USE_RESOLV_ARES
|
|
Curl_async_ares_destroy(data, data->state.async);
|
|
#endif
|
|
#ifdef USE_RESOLV_THREADED
|
|
Curl_async_thrdd_destroy(data, data->state.async);
|
|
#endif
|
|
#ifndef CURL_DISABLE_DOH
|
|
Curl_doh_cleanup(data, data->state.async);
|
|
#endif
|
|
Curl_safefree(data->state.async);
|
|
}
|
|
}
|
|
|
|
#endif /* USE_CURL_ASYNC */
|