• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Client Connection Latency and DNS reporting
25  */
26 
27 /*
28  * We want to allocate copies for and append DNS results that we don't already
29  * have.  We take this approach because a) we may be getting duplicated results
30  * from multiple DNS servers, and b) we may be getting results stacatto over
31  * time.
32  *
33  * We capture DNS results from either getaddrinfo or ASYNC_DNS the same here,
34  * before they are sorted and filtered.
35  *
36  * Because this is relatively expensive, we only do it on client wsi that
37  * explicitly indicated that they want it with the LCCSCF_CONMON flag.
38  */
39 
40 #include <private-lib-core.h>
41 
42 int
lws_conmon_append_copy_new_dns_results(struct lws * wsi,const struct addrinfo * cai)43 lws_conmon_append_copy_new_dns_results(struct lws *wsi,
44 				       const struct addrinfo *cai)
45 {
46 	if (!(wsi->flags & LCCSCF_CONMON))
47 		return 0;
48 
49 	/*
50 	 * Let's go through the incoming guys, seeing if we already have them,
51 	 * or if we want to take a copy
52 	 */
53 
54 	while (cai) {
55 		struct addrinfo *ai = wsi->conmon.dns_results_copy;
56 		char skip = 0;
57 
58 		/* do we already have this guy? */
59 
60 		while (ai) {
61 
62 			if (ai->ai_family != cai->ai_family &&
63 			    ai->ai_addrlen != cai->ai_addrlen &&
64 			    ai->ai_protocol != cai->ai_protocol &&
65 			    ai->ai_socktype != cai->ai_socktype &&
66 			    /* either ipv4 or v6 address must match */
67 			    ((ai->ai_family == AF_INET &&
68 			      ((struct sockaddr_in *)ai->ai_addr)->
69 							     sin_addr.s_addr ==
70 			      ((struct sockaddr_in *)cai->ai_addr)->
71 							     sin_addr.s_addr)
72 #if defined(LWS_WITH_IPV6)
73 					    ||
74 			    (ai->ai_family == AF_INET6 &&
75 			     !memcmp(((struct sockaddr_in6 *)ai->ai_addr)->
76 							     sin6_addr.s6_addr,
77 				     ((struct sockaddr_in6 *)cai->ai_addr)->
78 						     sin6_addr.s6_addr, 16))
79 #endif
80 			    )) {
81 				/* yes, we already got a copy then */
82 				skip = 1;
83 				break;
84 			}
85 
86 			ai = ai->ai_next;
87 		}
88 
89 		if (!skip) {
90 			/*
91 			 * No we don't already have a copy of this one, let's
92 			 * allocate and append it then
93 			 */
94 			size_t al = sizeof(struct addrinfo) +
95 				    (size_t)cai->ai_addrlen;
96 			size_t cl = cai->ai_canonname ?
97 					strlen(cai->ai_canonname) + 1 : 0;
98 
99 			ai = lws_malloc(al + cl + 1, __func__);
100 			if (!ai) {
101 				lwsl_wsi_warn(wsi, "OOM");
102 				return 1;
103 			}
104 			*ai = *cai;
105 			ai->ai_addr = (struct sockaddr *)&ai[1];
106 			memcpy(ai->ai_addr, cai->ai_addr, (size_t)cai->ai_addrlen);
107 
108 			if (cl) {
109 				ai->ai_canonname = ((char *)ai->ai_addr) +
110 							cai->ai_addrlen;
111 				memcpy(ai->ai_canonname, cai->ai_canonname,
112 				       cl + 1);
113 			}
114 			ai->ai_next = wsi->conmon.dns_results_copy;
115 			wsi->conmon.dns_results_copy = ai;
116 		}
117 
118 		cai = cai->ai_next;
119 	}
120 
121 	return 0;
122 }
123 
124 void
lws_conmon_addrinfo_destroy(struct addrinfo * ai)125 lws_conmon_addrinfo_destroy(struct addrinfo *ai)
126 {
127 	while (ai) {
128 		struct addrinfo *ai1 = ai->ai_next;
129 
130 		lws_free(ai);
131 		ai = ai1;
132 	}
133 }
134 
135 void
lws_conmon_wsi_take(struct lws * wsi,struct lws_conmon * dest)136 lws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest)
137 {
138 	memcpy(dest, &wsi->conmon, sizeof(*dest));
139 	dest->peer46 = wsi->sa46_peer;
140 
141 	/* wsi no longer has to free it... */
142 	wsi->conmon.dns_results_copy = NULL;
143 	wsi->perf_done = 1;
144 }
145 
146 void
lws_conmon_release(struct lws_conmon * conmon)147 lws_conmon_release(struct lws_conmon *conmon)
148 {
149 	if (!conmon)
150 		return;
151 
152 	lws_conmon_addrinfo_destroy(conmon->dns_results_copy);
153 	conmon->dns_results_copy = NULL;
154 }
155