android13/external/libwebsockets/lib/core-net/client/conmon.c

155 lines
4.3 KiB
C

/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Client Connection Latency and DNS reporting
*/
/*
* We want to allocate copies for and append DNS results that we don't already
* have. We take this approach because a) we may be getting duplicated results
* from multiple DNS servers, and b) we may be getting results stacatto over
* time.
*
* We capture DNS results from either getaddrinfo or ASYNC_DNS the same here,
* before they are sorted and filtered.
*
* Because this is relatively expensive, we only do it on client wsi that
* explicitly indicated that they want it with the LCCSCF_CONMON flag.
*/
#include <private-lib-core.h>
int
lws_conmon_append_copy_new_dns_results(struct lws *wsi,
const struct addrinfo *cai)
{
if (!(wsi->flags & LCCSCF_CONMON))
return 0;
/*
* Let's go through the incoming guys, seeing if we already have them,
* or if we want to take a copy
*/
while (cai) {
struct addrinfo *ai = wsi->conmon.dns_results_copy;
char skip = 0;
/* do we already have this guy? */
while (ai) {
if (ai->ai_family != cai->ai_family &&
ai->ai_addrlen != cai->ai_addrlen &&
ai->ai_protocol != cai->ai_protocol &&
ai->ai_socktype != cai->ai_socktype &&
/* either ipv4 or v6 address must match */
((ai->ai_family == AF_INET &&
((struct sockaddr_in *)ai->ai_addr)->
sin_addr.s_addr ==
((struct sockaddr_in *)cai->ai_addr)->
sin_addr.s_addr)
#if defined(LWS_WITH_IPV6)
||
(ai->ai_family == AF_INET6 &&
!memcmp(((struct sockaddr_in6 *)ai->ai_addr)->
sin6_addr.s6_addr,
((struct sockaddr_in6 *)cai->ai_addr)->
sin6_addr.s6_addr, 16))
#endif
)) {
/* yes, we already got a copy then */
skip = 1;
break;
}
ai = ai->ai_next;
}
if (!skip) {
/*
* No we don't already have a copy of this one, let's
* allocate and append it then
*/
size_t al = sizeof(struct addrinfo) +
(size_t)cai->ai_addrlen;
size_t cl = cai->ai_canonname ?
strlen(cai->ai_canonname) + 1 : 0;
ai = lws_malloc(al + cl + 1, __func__);
if (!ai) {
lwsl_wsi_warn(wsi, "OOM");
return 1;
}
*ai = *cai;
ai->ai_addr = (struct sockaddr *)&ai[1];
memcpy(ai->ai_addr, cai->ai_addr, (size_t)cai->ai_addrlen);
if (cl) {
ai->ai_canonname = ((char *)ai->ai_addr) +
cai->ai_addrlen;
memcpy(ai->ai_canonname, cai->ai_canonname,
cl + 1);
}
ai->ai_next = wsi->conmon.dns_results_copy;
wsi->conmon.dns_results_copy = ai;
}
cai = cai->ai_next;
}
return 0;
}
void
lws_conmon_addrinfo_destroy(struct addrinfo *ai)
{
while (ai) {
struct addrinfo *ai1 = ai->ai_next;
lws_free(ai);
ai = ai1;
}
}
void
lws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest)
{
memcpy(dest, &wsi->conmon, sizeof(*dest));
dest->peer46 = wsi->sa46_peer;
/* wsi no longer has to free it... */
wsi->conmon.dns_results_copy = NULL;
wsi->perf_done = 1;
}
void
lws_conmon_release(struct lws_conmon *conmon)
{
if (!conmon)
return;
lws_conmon_addrinfo_destroy(conmon->dns_results_copy);
conmon->dns_results_copy = NULL;
}