]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Metrics.m
mDNSResponder-878.30.4.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Metrics.m
1 /*
2 * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #import "Metrics.h"
18
19 #if (TARGET_OS_IOS)
20 #import <CoreUtils/SoftLinking.h>
21 #import <WirelessDiagnostics/AWDDNSDomainStats.h>
22 #import <WirelessDiagnostics/AWDMDNSResponderDNSMessageSizeStats.h>
23 #import <WirelessDiagnostics/AWDMDNSResponderDNSStatistics.h>
24 #import <WirelessDiagnostics/AWDMDNSResponderResolveStats.h>
25 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDNSServer.h>
26 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDomain.h>
27 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsHostname.h>
28 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsResult.h>
29 #import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
30 #import <WirelessDiagnostics/AWDMetricIds_MDNSResponder.h>
31 #import <WirelessDiagnostics/WirelessDiagnostics.h>
32
33 #import "DNSCommon.h"
34 #import "mDNSMacOSX.h"
35 #import "DebugServices.h"
36
37 //===========================================================================================================================
38 // External Frameworks
39 //===========================================================================================================================
40
41 SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics)
42
43 // AWDServerConnection class
44
45 SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection)
46
47 #define AWDServerConnectionSoft getAWDServerConnectionClass()
48
49 // Classes for query stats
50
51 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics)
52 SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
53
54 #define AWDMDNSResponderDNSStatisticsSoft getAWDMDNSResponderDNSStatisticsClass()
55 #define AWDDNSDomainStatsSoft getAWDDNSDomainStatsClass()
56
57 // Classes for resolve stats
58
59 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats)
60 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer)
61 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain)
62 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname)
63 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult)
64
65 #define AWDMDNSResponderResolveStatsSoft getAWDMDNSResponderResolveStatsClass()
66 #define AWDMDNSResponderResolveStatsDNSServerSoft getAWDMDNSResponderResolveStatsDNSServerClass()
67 #define AWDMDNSResponderResolveStatsDomainSoft getAWDMDNSResponderResolveStatsDomainClass()
68 #define AWDMDNSResponderResolveStatsHostnameSoft getAWDMDNSResponderResolveStatsHostnameClass()
69 #define AWDMDNSResponderResolveStatsResultSoft getAWDMDNSResponderResolveStatsResultClass()
70
71 // Classes for services stats
72
73 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
74
75 #define AWDMetricManagerSoft getAWDMetricManagerClass()
76
77 // Classes for DNS message size stats
78
79 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSMessageSizeStats)
80
81 #define AWDMDNSResponderDNSMessageSizeStatsSoft getAWDMDNSResponderDNSMessageSizeStatsClass()
82
83 //===========================================================================================================================
84 // Macros
85 //===========================================================================================================================
86
87 #define countof(X) (sizeof(X) / sizeof(X[0]))
88 #define countof_field(TYPE, FIELD) countof(((TYPE *)0)->FIELD)
89 #define increment_saturate(VAR, MAX) do {if ((VAR) < (MAX)) {++(VAR);}} while (0)
90 #define ForgetMem(X) do {if(*(X)) {free(*(X)); *(X) = NULL;}} while(0)
91
92 //===========================================================================================================================
93 // Constants
94 //===========================================================================================================================
95
96 #define kQueryStatsMaxQuerySendCount 10
97 #define kQueryStatsSendCountBinCount (kQueryStatsMaxQuerySendCount + 1)
98 #define kQueryStatsLatencyBinCount 55
99 #define kResolveStatsMaxObjCount 2000
100
101 //===========================================================================================================================
102 // Data structures
103 //===========================================================================================================================
104
105 // Data structures for query stats.
106
107 typedef struct QueryStats QueryStats;
108 typedef struct DNSHistSet DNSHistSet;
109 typedef mDNSBool (*QueryNameTest_f)(const QueryStats *inStats, const domainname *inQueryName);
110
111 struct QueryStats
112 {
113 QueryStats * next; // Pointer to next domain stats in list.
114 const char * domainStr; // Domain (see below) as a C string.
115 uint8_t * domain; // Domain for which these stats are collected.
116 const char * altDomainStr; // Alt domain string to use in the AWD version of the stats instead of domainStr.
117 DNSHistSet * nonCellular; // Query stats for queries sent over non-cellular interfaces.
118 DNSHistSet * cellular; // Query stats for queries sent over cellular interfaces.
119 QueryNameTest_f test; // Function that tests whether a given query's stats belong based on the query name.
120 int labelCount; // Number of labels in domain name. Used for domain name comparisons.
121 mDNSBool terminal; // If true and test passes, then no other QueryStats on the list should be visited.
122 };
123
124 check_compile_time(sizeof(QueryStats) <= 64);
125
126 // DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
127 // <rdar://problem/23980546> MDNSResponder.proto update.
128 //
129 // answeredQuerySendCountBins
130 //
131 // An array of 11 histogram bins. The value at index i, for 0 <= i <= 9, is the number of times that an answered DNS query
132 // was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times.
133 //
134 // unansweredQuerySendCountBins
135 //
136 // An array of 11 histogram bins. The value at index i, for 0 <= i <= 9, is the number of times that an unanswered DNS query
137 // was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times.
138 //
139 // responseLatencyBins
140 //
141 // An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time
142 // interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are
143 // in milliseconds): 1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
144 // 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
145 // 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞.
146
147 typedef struct
148 {
149 uint16_t unansweredQuerySendCountBins[kQueryStatsSendCountBinCount];
150 uint16_t unansweredQueryDurationBins[kQueryStatsLatencyBinCount];
151 uint16_t answeredQuerySendCountBins[kQueryStatsSendCountBinCount];
152 uint16_t responseLatencyBins[kQueryStatsLatencyBinCount];
153 uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
154 uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount];
155
156 } DNSHist;
157
158 check_compile_time(sizeof(DNSHist) <= 512);
159 check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
160 check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
161 check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
162
163 // Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
164 // latency histogram bins to observe these time interval upper bounds.
165
166 static const mDNSu32 kResponseLatencyMsLimits[] =
167 {
168 1, 2, 3, 4, 5,
169 10, 20, 30, 40, 50, 60, 70, 80, 90,
170 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
171 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
172 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
173 5000, 6000, 7000, 8000, 9000,
174 10000
175 };
176
177 check_compile_time(countof(kResponseLatencyMsLimits) == 54);
178 check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1));
179 check_compile_time(countof_field(DNSHist, responseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
180 check_compile_time(countof_field(DNSHist, negResponseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
181
182 struct DNSHistSet
183 {
184 DNSHist * histA; // Histogram data for queries for A resource records.
185 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
186 };
187
188 typedef struct
189 {
190 const char * domainStr;
191 const char * altDomainStr;
192 QueryNameTest_f test;
193 mDNSBool terminal;
194
195 } QueryStatsArgs;
196
197 // Data structures for resolve stats.
198
199 static const char * const kResolveStatsDomains[] =
200 {
201 "apple.com.",
202 "icloud.com.",
203 "mzstatic.com.",
204 "me.com."
205 };
206
207 check_compile_time(countof(kResolveStatsDomains) == 4);
208
209 typedef struct ResolveStatsDomain ResolveStatsDomain;
210 typedef struct ResolveStatsHostname ResolveStatsHostname;
211 typedef struct ResolveStatsDNSServer ResolveStatsDNSServer;
212 typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet;
213 typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr;
214 typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet;
215
216 struct ResolveStatsDomain
217 {
218 ResolveStatsDomain * next; // Next domain object in list.
219 const char * domainStr;
220 uint8_t * domain; // Domain for which these stats are collected.
221 int labelCount; // Number of labels in domain name. Used for domain name comparisons.
222 ResolveStatsHostname * hostnameList; // List of hostname objects in this domain.
223 };
224
225 check_compile_time(sizeof(ResolveStatsDomain) <= 40);
226
227 struct ResolveStatsHostname
228 {
229 ResolveStatsHostname * next; // Next hostname object in list.
230 ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved.
231 ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved.
232 ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects.
233 uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels.
234 };
235
236 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
237
238 struct ResolveStatsDNSServer
239 {
240 ResolveStatsDNSServer * next; // Next DNS server object in list.
241 uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects.
242 mDNSBool isForCell; // True if this DNS server belongs to a cellular interface.
243 mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4.
244 uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address.
245 };
246
247 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
248
249 typedef struct
250 {
251 uint16_t count; // Number of times this IPv4 address was provided as a resolution result.
252 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came.
253 uint8_t isNegative;
254 uint8_t addrBytes[4]; // IPv4 address bytes.
255
256 } IPv4AddrCounter;
257
258 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
259
260 struct ResolveStatsIPv4AddrSet
261 {
262 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
263 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
264 };
265
266 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
267
268 struct ResolveStatsIPv6Addr
269 {
270 ResolveStatsIPv6Addr * next; // Next IPv6 address object in list.
271 uint16_t count; // Number of times this IPv6 address was provided as a resolution result.
272 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came.
273 uint8_t addrBytes[16]; // IPv6 address bytes.
274 };
275
276 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
277
278 typedef struct
279 {
280 uint16_t count; // Number of times that a negative response was returned by a DNS server.
281 uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses.
282
283 } NegAAAACounter;
284
285 check_compile_time(sizeof(NegAAAACounter) <= 4);
286
287 struct ResolveStatsNegAAAASet
288 {
289 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
290 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
291 };
292
293 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
294
295 typedef enum
296 {
297 kResponseType_IPv4Addr = 1,
298 kResponseType_IPv6Addr = 2,
299 kResponseType_NegA = 3,
300 kResponseType_NegAAAA = 4
301
302 } ResponseType;
303
304 typedef struct
305 {
306 ResponseType type;
307 const uint8_t * data;
308
309 } Response;
310
311 // Data structures for DNS message size stats.
312
313 #define kQuerySizeBinWidth 16
314 #define kQuerySizeBinMax 512
315 #define kQuerySizeBinCount ((kQuerySizeBinMax / kQuerySizeBinWidth) + 1)
316
317 check_compile_time(kQuerySizeBinWidth > 0);
318 check_compile_time(kQuerySizeBinCount > 0);
319 check_compile_time((kQuerySizeBinMax % kQuerySizeBinWidth) == 0);
320
321 #define kResponseSizeBinWidth 16
322 #define kResponseSizeBinMax 512
323 #define kResponseSizeBinCount ((kResponseSizeBinMax / kResponseSizeBinWidth) + 1)
324
325 check_compile_time(kResponseSizeBinWidth > 0);
326 check_compile_time(kResponseSizeBinCount > 0);
327 check_compile_time((kResponseSizeBinMax % kResponseSizeBinWidth) == 0);
328
329 typedef struct
330 {
331 uint16_t querySizeBins[kQuerySizeBinCount];
332 uint16_t responseSizeBins[kResponseSizeBinCount];
333
334 } DNSMessageSizeStats;
335
336 check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
337
338 //===========================================================================================================================
339 // Local Prototypes
340 //===========================================================================================================================
341
342 // Query stats
343
344 mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats);
345 mDNSlocal void QueryStatsFree(QueryStats *inStats);
346 mDNSlocal void QueryStatsFreeList(QueryStats *inList);
347 mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
348 mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats);
349 mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName);
350 mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName);
351 mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName);
352 mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName);
353
354 // Resolve stats
355
356 mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain);
357 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
358 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
359 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
360
361 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
362 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
363 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
364 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
365
366 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
367 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
368 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
369
370 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
371 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
372
373 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
374 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
375
376 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
377 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
378 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
379
380 // DNS message size stats
381
382 mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
383 mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
384
385 mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList);
386 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList);
387 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList);
388 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
389 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID);
390 mDNSlocal mStatus SubmitAWDMetricQueryStats(void);
391 mDNSlocal mStatus SubmitAWDMetricResolveStats(void);
392 mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void);
393 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
394 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
395 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
396 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
397 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
398 mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth);
399
400 mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
401
402 //===========================================================================================================================
403 // Globals
404 //===========================================================================================================================
405
406 static AWDServerConnection * gAWDServerConnection = nil;
407 static QueryStats * gQueryStatsList = NULL;
408 static ResolveStatsDomain * gResolveStatsList = NULL;
409 static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
410 static unsigned int gResolveStatsNextServerID = 0;
411 static int gResolveStatsObjCount = 0;
412 static DNSMessageSizeStats * gDNSMessageSizeStats = NULL;
413
414 // Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
415
416 static const QueryStatsArgs kQueryStatsArgs[] =
417 {
418 { ".", NULL, QueryStatsDomainTest, mDNSfalse },
419 { "", "alt:*-courier.push.apple.com.", QueryStatsCourierPushTest, mDNSfalse },
420 { "apple.com.", NULL, QueryStatsDomainTest, mDNStrue },
421 { "gateway.icloud.com.", "alt:gateway.icloud.com", QueryStatsHostnameTest, mDNSfalse },
422 { "", "alt:*-content.icloud.com.", QueryStatsContentiCloudTest, mDNSfalse },
423 { "icloud.com.", NULL, QueryStatsDomainTest, mDNStrue },
424 { "mzstatic.com.", NULL, QueryStatsDomainTest, mDNStrue },
425 { "google.com.", NULL, QueryStatsDomainTest, mDNStrue },
426 { "baidu.com.", NULL, QueryStatsDomainTest, mDNStrue },
427 { "yahoo.com.", NULL, QueryStatsDomainTest, mDNStrue },
428 { "qq.com.", NULL, QueryStatsDomainTest, mDNStrue }
429 };
430
431 check_compile_time(countof(kQueryStatsArgs) == 11);
432
433 //===========================================================================================================================
434 // MetricsInit
435 //===========================================================================================================================
436
437 mStatus MetricsInit(void)
438 {
439 @autoreleasepool
440 {
441 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
442 initWithComponentId: AWDComponentId_MDNSResponder
443 andBlockOnConfiguration: NO];
444
445 if (gAWDServerConnection)
446 {
447 [gAWDServerConnection
448 registerQueriableMetricCallback: ^(UInt32 inMetricID)
449 {
450 SubmitAWDMetric(inMetricID);
451 }
452 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
453
454 [gAWDServerConnection
455 registerQueriableMetricCallback: ^(UInt32 inMetricID)
456 {
457 SubmitAWDMetric(inMetricID);
458 }
459 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
460
461 [gAWDServerConnection
462 registerQueriableMetricCallback: ^(UInt32 inMetricID)
463 {
464 SubmitAWDMetric(inMetricID);
465 }
466 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
467
468 [gAWDServerConnection
469 registerQueriableMetricCallback: ^(UInt32 inMetricID)
470 {
471 SubmitAWDMetric(inMetricID);
472 }
473 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSMessageSizeStats];
474 }
475 else
476 {
477 LogMsg("MetricsInit: failed to create AWD server connection.");
478 }
479 }
480
481 if( gAWDServerConnection )
482 {
483 CreateQueryStatsList(&gQueryStatsList);
484 CreateResolveStatsList(&gResolveStatsList);
485 DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
486 }
487
488 return (mStatus_NoError);
489 }
490
491 //===========================================================================================================================
492 // MetricsUpdateDNSQueryStats
493 //===========================================================================================================================
494
495 mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
496 {
497 QueryStats * stats;
498 mDNSBool match;
499
500 require_quiet(gAWDServerConnection, exit);
501 require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
502
503 for (stats = gQueryStatsList; stats; stats = stats->next)
504 {
505 match = stats->test(stats, inQueryName);
506 if (match)
507 {
508 QueryStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
509 if (stats->terminal) break;
510 }
511 }
512
513 exit:
514 return;
515 }
516
517 //===========================================================================================================================
518 // MetricsUpdateDNSResolveStats
519 //===========================================================================================================================
520
521 mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
522 {
523 ResolveStatsDomain * domainStats;
524 domainname hostname;
525 size_t hostnameLen;
526 mDNSBool isQueryInDomain;
527 int skipCount;
528 int skipCountLast = -1;
529 int queryLabelCount;
530 const domainname * queryParentDomain;
531 Response response;
532
533 require_quiet(gAWDServerConnection, exit);
534 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
535 require_quiet(inRR->rDNSServer, exit);
536
537 queryLabelCount = CountLabels(inQueryName);
538
539 for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
540 {
541 isQueryInDomain = mDNSfalse;
542 skipCount = queryLabelCount - domainStats->labelCount;
543 if (skipCount >= 0)
544 {
545 if (skipCount != skipCountLast)
546 {
547 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
548 skipCountLast = skipCount;
549 }
550 isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
551 }
552 if (!isQueryInDomain) continue;
553
554 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
555 if (hostnameLen >= sizeof(hostname.c)) continue;
556
557 memcpy(hostname.c, inQueryName->c, hostnameLen);
558 hostname.c[hostnameLen] = 0;
559
560 if (inRR->RecordType == kDNSRecordTypePacketNegative)
561 {
562 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
563 response.data = NULL;
564 }
565 else
566 {
567 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
568 response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
569 }
570 ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
571 }
572
573 exit:
574 return;
575 }
576
577 //===========================================================================================================================
578 // MetricsUpdateDNSQuerySize
579 //===========================================================================================================================
580
581 mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
582
583 mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
584 {
585 if (!gDNSMessageSizeStats) return;
586 UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
587 }
588
589 mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
590 {
591 size_t i;
592
593 if (inSize == 0) return;
594 i = (inSize - 1) / inBinWidth;
595 if (i >= inBinCount) i = inBinCount - 1;
596 increment_saturate(inBins[i], UINT16_MAX);
597 }
598
599 //===========================================================================================================================
600 // MetricsUpdateDNSResponseSize
601 //===========================================================================================================================
602
603 mDNSexport void MetricsUpdateDNSResponseSize(mDNSu32 inSize)
604 {
605 if (!gDNSMessageSizeStats) return;
606 UpdateMessageSizeCounts(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth, inSize);
607 }
608
609 //===========================================================================================================================
610 // LogMetrics
611 //===========================================================================================================================
612
613 mDNSexport void LogMetrics(void)
614 {
615 QueryStats * stats;
616 const ResolveStatsDomain * domain;
617 const ResolveStatsHostname * hostname;
618 const ResolveStatsDNSServer * server;
619 const ResolveStatsIPv4AddrSet * addrV4;
620 const ResolveStatsIPv6Addr * addrV6;
621 const ResolveStatsNegAAAASet * negV6;
622 int hostnameCount;
623 int i;
624 unsigned int serverID;
625 int serverObjCount = 0;
626 int hostnameObjCount = 0;
627 int addrObjCount = 0;
628
629 LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
630 LogMsgNoIdent("---- DNS query stats by domain -----");
631
632 for (stats = gQueryStatsList; stats; stats = stats->next)
633 {
634 if (!stats->nonCellular && !stats->cellular)
635 {
636 LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
637 continue;
638 }
639 if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
640 if (stats->cellular) LogDNSHistSet(stats->cellular, QueryStatsGetDomainString(stats), mDNStrue);
641 }
642
643 LogMsgNoIdent("---- DNS resolve stats by domain -----");
644
645 LogMsgNoIdent("Servers:");
646 for (server = gResolveStatsServerList; server; server = server->next)
647 {
648 serverObjCount++;
649 LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
650 server->id, server->isForCell ? " C" : "NC", server->addrBytes);
651 }
652
653 for (domain = gResolveStatsList; domain; domain = domain->next)
654 {
655 hostnameCount = 0;
656 for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
657 hostnameObjCount += hostnameCount;
658
659 LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
660
661 for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
662 {
663 LogMsgNoIdent(" %##s", hostname->name);
664 for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
665 {
666 for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
667 {
668 if (serverID == 0) addrObjCount++;
669 for (i = 0; i < (int)countof(addrV4->counters); ++i)
670 {
671 const IPv4AddrCounter * counter;
672
673 counter = &addrV4->counters[i];
674 if (counter->count == 0) break;
675 if (counter->serverID == serverID)
676 {
677 if (counter->isNegative)
678 {
679 LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
680 }
681 else
682 {
683 LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
684 }
685 }
686 }
687 }
688 for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
689 {
690 if (serverID == 0) addrObjCount++;
691 if (addrV6->serverID == serverID)
692 {
693 LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
694 }
695 }
696 for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
697 {
698 if (serverID == 0) addrObjCount++;
699 for (i = 0; i < (int)countof(negV6->counters); ++i)
700 {
701 const NegAAAACounter * counter;
702
703 counter = &negV6->counters[i];
704 if (counter->count == 0) break;
705 if (counter->serverID == serverID)
706 {
707 LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
708 }
709 }
710 }
711 }
712 }
713 }
714 LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
715 serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
716
717 LogMsgNoIdent("---- Num of Services Registered -----");
718 LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
719 curr_num_regservices, max_num_regservices);
720
721 if (gDNSMessageSizeStats)
722 {
723 LogMsgNoIdent("---- DNS query size stats ---");
724 LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
725
726 LogMsgNoIdent("-- DNS response size stats --");
727 LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
728 }
729 else
730 {
731 LogMsgNoIdent("No DNS message size stats.");
732 }
733 }
734
735 //===========================================================================================================================
736 // QueryStatsCreate
737 //===========================================================================================================================
738
739 mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName);
740
741 mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats)
742 {
743 mStatus err;
744 QueryStats * obj;
745
746 obj = (QueryStats *)calloc(1, sizeof(*obj));
747 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
748
749 obj->domainStr = inDomainStr;
750 err = StringToDomainName(obj->domainStr, &obj->domain);
751 require_noerr_quiet(err, exit);
752
753 obj->altDomainStr = inAltDomainStr;
754 obj->test = inTest;
755 obj->labelCount = CountLabels((const domainname *)obj->domain);
756 obj->terminal = inTerminal;
757
758 *outStats = obj;
759 obj = NULL;
760 err = mStatus_NoError;
761
762 exit:
763 if (obj) QueryStatsFree(obj);
764 return (err);
765 }
766
767 mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName)
768 {
769 mStatus err;
770 uint8_t * domainPtr = NULL;
771 size_t domainLen;
772 const mDNSu8 * ptr;
773 domainname domain;
774
775 if (strcmp(inString, ".") == 0)
776 {
777 domain.c[0] = 0;
778 }
779 else
780 {
781 ptr = MakeDomainNameFromDNSNameString(&domain, inString);
782 require_action_quiet(ptr, exit, err = mStatus_BadParamErr);
783 }
784 domainLen = DomainNameLength(&domain);
785
786 domainPtr = (uint8_t *)malloc(domainLen);
787 require_action_quiet(domainPtr, exit, err = mStatus_NoMemoryErr);
788
789 memcpy(domainPtr, domain.c, domainLen);
790
791 *outDomainName = domainPtr;
792 domainPtr = NULL;
793 err = mStatus_NoError;
794
795 exit:
796 return(err);
797 }
798
799 //===========================================================================================================================
800 // QueryStatsFree
801 //===========================================================================================================================
802
803 mDNSlocal void QueryStatsFree(QueryStats *inStats)
804 {
805 ForgetMem(&inStats->domain);
806 if (inStats->nonCellular)
807 {
808 ForgetMem(&inStats->nonCellular->histA);
809 ForgetMem(&inStats->nonCellular->histAAAA);
810 free(inStats->nonCellular);
811 inStats->nonCellular = NULL;
812 }
813 if (inStats->cellular)
814 {
815 ForgetMem(&inStats->cellular->histA);
816 ForgetMem(&inStats->cellular->histAAAA);
817 free(inStats->cellular);
818 inStats->cellular = NULL;
819 }
820 free(inStats);
821 }
822
823 //===========================================================================================================================
824 // QueryStatsFreeList
825 //===========================================================================================================================
826
827 mDNSlocal void QueryStatsFreeList(QueryStats *inList)
828 {
829 QueryStats * stats;
830
831 while ((stats = inList) != NULL)
832 {
833 inList = stats->next;
834 QueryStatsFree(stats);
835 }
836 }
837
838 //===========================================================================================================================
839 // QueryStatsUpdate
840 //===========================================================================================================================
841
842 mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
843 {
844 mStatus err;
845 DNSHistSet * set;
846 DNSHistSet ** pSet;
847 DNSHist * hist;
848 DNSHist ** pHist;
849 int i;
850
851 require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError);
852 require_action_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit, err = mStatus_NoError);
853
854 pSet = inForCell ? &inStats->cellular : &inStats->nonCellular;
855 if ((set = *pSet) == NULL)
856 {
857 set = (DNSHistSet *)calloc(1, sizeof(*set));
858 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
859 *pSet = set;
860 }
861 pHist = (inType == kDNSType_A) ? &set->histA : &set->histAAAA;
862 if ((hist = *pHist) == NULL)
863 {
864 hist = (DNSHist *)calloc(1, sizeof(*hist));
865 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
866 *pHist = hist;
867 }
868
869 if (inRR)
870 {
871 uint16_t * sendCountBins;
872 uint16_t * latencyBins;
873 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
874
875 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
876
877 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
878 increment_saturate(sendCountBins[i], UINT16_MAX);
879
880 if (inQuerySendCount > 0)
881 {
882 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
883 latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
884 increment_saturate(latencyBins[i], UINT16_MAX);
885 }
886 }
887 else
888 {
889 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
890 increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
891
892 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
893 increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
894 }
895 err = mStatus_NoError;
896
897 exit:
898 return (err);
899 }
900
901 //===========================================================================================================================
902 // QueryStatsGetDomainString
903 //===========================================================================================================================
904
905 mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats)
906 {
907 return (inStats->altDomainStr ? inStats->altDomainStr : inStats->domainStr);
908 }
909
910 //===========================================================================================================================
911 // QueryStatsDomainTest
912 //===========================================================================================================================
913
914 mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName)
915 {
916 const domainname * parentDomain;
917 int labelCount;
918
919 if (inStats->domain[0] == 0) return (mDNStrue);
920
921 labelCount = CountLabels(inQueryName);
922 if (labelCount < inStats->labelCount) return (mDNSfalse);
923
924 parentDomain = SkipLeadingLabels(inQueryName, labelCount - inStats->labelCount);
925 return (SameDomainName(parentDomain, (const domainname *)inStats->domain));
926 }
927
928 //===========================================================================================================================
929 // QueryStatsHostnameTest
930 //===========================================================================================================================
931
932 mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName)
933 {
934 return (SameDomainName(inQueryName, (const domainname *)inStats->domain));
935 }
936
937 //===========================================================================================================================
938 // QueryStatsContentiCloudTest
939 //===========================================================================================================================
940
941 mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen);
942
943 #define kContentSuffixStr "-content"
944
945 mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName)
946 {
947 const mDNSu8 * const firstLabel = inQueryName->c;
948 const uint8_t * suffix;
949 const domainname * parentDomain;
950 int labelCount;
951
952 (void) inStats; // Unused.
953
954 labelCount = CountLabels(inQueryName);
955 if (labelCount != 3) return (mDNSfalse);
956
957 suffix = LocateLabelSuffix(firstLabel, (const uint8_t *)kContentSuffixStr, sizeof_string(kContentSuffixStr));
958 if (suffix && (suffix > &firstLabel[1]))
959 {
960 parentDomain = SkipLeadingLabels(inQueryName, 1);
961 if (SameDomainName(parentDomain, (const domainname *)"\x6" "icloud" "\x3" "com"))
962 {
963 return (mDNStrue);
964 }
965 }
966
967 return (mDNSfalse);
968 }
969
970 mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen)
971 {
972 const uint8_t * ptr;
973 const uint8_t * lp;
974 const uint8_t * sp;
975 size_t len;
976 const size_t labelLen = inLabel[0];
977
978 if (labelLen < inSuffixLen) return (NULL);
979
980 ptr = &inLabel[1 + labelLen - inSuffixLen];
981 lp = ptr;
982 sp = inSuffixPtr;
983 for (len = inSuffixLen; len > 0; --len)
984 {
985 if (tolower(*lp) != tolower(*sp)) return (NULL);
986 ++lp;
987 ++sp;
988 }
989
990 return (ptr);
991 }
992
993 //===========================================================================================================================
994 // QueryStatsCourierPushTest
995 //===========================================================================================================================
996
997 #define kCourierSuffixStr "-courier"
998
999 mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName)
1000 {
1001 const mDNSu8 * const firstLabel = inQueryName->c;
1002 const uint8_t * suffix;
1003 const uint8_t * ptr;
1004 const domainname * parentDomain;
1005 int labelCount;
1006
1007 (void) inStats; // Unused.
1008
1009 labelCount = CountLabels(inQueryName);
1010 if (labelCount != 4) return (mDNSfalse);
1011
1012 suffix = LocateLabelSuffix(firstLabel, (const mDNSu8 *)kCourierSuffixStr, sizeof_string(kCourierSuffixStr));
1013 if (suffix && (suffix > &firstLabel[1]))
1014 {
1015 for (ptr = &firstLabel[1]; ptr < suffix; ++ptr)
1016 {
1017 if (!isdigit(*ptr)) break;
1018 }
1019 if (ptr == suffix)
1020 {
1021 parentDomain = SkipLeadingLabels(inQueryName, 1);
1022 if (SameDomainName(parentDomain, (const domainname *)"\x4" "push" "\x5" "apple" "\x3" "com"))
1023 {
1024 return (mDNStrue);
1025 }
1026 }
1027 }
1028
1029 return (mDNSfalse);
1030 }
1031
1032 //===========================================================================================================================
1033 // ResolveStatsDomainCreate
1034 //===========================================================================================================================
1035
1036 mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
1037 {
1038 mStatus err;
1039 ResolveStatsDomain * obj;
1040
1041 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
1042 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1043
1044 obj->domainStr = inDomainStr;
1045 err = StringToDomainName(obj->domainStr, &obj->domain);
1046 require_noerr_quiet(err, exit);
1047
1048 obj->labelCount = CountLabels((const domainname *)obj->domain);
1049
1050 *outDomain = obj;
1051 obj = NULL;
1052 err = mStatus_NoError;
1053
1054 exit:
1055 if (obj) ResolveStatsDomainFree(obj);
1056 return (err);
1057 }
1058
1059 //===========================================================================================================================
1060 // ResolveStatsDomainFree
1061 //===========================================================================================================================
1062
1063 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
1064 {
1065 ResolveStatsHostname * hostname;
1066
1067 ForgetMem(&inDomain->domain);
1068 while ((hostname = inDomain->hostnameList) != NULL)
1069 {
1070 inDomain->hostnameList = hostname->next;
1071 ResolveStatsHostnameFree(hostname);
1072 }
1073 free(inDomain);
1074 }
1075
1076 //===========================================================================================================================
1077 // ResolveStatsDomainUpdate
1078 //===========================================================================================================================
1079
1080 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
1081 {
1082 mStatus err;
1083 ResolveStatsHostname ** p;
1084 ResolveStatsHostname * hostname;
1085 uint8_t serverID;
1086
1087 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
1088 {
1089 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
1090 }
1091
1092 if (!hostname)
1093 {
1094 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1095 err = ResolveStatsHostnameCreate(inHostname, &hostname);
1096 require_noerr_quiet(err, exit);
1097 gResolveStatsObjCount++;
1098 *p = hostname;
1099 }
1100
1101 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
1102 require_noerr_quiet(err, exit);
1103
1104 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
1105 require_noerr_quiet(err, exit);
1106
1107 exit:
1108 return (err);
1109 }
1110
1111 //===========================================================================================================================
1112 // ResolveStatsHostnameCreate
1113 //===========================================================================================================================
1114
1115 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
1116 {
1117 mStatus err;
1118 ResolveStatsHostname * obj;
1119 size_t nameLen;
1120
1121 nameLen = DomainNameLength(inName);
1122 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
1123
1124 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
1125 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1126
1127 memcpy(obj->name, inName, nameLen);
1128
1129 *outHostname = obj;
1130 err = mStatus_NoError;
1131
1132 exit:
1133 return (err);
1134 }
1135
1136 //===========================================================================================================================
1137 // ResolveStatsDomainCreateAWDVersion
1138 //===========================================================================================================================
1139
1140 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
1141 {
1142 mStatus err;
1143 AWDMDNSResponderResolveStatsDomain * domain;
1144 ResolveStatsHostname * hostname;
1145 AWDMDNSResponderResolveStatsHostname * awdHostname;
1146 NSString * name;
1147
1148 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
1149 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1150
1151 name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
1152 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1153
1154 domain.name = name;
1155 [name release];
1156 name = nil;
1157
1158 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
1159 {
1160 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
1161 require_noerr_quiet(err, exit);
1162
1163 [domain addHostname:awdHostname];
1164 [awdHostname release];
1165 awdHostname = nil;
1166 }
1167
1168 *outDomain = domain;
1169 domain = nil;
1170 err = mStatus_NoError;
1171
1172 exit:
1173 [domain release];
1174 return (err);
1175 }
1176
1177 //===========================================================================================================================
1178 // ResolveStatsHostnameFree
1179 //===========================================================================================================================
1180
1181 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
1182 {
1183 ResolveStatsIPv4AddrSet * addrV4;
1184 ResolveStatsIPv6Addr * addrV6;
1185 ResolveStatsNegAAAASet * negV6;
1186
1187 while ((addrV4 = inHostname->addrV4List) != NULL)
1188 {
1189 inHostname->addrV4List = addrV4->next;
1190 ResolveStatsIPv4AddrSetFree(addrV4);
1191 }
1192 while ((addrV6 = inHostname->addrV6List) != NULL)
1193 {
1194 inHostname->addrV6List = addrV6->next;
1195 ResolveStatsIPv6AddressFree(addrV6);
1196 }
1197 while ((negV6 = inHostname->negV6List) != NULL)
1198 {
1199 inHostname->negV6List = negV6->next;
1200 ResolveStatsNegAAAASetFree(negV6);
1201 }
1202 free(inHostname);
1203 }
1204
1205 //===========================================================================================================================
1206 // ResolveStatsHostnameUpdate
1207 //===========================================================================================================================
1208
1209 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
1210 {
1211 mStatus err;
1212
1213 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
1214 {
1215 ResolveStatsIPv4AddrSet ** p;
1216 ResolveStatsIPv4AddrSet * addrV4;
1217 int i;
1218 IPv4AddrCounter * counter;
1219
1220 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
1221 {
1222 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1223 {
1224 counter = &addrV4->counters[i];
1225 if (counter->count == 0) break;
1226 if (counter->serverID != inServerID) continue;
1227 if (inResp->type == kResponseType_NegA)
1228 {
1229 if (counter->isNegative) break;
1230 }
1231 else
1232 {
1233 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
1234 }
1235 }
1236 if (i < (int)countof(addrV4->counters)) break;
1237 }
1238 if (!addrV4)
1239 {
1240 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1241 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
1242 require_noerr_quiet(err, exit);
1243 gResolveStatsObjCount++;
1244
1245 *p = addrV4;
1246 counter = &addrV4->counters[0];
1247 }
1248 if (counter->count == 0)
1249 {
1250 counter->serverID = inServerID;
1251 if (inResp->type == kResponseType_NegA)
1252 {
1253 counter->isNegative = 1;
1254 }
1255 else
1256 {
1257 counter->isNegative = 0;
1258 memcpy(counter->addrBytes, inResp->data, 4);
1259 }
1260 }
1261 increment_saturate(counter->count, UINT16_MAX);
1262 err = mStatus_NoError;
1263 }
1264 else if (inResp->type == kResponseType_IPv6Addr)
1265 {
1266 ResolveStatsIPv6Addr ** p;
1267 ResolveStatsIPv6Addr * addrV6;
1268
1269 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
1270 {
1271 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
1272 }
1273 if (!addrV6)
1274 {
1275 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1276 err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
1277 require_noerr_quiet(err, exit);
1278 gResolveStatsObjCount++;
1279
1280 *p = addrV6;
1281 }
1282 increment_saturate(addrV6->count, UINT16_MAX);
1283 err = mStatus_NoError;
1284 }
1285 else if (inResp->type == kResponseType_NegAAAA)
1286 {
1287 ResolveStatsNegAAAASet ** p;
1288 ResolveStatsNegAAAASet * negV6;
1289 int i;
1290 NegAAAACounter * counter;
1291
1292 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1293 {
1294 for (i = 0; i < (int)countof(negV6->counters); ++i)
1295 {
1296 counter = &negV6->counters[i];
1297 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1298 }
1299 if (i < (int)countof(negV6->counters)) break;
1300 }
1301 if (!negV6)
1302 {
1303 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1304 err = ResolveStatsNegAAAASetCreate(&negV6);
1305 require_noerr_quiet(err, exit);
1306 gResolveStatsObjCount++;
1307
1308 *p = negV6;
1309 counter = &negV6->counters[0];
1310 }
1311 if (counter->count == 0) counter->serverID = inServerID;
1312 increment_saturate(counter->count, UINT16_MAX);
1313 err = mStatus_NoError;
1314 }
1315 else
1316 {
1317 err = mStatus_Invalid;
1318 }
1319
1320 exit:
1321 return (err);
1322 }
1323
1324 //===========================================================================================================================
1325 // ResolveStatsHostnameCreateAWDVersion
1326 //===========================================================================================================================
1327
1328 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1329 {
1330 mStatus err;
1331 AWDMDNSResponderResolveStatsHostname * hostname;
1332 NSString * name;
1333 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1334 const char * ptr;
1335 ResolveStatsIPv4AddrSet * addrV4;
1336 ResolveStatsIPv6Addr * addrV6;
1337 ResolveStatsNegAAAASet * negV6;
1338 AWDMDNSResponderResolveStatsResult * result = nil;
1339 int i;
1340
1341 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1342 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1343
1344 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1345 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1346
1347 name = [[NSString alloc] initWithUTF8String:nameBuf];
1348 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1349
1350 hostname.name = name;
1351 [name release];
1352 name = nil;
1353
1354 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1355 {
1356 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1357 {
1358 const IPv4AddrCounter * counter;
1359 NSData * addrBytes;
1360
1361 counter = &addrV4->counters[i];
1362 if (counter->count == 0) break;
1363
1364 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1365 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1366
1367 if (counter->isNegative)
1368 {
1369 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1370 }
1371 else
1372 {
1373 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1374 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1375
1376 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1377 result.data = addrBytes;
1378 [addrBytes release];
1379 }
1380 result.count = counter->count;
1381 result.serverID = counter->serverID;
1382
1383 [hostname addResult:result];
1384 [result release];
1385 result = nil;
1386 }
1387 }
1388
1389 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1390 {
1391 NSData * addrBytes;
1392
1393 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1394 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1395
1396 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1397 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1398
1399 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1400 result.count = addrV6->count;
1401 result.serverID = addrV6->serverID;
1402 result.data = addrBytes;
1403
1404 [addrBytes release];
1405
1406 [hostname addResult:result];
1407 [result release];
1408 result = nil;
1409 }
1410
1411 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1412 {
1413 for (i = 0; i < (int)countof(negV6->counters); ++i)
1414 {
1415 const NegAAAACounter * counter;
1416
1417 counter = &negV6->counters[i];
1418 if (counter->count == 0) break;
1419
1420 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1421 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1422
1423 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1424 result.count = counter->count;
1425 result.serverID = counter->serverID;
1426
1427 [hostname addResult:result];
1428 [result release];
1429 result = nil;
1430 }
1431 }
1432
1433 *outHostname = hostname;
1434 hostname = nil;
1435 err = mStatus_NoError;
1436
1437 exit:
1438 [result release];
1439 [hostname release];
1440 return (err);
1441 }
1442
1443 //===========================================================================================================================
1444 // ResolveStatsDNSServerCreate
1445 //===========================================================================================================================
1446
1447 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1448 {
1449 mStatus err;
1450 ResolveStatsDNSServer * obj;
1451 size_t addrLen;
1452
1453 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1454
1455 addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
1456 obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
1457 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1458
1459 obj->isForCell = inForCell;
1460 if (inAddr->type == mDNSAddrType_IPv4)
1461 {
1462 obj->isAddrV6 = mDNSfalse;
1463 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1464 }
1465 else
1466 {
1467 obj->isAddrV6 = mDNStrue;
1468 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1469 }
1470
1471 *outServer = obj;
1472 err = mStatus_NoError;
1473
1474 exit:
1475 return (err);
1476 }
1477
1478 //===========================================================================================================================
1479 // ResolveStatsDNSServerFree
1480 //===========================================================================================================================
1481
1482 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1483 {
1484 free(inServer);
1485 }
1486
1487 //===========================================================================================================================
1488 // ResolveStatsDNSServerCreateAWDVersion
1489 //===========================================================================================================================
1490
1491 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1492 {
1493 mStatus err;
1494 AWDMDNSResponderResolveStatsDNSServer * server;
1495 NSData * addrBytes = nil;
1496
1497 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1498 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1499
1500 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1501 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1502
1503 server.serverID = inServer->id;
1504 server.address = addrBytes;
1505 if (inServer->isForCell)
1506 {
1507 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1508 }
1509 else
1510 {
1511 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1512 }
1513
1514 *outServer = server;
1515 server = nil;
1516 err = mStatus_NoError;
1517
1518 exit:
1519 [addrBytes release];
1520 [server release];
1521 return (err);
1522 }
1523
1524 //===========================================================================================================================
1525 // ResolveStatsIPv4AddrSetCreate
1526 //===========================================================================================================================
1527
1528 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1529 {
1530 mStatus err;
1531 ResolveStatsIPv4AddrSet * obj;
1532
1533 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1534 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1535
1536 *outSet = obj;
1537 err = mStatus_NoError;
1538
1539 exit:
1540 return (err);
1541 }
1542
1543 //===========================================================================================================================
1544 // ResolveStatsIPv4AddrSetFree
1545 //===========================================================================================================================
1546
1547 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1548 {
1549 free(inSet);
1550 }
1551
1552 //===========================================================================================================================
1553 // ResolveStatsIPv6AddressCreate
1554 //===========================================================================================================================
1555
1556 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1557 {
1558 mStatus err;
1559 ResolveStatsIPv6Addr * obj;
1560
1561 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1562 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1563
1564 obj->serverID = inServerID;
1565 memcpy(obj->addrBytes, inAddrBytes, 16);
1566
1567 *outAddr = obj;
1568 err = mStatus_NoError;
1569
1570 exit:
1571 return (err);
1572 }
1573
1574 //===========================================================================================================================
1575 // ResolveStatsIPv6AddressFree
1576 //===========================================================================================================================
1577
1578 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1579 {
1580 free(inAddr);
1581 }
1582
1583 //===========================================================================================================================
1584 // ResolveStatsNegAAAASetCreate
1585 //===========================================================================================================================
1586
1587 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1588 {
1589 mStatus err;
1590 ResolveStatsNegAAAASet * obj;
1591
1592 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1593 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1594
1595 *outSet = obj;
1596 err = mStatus_NoError;
1597
1598 exit:
1599 return (err);
1600 }
1601
1602 //===========================================================================================================================
1603 // ResolveStatsNegAAAASetFree
1604 //===========================================================================================================================
1605
1606 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1607 {
1608 free(inSet);
1609 }
1610
1611 //===========================================================================================================================
1612 // ResolveStatsGetServerID
1613 //===========================================================================================================================
1614
1615 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1616 {
1617 mStatus err;
1618 ResolveStatsDNSServer ** p;
1619 ResolveStatsDNSServer * server;
1620
1621 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1622
1623 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1624 {
1625 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1626 {
1627 if (inServerAddr->type == mDNSAddrType_IPv4)
1628 {
1629 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1630 }
1631 else
1632 {
1633 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1634 }
1635 }
1636 }
1637
1638 if (!server)
1639 {
1640 require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
1641 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1642 err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
1643 require_noerr_quiet(err, exit);
1644 gResolveStatsObjCount++;
1645
1646 server->id = (uint8_t)gResolveStatsNextServerID++;
1647 server->next = gResolveStatsServerList;
1648 gResolveStatsServerList = server;
1649 }
1650 else if (gResolveStatsServerList != server)
1651 {
1652 *p = server->next;
1653 server->next = gResolveStatsServerList;
1654 gResolveStatsServerList = server;
1655 }
1656
1657 *outServerID = server->id;
1658 err = mStatus_NoError;
1659
1660 exit:
1661 return (err);
1662 }
1663
1664 //===========================================================================================================================
1665 // DNSMessageSizeStatsCreate
1666 //===========================================================================================================================
1667
1668 mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
1669 {
1670 mStatus err;
1671 DNSMessageSizeStats * stats;
1672
1673 stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
1674 require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
1675
1676 *outStats = stats;
1677 err = mStatus_NoError;
1678
1679 exit:
1680 return (err);
1681 }
1682
1683 //===========================================================================================================================
1684 // DNSMessageSizeStatsFree
1685 //===========================================================================================================================
1686
1687 mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
1688 {
1689 free(inStats);
1690 }
1691
1692 //===========================================================================================================================
1693 // CreateQueryStatsList
1694 //===========================================================================================================================
1695
1696 mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
1697 {
1698 mStatus err;
1699 QueryStats ** p;
1700 QueryStats * stats;
1701 const QueryStatsArgs * args;
1702 const QueryStatsArgs * const end = kQueryStatsArgs + countof(kQueryStatsArgs);
1703 QueryStats * list = NULL;
1704
1705 p = &list;
1706 for (args = kQueryStatsArgs; args < end; ++args)
1707 {
1708 err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
1709 require_noerr_quiet(err, exit);
1710
1711 *p = stats;
1712 p = &stats->next;
1713 }
1714
1715 *outList = list;
1716 list = NULL;
1717 err = mStatus_NoError;
1718
1719 exit:
1720 QueryStatsFreeList(list);
1721 return (err);
1722 }
1723
1724 //===========================================================================================================================
1725 // CreateResolveStatsList
1726 //===========================================================================================================================
1727
1728 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1729 {
1730 mStatus err;
1731 unsigned int i;
1732 ResolveStatsDomain * domain;
1733 ResolveStatsDomain ** p;
1734 ResolveStatsDomain * list = NULL;
1735
1736 p = &list;
1737 for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
1738 {
1739 err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
1740 require_noerr_quiet(err, exit);
1741
1742 *p = domain;
1743 p = &domain->next;
1744 }
1745
1746 *outList = list;
1747 list = NULL;
1748 err = mStatus_NoError;
1749
1750 exit:
1751 FreeResolveStatsList(list);
1752 return (err);
1753 }
1754
1755 //===========================================================================================================================
1756 // FreeResolveStatsList
1757 //===========================================================================================================================
1758
1759 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1760 {
1761 ResolveStatsDomain * domain;
1762
1763 while ((domain = inList) != NULL)
1764 {
1765 inList = domain->next;
1766 ResolveStatsDomainFree(domain);
1767 }
1768 }
1769
1770 //===========================================================================================================================
1771 // FreeResolveStatsServerList
1772 //===========================================================================================================================
1773
1774 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1775 {
1776 ResolveStatsDNSServer * server;
1777
1778 while ((server = inList) != NULL)
1779 {
1780 inList = server->next;
1781 ResolveStatsDNSServerFree(server);
1782 }
1783 }
1784
1785 //===========================================================================================================================
1786 // SubmitAWDMetric
1787 //===========================================================================================================================
1788
1789 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1790 {
1791 mStatus err;
1792
1793 switch (inMetricID)
1794 {
1795 case AWDMetricId_MDNSResponder_DNSStatistics:
1796 err = SubmitAWDMetricQueryStats();
1797 break;
1798
1799 case AWDMetricId_MDNSResponder_ResolveStats:
1800 err = SubmitAWDMetricResolveStats();
1801 break;
1802
1803 case AWDMetricId_MDNSResponder_ServicesStats:
1804 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
1805 KQueueLock();
1806 // reset the no of max services since we want to collect the max no of services registered per AWD submission period
1807 max_num_regservices = curr_num_regservices;
1808 KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
1809 err = mStatus_NoError;
1810 break;
1811
1812 case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
1813 err = SubmitAWDMetricDNSMessageSizeStats();
1814 break;
1815
1816 default:
1817 err = mStatus_UnsupportedErr;
1818 break;
1819 }
1820
1821 if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1822 return (err);
1823 }
1824
1825 //===========================================================================================================================
1826 // SubmitAWDMetricQueryStats
1827 //===========================================================================================================================
1828
1829 mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
1830 mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
1831
1832 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1833 {
1834 mStatus err;
1835 BOOL success;
1836 QueryStats * stats;
1837 QueryStats * statsList;
1838 QueryStats * newStatsList;
1839 AWDMetricContainer * container = nil;
1840 AWDMDNSResponderDNSStatistics * metric = nil;
1841
1842 newStatsList = NULL;
1843 CreateQueryStatsList(&newStatsList);
1844
1845 KQueueLock();
1846 statsList = gQueryStatsList;
1847 gQueryStatsList = newStatsList;
1848 KQueueUnlock("SubmitAWDMetricQueryStats");
1849
1850 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1851 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1852
1853 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1854 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1855
1856 while ((stats = statsList) != NULL)
1857 {
1858 err = AddQueryStats(metric, stats);
1859 require_noerr_quiet(err, exit);
1860
1861 statsList = stats->next;
1862 QueryStatsFree(stats);
1863 }
1864
1865 container.metric = metric;
1866 success = [gAWDServerConnection submitMetric:container];
1867 LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
1868 err = success ? mStatus_NoError : mStatus_UnknownErr;
1869
1870 exit:
1871 [metric release];
1872 [container release];
1873 QueryStatsFreeList(statsList);
1874 return (err);
1875 }
1876
1877 mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
1878 {
1879 mStatus err;
1880
1881 if (inStats->nonCellular)
1882 {
1883 err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
1884 require_noerr_quiet(err, exit);
1885 }
1886 if (inStats->cellular)
1887 {
1888 err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
1889 require_noerr_quiet(err, exit);
1890 }
1891 err = mStatus_NoError;
1892
1893 exit:
1894 return (err);
1895 }
1896
1897 mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1898 {
1899 mStatus err;
1900 AWDDNSDomainStats * awdStats;
1901
1902 if (inSet->histA)
1903 {
1904 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1905 require_noerr_quiet(err, exit);
1906
1907 [inMetric addStats:awdStats];
1908 [awdStats release];
1909 }
1910 if (inSet->histAAAA)
1911 {
1912 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1913 require_noerr_quiet(err, exit);
1914
1915 [inMetric addStats:awdStats];
1916 [awdStats release];
1917 }
1918 err = mStatus_NoError;
1919
1920 exit:
1921 return (err);
1922 }
1923
1924 //===========================================================================================================================
1925 // SubmitAWDMetricResolveStats
1926 //===========================================================================================================================
1927
1928 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1929 {
1930 mStatus err;
1931 ResolveStatsDomain * newResolveStatsList;
1932 ResolveStatsDomain * domainList = NULL;
1933 ResolveStatsDNSServer * serverList = NULL;
1934 AWDMetricContainer * container = nil;
1935 AWDMDNSResponderResolveStats * metric = nil;
1936 ResolveStatsDNSServer * server;
1937 ResolveStatsDomain * domain;
1938 BOOL success;
1939
1940 err = CreateResolveStatsList(&newResolveStatsList);
1941 require_noerr_quiet(err, exit);
1942
1943 KQueueLock();
1944 domainList = gResolveStatsList;
1945 serverList = gResolveStatsServerList;
1946 gResolveStatsList = newResolveStatsList;
1947 gResolveStatsServerList = NULL;
1948 gResolveStatsNextServerID = 0;
1949 gResolveStatsObjCount = 0;
1950 KQueueUnlock("SubmitAWDMetricResolveStats");
1951
1952 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1953 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1954
1955 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1956 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1957
1958 while ((server = serverList) != NULL)
1959 {
1960 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1961
1962 serverList = server->next;
1963 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1964 ResolveStatsDNSServerFree(server);
1965 require_noerr_quiet(err, exit);
1966
1967 [metric addServer:awdServer];
1968 [awdServer release];
1969 }
1970
1971 while ((domain = domainList) != NULL)
1972 {
1973 AWDMDNSResponderResolveStatsDomain * awdDomain;
1974
1975 domainList = domain->next;
1976 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1977 ResolveStatsDomainFree(domain);
1978 require_noerr_quiet(err, exit);
1979
1980 [metric addDomain:awdDomain];
1981 [awdDomain release];
1982 }
1983
1984 container.metric = metric;
1985 success = [gAWDServerConnection submitMetric:container];
1986 LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed");
1987 err = success ? mStatus_NoError : mStatus_UnknownErr;
1988
1989 exit:
1990 [metric release];
1991 [container release];
1992 FreeResolveStatsList(domainList);
1993 FreeResolveStatsServerList(serverList);
1994 return (err);
1995 }
1996
1997 //===========================================================================================================================
1998 // SubmitAWDMetricDNSMessageSizeStats
1999 //===========================================================================================================================
2000
2001 mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
2002 {
2003 mStatus err;
2004 DNSMessageSizeStats * stats;
2005 DNSMessageSizeStats * newStats;
2006 AWDMetricContainer * container;
2007 AWDMDNSResponderDNSMessageSizeStats * metric = nil;
2008 BOOL success;
2009
2010 newStats = NULL;
2011 DNSMessageSizeStatsCreate(&newStats);
2012
2013 KQueueLock();
2014 stats = gDNSMessageSizeStats;
2015 gDNSMessageSizeStats = newStats;
2016 KQueueUnlock("SubmitAWDMetricDNSMessageSizeStats");
2017
2018 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSMessageSizeStats];
2019 require_action_quiet(container, exit, err = mStatus_UnknownErr);
2020
2021 metric = [[AWDMDNSResponderDNSMessageSizeStatsSoft alloc] init];
2022 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
2023
2024 if (stats)
2025 {
2026 size_t binCount;
2027 uint32_t bins[Max(kQuerySizeBinCount, kResponseSizeBinCount)];
2028
2029 // Set query size counts.
2030
2031 binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
2032 [metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
2033
2034 // Set response size counts.
2035
2036 binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
2037 [metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
2038 }
2039
2040 container.metric = metric;
2041 success = [gAWDServerConnection submitMetric:container];
2042 LogMsg("SubmitAWDMetricDNSMessageSizeStats: metric submission %s.", success ? "succeeded" : "failed");
2043 err = success ? mStatus_NoError : mStatus_UnknownErr;
2044
2045 exit:
2046 [metric release];
2047 [container release];
2048 if (stats) DNSMessageSizeStatsFree(stats);
2049 return (err);
2050 }
2051
2052 //===========================================================================================================================
2053 // CreateAWDDNSDomainStats
2054 //===========================================================================================================================
2055
2056 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
2057 {
2058 mStatus err;
2059 AWDDNSDomainStats * awdStats = nil;
2060 NSString * domain = nil;
2061 size_t binCount;
2062 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
2063 uint32_t latencyBins[kQueryStatsLatencyBinCount];
2064
2065 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
2066 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
2067
2068 domain = [[NSString alloc] initWithUTF8String:inDomain];
2069 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
2070
2071 awdStats.domain = domain;
2072 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
2073 awdStats.recordType = inType;
2074
2075 // Positively answered query send counts
2076
2077 binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
2078 [awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2079
2080 // binCount > 1 means that at least one of the non-zero send count bins had a non-zero count, i.e., at least one query
2081 // was sent out on the wire. In that case, include the associated latency bins as well.
2082
2083 if (binCount > 1)
2084 {
2085 binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
2086 [awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2087 }
2088
2089 // Negatively answered query send counts
2090
2091 binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2092 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2093
2094 if (binCount > 1)
2095 {
2096 binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
2097 [awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2098 }
2099
2100 // Unanswered query send counts
2101
2102 binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2103 [awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2104
2105 if (binCount > 1)
2106 {
2107 binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
2108 [awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
2109 }
2110
2111 *outStats = awdStats;
2112 awdStats = nil;
2113 err = mStatus_NoError;
2114
2115 exit:
2116 [domain release];
2117 [awdStats release];
2118 return (err);
2119 }
2120
2121 //===========================================================================================================================
2122 // LogDNSHistSet
2123 //===========================================================================================================================
2124
2125 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
2126 {
2127 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
2128 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
2129 }
2130
2131 //===========================================================================================================================
2132 // LogDNSHist
2133 //===========================================================================================================================
2134
2135 #define Percent(N, D) (((N) * 100) / (D)), ((((N) * 10000) / (D)) % 100)
2136 #define PercentFmt "%3u.%02u"
2137 #define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
2138 LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
2139
2140 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
2141 {
2142 unsigned int totalAnswered;
2143 unsigned int totalNegAnswered;
2144 unsigned int totalUnanswered;
2145 int i;
2146
2147 totalAnswered = 0;
2148 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2149 {
2150 totalAnswered += inHist->answeredQuerySendCountBins[i];
2151 }
2152
2153 totalNegAnswered = 0;
2154 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2155 {
2156 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
2157 }
2158
2159 totalUnanswered = 0;
2160 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2161 {
2162 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
2163 }
2164
2165 LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
2166 LogMsgNoIdent("Answered questions %4u", totalAnswered);
2167 LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
2168 LogMsgNoIdent("Unanswered questions %4u", totalUnanswered);
2169 LogMsgNoIdent("-- Query send counts ---------");
2170 LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
2171 LogMsgNoIdent("-- Query send counts (NAQs) --");
2172 LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
2173
2174 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
2175 {
2176 LogMsgNoIdent("--- Response times -----------");
2177 LogDNSHistLatencies(inHist->responseLatencyBins);
2178 }
2179
2180 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
2181 {
2182 LogMsgNoIdent("--- Response times (NAQs) ----");
2183 LogDNSHistLatencies(inHist->negResponseLatencyBins);
2184 }
2185
2186 if (totalUnanswered > 0)
2187 {
2188 LogMsgNoIdent("--- Unanswered query times ---");
2189 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
2190 }
2191 }
2192
2193 //===========================================================================================================================
2194 // LogDNSHistSendCounts
2195 //===========================================================================================================================
2196
2197 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
2198 {
2199 uint32_t total;
2200 char label[16];
2201 int i;
2202
2203 total = 0;
2204 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2205 {
2206 total += inSendCountBins[i];
2207 }
2208
2209 if (total > 0)
2210 {
2211 uint32_t accumulator = 0;
2212
2213 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2214 {
2215 accumulator += inSendCountBins[i];
2216 if (i < (kQueryStatsSendCountBinCount - 1))
2217 {
2218 snprintf(label, sizeof(label), "%2d ", i);
2219 }
2220 else
2221 {
2222 snprintf(label, sizeof(label), "%2d+", i);
2223 }
2224 LogStat(label, inSendCountBins[i], accumulator, total);
2225 if (accumulator == total) break;
2226 }
2227 }
2228 else
2229 {
2230 LogMsgNoIdent("No data.");
2231 }
2232 }
2233
2234 //===========================================================================================================================
2235 // LogDNSHistLatencies
2236 //===========================================================================================================================
2237
2238 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
2239 {
2240 uint32_t total;
2241 int i;
2242 char label[16];
2243
2244 total = 0;
2245 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2246 {
2247 total += inLatencyBins[i];
2248 }
2249
2250 if (total > 0)
2251 {
2252 uint32_t accumulator = 0;
2253
2254 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2255 {
2256 accumulator += inLatencyBins[i];
2257 if (i < (int)countof(kResponseLatencyMsLimits))
2258 {
2259 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
2260 }
2261 else
2262 {
2263 snprintf(label, sizeof(label), "< ∞ ms");
2264 }
2265 LogStat(label, inLatencyBins[i], accumulator, total);
2266 if (accumulator == total) break;
2267 }
2268 }
2269 else
2270 {
2271 LogMsgNoIdent("No data.");
2272 }
2273 }
2274
2275 //===========================================================================================================================
2276 // LogDNSMessageSizeStats
2277 //===========================================================================================================================
2278
2279 mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
2280 {
2281 size_t i;
2282 uint32_t total;
2283
2284 total = 0;
2285 for (i = 0; i < inBinCount; ++i)
2286 {
2287 total += inBins[i];
2288 }
2289
2290 if (total > 0)
2291 {
2292 uint32_t accumulator;
2293 unsigned int lower, upper;
2294 char label[16];
2295
2296 accumulator = 0;
2297 upper = 0;
2298 for (i = 0; i < inBinCount; ++i)
2299 {
2300 accumulator += inBins[i];
2301 lower = upper + 1;
2302 if (i < (inBinCount - 1))
2303 {
2304 upper += inBinWidth;
2305 snprintf(label, sizeof(label), "%3u - %-3u", lower, upper);
2306 }
2307 else
2308 {
2309 snprintf(label, sizeof(label), "%3u+ ", lower);
2310 }
2311 LogStat(label, inBins[i], accumulator, total);
2312 if (accumulator == total) break;
2313 }
2314 }
2315 else
2316 {
2317 LogMsgNoIdent("No data.");
2318 }
2319 }
2320
2321 //===========================================================================================================================
2322 // CopyHistogramBins
2323 //
2324 // Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
2325 // bin and all bins with non-zero values.
2326 //===========================================================================================================================
2327
2328 mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
2329 {
2330 size_t i;
2331 size_t minCount;
2332
2333 if (inBinCount == 0) return (0);
2334
2335 minCount = 1;
2336 for (i = 0; i < inBinCount; ++i)
2337 {
2338 inDstBins[i] = inSrcBins[i];
2339 if (inDstBins[i] > 0) minCount = i + 1;
2340 }
2341
2342 return (minCount);
2343 }
2344 #endif // TARGET_OS_IOS