2 * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
34 #import "mDNSMacOSX.h"
35 #import "DebugServices.h"
37 //===========================================================================================================================
38 // External Frameworks
39 //===========================================================================================================================
41 SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics)
43 // AWDServerConnection class
45 SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection)
47 #define AWDServerConnectionSoft getAWDServerConnectionClass()
49 // Classes for query stats
51 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics)
52 SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
54 #define AWDMDNSResponderDNSStatisticsSoft getAWDMDNSResponderDNSStatisticsClass()
55 #define AWDDNSDomainStatsSoft getAWDDNSDomainStatsClass()
57 // Classes for resolve stats
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)
65 #define AWDMDNSResponderResolveStatsSoft getAWDMDNSResponderResolveStatsClass()
66 #define AWDMDNSResponderResolveStatsDNSServerSoft getAWDMDNSResponderResolveStatsDNSServerClass()
67 #define AWDMDNSResponderResolveStatsDomainSoft getAWDMDNSResponderResolveStatsDomainClass()
68 #define AWDMDNSResponderResolveStatsHostnameSoft getAWDMDNSResponderResolveStatsHostnameClass()
69 #define AWDMDNSResponderResolveStatsResultSoft getAWDMDNSResponderResolveStatsResultClass()
71 // Classes for services stats
73 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
75 #define AWDMetricManagerSoft getAWDMetricManagerClass()
77 // Classes for DNS message size stats
79 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSMessageSizeStats)
81 #define AWDMDNSResponderDNSMessageSizeStatsSoft getAWDMDNSResponderDNSMessageSizeStatsClass()
83 //===========================================================================================================================
85 //===========================================================================================================================
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)
92 //===========================================================================================================================
94 //===========================================================================================================================
96 #define kQueryStatsMaxQuerySendCount 10
97 #define kQueryStatsSendCountBinCount (kQueryStatsMaxQuerySendCount + 1)
98 #define kQueryStatsLatencyBinCount 55
99 #define kResolveStatsMaxObjCount 2000
101 //===========================================================================================================================
103 //===========================================================================================================================
105 // Data structures for query stats.
107 typedef struct QueryStats QueryStats;
108 typedef struct DNSHistSet DNSHistSet;
109 typedef mDNSBool (*QueryNameTest_f)(const QueryStats *inStats, const domainname *inQueryName);
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.
124 check_compile_time(sizeof(QueryStats) <= 64);
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.
129 // answeredQuerySendCountBins
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.
134 // unansweredQuerySendCountBins
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.
139 // responseLatencyBins
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, ∞.
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];
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));
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.
166 static const mDNSu32 kResponseLatencyMsLimits[] =
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,
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));
184 DNSHist * histA; // Histogram data for queries for A resource records.
185 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
190 const char * domainStr;
191 const char * altDomainStr;
192 QueryNameTest_f test;
197 // Data structures for resolve stats.
199 static const char * const kResolveStatsDomains[] =
207 check_compile_time(countof(kResolveStatsDomains) == 4);
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;
216 struct ResolveStatsDomain
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.
225 check_compile_time(sizeof(ResolveStatsDomain) <= 40);
227 struct ResolveStatsHostname
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.
236 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
238 struct ResolveStatsDNSServer
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.
247 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
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.
254 uint8_t addrBytes[4]; // IPv4 address bytes.
258 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
260 struct ResolveStatsIPv4AddrSet
262 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
263 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
266 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
268 struct ResolveStatsIPv6Addr
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.
276 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
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.
285 check_compile_time(sizeof(NegAAAACounter) <= 4);
287 struct ResolveStatsNegAAAASet
289 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
290 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
293 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
297 kResponseType_IPv4Addr = 1,
298 kResponseType_IPv6Addr = 2,
299 kResponseType_NegA = 3,
300 kResponseType_NegAAAA = 4
307 const uint8_t * data;
311 // Data structures for DNS message size stats.
313 #define kQuerySizeBinWidth 16
314 #define kQuerySizeBinMax 512
315 #define kQuerySizeBinCount ((kQuerySizeBinMax / kQuerySizeBinWidth) + 1)
317 check_compile_time(kQuerySizeBinWidth > 0);
318 check_compile_time(kQuerySizeBinCount > 0);
319 check_compile_time((kQuerySizeBinMax % kQuerySizeBinWidth) == 0);
321 #define kResponseSizeBinWidth 16
322 #define kResponseSizeBinMax 512
323 #define kResponseSizeBinCount ((kResponseSizeBinMax / kResponseSizeBinWidth) + 1)
325 check_compile_time(kResponseSizeBinWidth > 0);
326 check_compile_time(kResponseSizeBinCount > 0);
327 check_compile_time((kResponseSizeBinMax % kResponseSizeBinWidth) == 0);
331 uint16_t querySizeBins[kQuerySizeBinCount];
332 uint16_t responseSizeBins[kResponseSizeBinCount];
334 } DNSMessageSizeStats;
336 check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
338 //===========================================================================================================================
340 //===========================================================================================================================
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);
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);
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);
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);
370 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
371 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
373 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
374 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
376 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
377 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
378 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
380 // DNS message size stats
382 mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
383 mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
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);
400 mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
402 //===========================================================================================================================
404 //===========================================================================================================================
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;
414 // Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
416 static const QueryStatsArgs kQueryStatsArgs[] =
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 }
431 check_compile_time(countof(kQueryStatsArgs) == 11);
433 //===========================================================================================================================
435 //===========================================================================================================================
437 mStatus MetricsInit(void)
441 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
442 initWithComponentId: AWDComponentId_MDNSResponder
443 andBlockOnConfiguration: NO];
445 if (gAWDServerConnection)
447 [gAWDServerConnection
448 registerQueriableMetricCallback: ^(UInt32 inMetricID)
450 SubmitAWDMetric(inMetricID);
452 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
454 [gAWDServerConnection
455 registerQueriableMetricCallback: ^(UInt32 inMetricID)
457 SubmitAWDMetric(inMetricID);
459 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
461 [gAWDServerConnection
462 registerQueriableMetricCallback: ^(UInt32 inMetricID)
464 SubmitAWDMetric(inMetricID);
466 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
468 [gAWDServerConnection
469 registerQueriableMetricCallback: ^(UInt32 inMetricID)
471 SubmitAWDMetric(inMetricID);
473 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSMessageSizeStats];
477 LogMsg("MetricsInit: failed to create AWD server connection.");
481 if( gAWDServerConnection )
483 CreateQueryStatsList(&gQueryStatsList);
484 CreateResolveStatsList(&gResolveStatsList);
485 DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
488 return (mStatus_NoError);
491 //===========================================================================================================================
492 // MetricsUpdateDNSQueryStats
493 //===========================================================================================================================
495 mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
500 require_quiet(gAWDServerConnection, exit);
501 require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
503 for (stats = gQueryStatsList; stats; stats = stats->next)
505 match = stats->test(stats, inQueryName);
508 QueryStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
509 if (stats->terminal) break;
517 //===========================================================================================================================
518 // MetricsUpdateDNSResolveStats
519 //===========================================================================================================================
521 mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
523 ResolveStatsDomain * domainStats;
526 mDNSBool isQueryInDomain;
528 int skipCountLast = -1;
530 const domainname * queryParentDomain;
533 require_quiet(gAWDServerConnection, exit);
534 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
535 require_quiet(inRR->rDNSServer, exit);
537 queryLabelCount = CountLabels(inQueryName);
539 for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
541 isQueryInDomain = mDNSfalse;
542 skipCount = queryLabelCount - domainStats->labelCount;
545 if (skipCount != skipCountLast)
547 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
548 skipCountLast = skipCount;
550 isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
552 if (!isQueryInDomain) continue;
554 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
555 if (hostnameLen >= sizeof(hostname.c)) continue;
557 memcpy(hostname.c, inQueryName->c, hostnameLen);
558 hostname.c[hostnameLen] = 0;
560 if (inRR->RecordType == kDNSRecordTypePacketNegative)
562 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
563 response.data = NULL;
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;
570 ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
577 //===========================================================================================================================
578 // MetricsUpdateDNSQuerySize
579 //===========================================================================================================================
581 mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
583 mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
585 if (!gDNSMessageSizeStats) return;
586 UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
589 mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
593 if (inSize == 0) return;
594 i = (inSize - 1) / inBinWidth;
595 if (i >= inBinCount) i = inBinCount - 1;
596 increment_saturate(inBins[i], UINT16_MAX);
599 //===========================================================================================================================
600 // MetricsUpdateDNSResponseSize
601 //===========================================================================================================================
603 mDNSexport void MetricsUpdateDNSResponseSize(mDNSu32 inSize)
605 if (!gDNSMessageSizeStats) return;
606 UpdateMessageSizeCounts(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth, inSize);
609 //===========================================================================================================================
611 //===========================================================================================================================
613 mDNSexport void LogMetrics(void)
616 const ResolveStatsDomain * domain;
617 const ResolveStatsHostname * hostname;
618 const ResolveStatsDNSServer * server;
619 const ResolveStatsIPv4AddrSet * addrV4;
620 const ResolveStatsIPv6Addr * addrV6;
621 const ResolveStatsNegAAAASet * negV6;
624 unsigned int serverID;
625 int serverObjCount = 0;
626 int hostnameObjCount = 0;
627 int addrObjCount = 0;
629 LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
630 LogMsgNoIdent("---- DNS query stats by domain -----");
632 for (stats = gQueryStatsList; stats; stats = stats->next)
634 if (!stats->nonCellular && !stats->cellular)
636 LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
639 if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
640 if (stats->cellular) LogDNSHistSet(stats->cellular, QueryStatsGetDomainString(stats), mDNStrue);
643 LogMsgNoIdent("---- DNS resolve stats by domain -----");
645 LogMsgNoIdent("Servers:");
646 for (server = gResolveStatsServerList; server; server = server->next)
649 LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
650 server->id, server->isForCell ? " C" : "NC", server->addrBytes);
653 for (domain = gResolveStatsList; domain; domain = domain->next)
656 for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
657 hostnameObjCount += hostnameCount;
659 LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
661 for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
663 LogMsgNoIdent(" %##s", hostname->name);
664 for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
666 for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
668 if (serverID == 0) addrObjCount++;
669 for (i = 0; i < (int)countof(addrV4->counters); ++i)
671 const IPv4AddrCounter * counter;
673 counter = &addrV4->counters[i];
674 if (counter->count == 0) break;
675 if (counter->serverID == serverID)
677 if (counter->isNegative)
679 LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
683 LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
688 for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
690 if (serverID == 0) addrObjCount++;
691 if (addrV6->serverID == serverID)
693 LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
696 for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
698 if (serverID == 0) addrObjCount++;
699 for (i = 0; i < (int)countof(negV6->counters); ++i)
701 const NegAAAACounter * counter;
703 counter = &negV6->counters[i];
704 if (counter->count == 0) break;
705 if (counter->serverID == serverID)
707 LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
714 LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
715 serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
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);
721 if (gDNSMessageSizeStats)
723 LogMsgNoIdent("---- DNS query size stats ---");
724 LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
726 LogMsgNoIdent("-- DNS response size stats --");
727 LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
731 LogMsgNoIdent("No DNS message size stats.");
735 //===========================================================================================================================
737 //===========================================================================================================================
739 mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName);
741 mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats)
746 obj = (QueryStats *)calloc(1, sizeof(*obj));
747 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
749 obj->domainStr = inDomainStr;
750 err = StringToDomainName(obj->domainStr, &obj->domain);
751 require_noerr_quiet(err, exit);
753 obj->altDomainStr = inAltDomainStr;
755 obj->labelCount = CountLabels((const domainname *)obj->domain);
756 obj->terminal = inTerminal;
760 err = mStatus_NoError;
763 if (obj) QueryStatsFree(obj);
767 mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName)
770 uint8_t * domainPtr = NULL;
775 if (strcmp(inString, ".") == 0)
781 ptr = MakeDomainNameFromDNSNameString(&domain, inString);
782 require_action_quiet(ptr, exit, err = mStatus_BadParamErr);
784 domainLen = DomainNameLength(&domain);
786 domainPtr = (uint8_t *)malloc(domainLen);
787 require_action_quiet(domainPtr, exit, err = mStatus_NoMemoryErr);
789 memcpy(domainPtr, domain.c, domainLen);
791 *outDomainName = domainPtr;
793 err = mStatus_NoError;
799 //===========================================================================================================================
801 //===========================================================================================================================
803 mDNSlocal void QueryStatsFree(QueryStats *inStats)
805 ForgetMem(&inStats->domain);
806 if (inStats->nonCellular)
808 ForgetMem(&inStats->nonCellular->histA);
809 ForgetMem(&inStats->nonCellular->histAAAA);
810 free(inStats->nonCellular);
811 inStats->nonCellular = NULL;
813 if (inStats->cellular)
815 ForgetMem(&inStats->cellular->histA);
816 ForgetMem(&inStats->cellular->histAAAA);
817 free(inStats->cellular);
818 inStats->cellular = NULL;
823 //===========================================================================================================================
824 // QueryStatsFreeList
825 //===========================================================================================================================
827 mDNSlocal void QueryStatsFreeList(QueryStats *inList)
831 while ((stats = inList) != NULL)
833 inList = stats->next;
834 QueryStatsFree(stats);
838 //===========================================================================================================================
840 //===========================================================================================================================
842 mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
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);
854 pSet = inForCell ? &inStats->cellular : &inStats->nonCellular;
855 if ((set = *pSet) == NULL)
857 set = (DNSHistSet *)calloc(1, sizeof(*set));
858 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
861 pHist = (inType == kDNSType_A) ? &set->histA : &set->histAAAA;
862 if ((hist = *pHist) == NULL)
864 hist = (DNSHist *)calloc(1, sizeof(*hist));
865 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
871 uint16_t * sendCountBins;
872 uint16_t * latencyBins;
873 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
875 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
877 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
878 increment_saturate(sendCountBins[i], UINT16_MAX);
880 if (inQuerySendCount > 0)
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);
889 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
890 increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
892 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
893 increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
895 err = mStatus_NoError;
901 //===========================================================================================================================
902 // QueryStatsGetDomainString
903 //===========================================================================================================================
905 mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats)
907 return (inStats->altDomainStr ? inStats->altDomainStr : inStats->domainStr);
910 //===========================================================================================================================
911 // QueryStatsDomainTest
912 //===========================================================================================================================
914 mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName)
916 const domainname * parentDomain;
919 if (inStats->domain[0] == 0) return (mDNStrue);
921 labelCount = CountLabels(inQueryName);
922 if (labelCount < inStats->labelCount) return (mDNSfalse);
924 parentDomain = SkipLeadingLabels(inQueryName, labelCount - inStats->labelCount);
925 return (SameDomainName(parentDomain, (const domainname *)inStats->domain));
928 //===========================================================================================================================
929 // QueryStatsHostnameTest
930 //===========================================================================================================================
932 mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName)
934 return (SameDomainName(inQueryName, (const domainname *)inStats->domain));
937 //===========================================================================================================================
938 // QueryStatsContentiCloudTest
939 //===========================================================================================================================
941 mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen);
943 #define kContentSuffixStr "-content"
945 mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName)
947 const mDNSu8 * const firstLabel = inQueryName->c;
948 const uint8_t * suffix;
949 const domainname * parentDomain;
952 (void) inStats; // Unused.
954 labelCount = CountLabels(inQueryName);
955 if (labelCount != 3) return (mDNSfalse);
957 suffix = LocateLabelSuffix(firstLabel, (const uint8_t *)kContentSuffixStr, sizeof_string(kContentSuffixStr));
958 if (suffix && (suffix > &firstLabel[1]))
960 parentDomain = SkipLeadingLabels(inQueryName, 1);
961 if (SameDomainName(parentDomain, (const domainname *)"\x6" "icloud" "\x3" "com"))
970 mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen)
976 const size_t labelLen = inLabel[0];
978 if (labelLen < inSuffixLen) return (NULL);
980 ptr = &inLabel[1 + labelLen - inSuffixLen];
983 for (len = inSuffixLen; len > 0; --len)
985 if (tolower(*lp) != tolower(*sp)) return (NULL);
993 //===========================================================================================================================
994 // QueryStatsCourierPushTest
995 //===========================================================================================================================
997 #define kCourierSuffixStr "-courier"
999 mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName)
1001 const mDNSu8 * const firstLabel = inQueryName->c;
1002 const uint8_t * suffix;
1003 const uint8_t * ptr;
1004 const domainname * parentDomain;
1007 (void) inStats; // Unused.
1009 labelCount = CountLabels(inQueryName);
1010 if (labelCount != 4) return (mDNSfalse);
1012 suffix = LocateLabelSuffix(firstLabel, (const mDNSu8 *)kCourierSuffixStr, sizeof_string(kCourierSuffixStr));
1013 if (suffix && (suffix > &firstLabel[1]))
1015 for (ptr = &firstLabel[1]; ptr < suffix; ++ptr)
1017 if (!isdigit(*ptr)) break;
1021 parentDomain = SkipLeadingLabels(inQueryName, 1);
1022 if (SameDomainName(parentDomain, (const domainname *)"\x4" "push" "\x5" "apple" "\x3" "com"))
1032 //===========================================================================================================================
1033 // ResolveStatsDomainCreate
1034 //===========================================================================================================================
1036 mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
1039 ResolveStatsDomain * obj;
1041 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
1042 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1044 obj->domainStr = inDomainStr;
1045 err = StringToDomainName(obj->domainStr, &obj->domain);
1046 require_noerr_quiet(err, exit);
1048 obj->labelCount = CountLabels((const domainname *)obj->domain);
1052 err = mStatus_NoError;
1055 if (obj) ResolveStatsDomainFree(obj);
1059 //===========================================================================================================================
1060 // ResolveStatsDomainFree
1061 //===========================================================================================================================
1063 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
1065 ResolveStatsHostname * hostname;
1067 ForgetMem(&inDomain->domain);
1068 while ((hostname = inDomain->hostnameList) != NULL)
1070 inDomain->hostnameList = hostname->next;
1071 ResolveStatsHostnameFree(hostname);
1076 //===========================================================================================================================
1077 // ResolveStatsDomainUpdate
1078 //===========================================================================================================================
1080 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
1083 ResolveStatsHostname ** p;
1084 ResolveStatsHostname * hostname;
1087 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
1089 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
1094 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1095 err = ResolveStatsHostnameCreate(inHostname, &hostname);
1096 require_noerr_quiet(err, exit);
1097 gResolveStatsObjCount++;
1101 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
1102 require_noerr_quiet(err, exit);
1104 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
1105 require_noerr_quiet(err, exit);
1111 //===========================================================================================================================
1112 // ResolveStatsHostnameCreate
1113 //===========================================================================================================================
1115 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
1118 ResolveStatsHostname * obj;
1121 nameLen = DomainNameLength(inName);
1122 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
1124 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
1125 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1127 memcpy(obj->name, inName, nameLen);
1130 err = mStatus_NoError;
1136 //===========================================================================================================================
1137 // ResolveStatsDomainCreateAWDVersion
1138 //===========================================================================================================================
1140 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
1143 AWDMDNSResponderResolveStatsDomain * domain;
1144 ResolveStatsHostname * hostname;
1145 AWDMDNSResponderResolveStatsHostname * awdHostname;
1148 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
1149 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1151 name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
1152 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1158 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
1160 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
1161 require_noerr_quiet(err, exit);
1163 [domain addHostname:awdHostname];
1164 [awdHostname release];
1168 *outDomain = domain;
1170 err = mStatus_NoError;
1177 //===========================================================================================================================
1178 // ResolveStatsHostnameFree
1179 //===========================================================================================================================
1181 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
1183 ResolveStatsIPv4AddrSet * addrV4;
1184 ResolveStatsIPv6Addr * addrV6;
1185 ResolveStatsNegAAAASet * negV6;
1187 while ((addrV4 = inHostname->addrV4List) != NULL)
1189 inHostname->addrV4List = addrV4->next;
1190 ResolveStatsIPv4AddrSetFree(addrV4);
1192 while ((addrV6 = inHostname->addrV6List) != NULL)
1194 inHostname->addrV6List = addrV6->next;
1195 ResolveStatsIPv6AddressFree(addrV6);
1197 while ((negV6 = inHostname->negV6List) != NULL)
1199 inHostname->negV6List = negV6->next;
1200 ResolveStatsNegAAAASetFree(negV6);
1205 //===========================================================================================================================
1206 // ResolveStatsHostnameUpdate
1207 //===========================================================================================================================
1209 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
1213 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
1215 ResolveStatsIPv4AddrSet ** p;
1216 ResolveStatsIPv4AddrSet * addrV4;
1218 IPv4AddrCounter * counter;
1220 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
1222 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1224 counter = &addrV4->counters[i];
1225 if (counter->count == 0) break;
1226 if (counter->serverID != inServerID) continue;
1227 if (inResp->type == kResponseType_NegA)
1229 if (counter->isNegative) break;
1233 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
1236 if (i < (int)countof(addrV4->counters)) break;
1240 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1241 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
1242 require_noerr_quiet(err, exit);
1243 gResolveStatsObjCount++;
1246 counter = &addrV4->counters[0];
1248 if (counter->count == 0)
1250 counter->serverID = inServerID;
1251 if (inResp->type == kResponseType_NegA)
1253 counter->isNegative = 1;
1257 counter->isNegative = 0;
1258 memcpy(counter->addrBytes, inResp->data, 4);
1261 increment_saturate(counter->count, UINT16_MAX);
1262 err = mStatus_NoError;
1264 else if (inResp->type == kResponseType_IPv6Addr)
1266 ResolveStatsIPv6Addr ** p;
1267 ResolveStatsIPv6Addr * addrV6;
1269 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
1271 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
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++;
1282 increment_saturate(addrV6->count, UINT16_MAX);
1283 err = mStatus_NoError;
1285 else if (inResp->type == kResponseType_NegAAAA)
1287 ResolveStatsNegAAAASet ** p;
1288 ResolveStatsNegAAAASet * negV6;
1290 NegAAAACounter * counter;
1292 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1294 for (i = 0; i < (int)countof(negV6->counters); ++i)
1296 counter = &negV6->counters[i];
1297 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1299 if (i < (int)countof(negV6->counters)) break;
1303 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1304 err = ResolveStatsNegAAAASetCreate(&negV6);
1305 require_noerr_quiet(err, exit);
1306 gResolveStatsObjCount++;
1309 counter = &negV6->counters[0];
1311 if (counter->count == 0) counter->serverID = inServerID;
1312 increment_saturate(counter->count, UINT16_MAX);
1313 err = mStatus_NoError;
1317 err = mStatus_Invalid;
1324 //===========================================================================================================================
1325 // ResolveStatsHostnameCreateAWDVersion
1326 //===========================================================================================================================
1328 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1331 AWDMDNSResponderResolveStatsHostname * hostname;
1333 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1335 ResolveStatsIPv4AddrSet * addrV4;
1336 ResolveStatsIPv6Addr * addrV6;
1337 ResolveStatsNegAAAASet * negV6;
1338 AWDMDNSResponderResolveStatsResult * result = nil;
1341 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1342 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1344 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1345 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1347 name = [[NSString alloc] initWithUTF8String:nameBuf];
1348 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1350 hostname.name = name;
1354 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1356 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1358 const IPv4AddrCounter * counter;
1361 counter = &addrV4->counters[i];
1362 if (counter->count == 0) break;
1364 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1365 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1367 if (counter->isNegative)
1369 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1373 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1374 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1376 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1377 result.data = addrBytes;
1378 [addrBytes release];
1380 result.count = counter->count;
1381 result.serverID = counter->serverID;
1383 [hostname addResult:result];
1389 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1393 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1394 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1396 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1397 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1399 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1400 result.count = addrV6->count;
1401 result.serverID = addrV6->serverID;
1402 result.data = addrBytes;
1404 [addrBytes release];
1406 [hostname addResult:result];
1411 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1413 for (i = 0; i < (int)countof(negV6->counters); ++i)
1415 const NegAAAACounter * counter;
1417 counter = &negV6->counters[i];
1418 if (counter->count == 0) break;
1420 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1421 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1423 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1424 result.count = counter->count;
1425 result.serverID = counter->serverID;
1427 [hostname addResult:result];
1433 *outHostname = hostname;
1435 err = mStatus_NoError;
1443 //===========================================================================================================================
1444 // ResolveStatsDNSServerCreate
1445 //===========================================================================================================================
1447 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1450 ResolveStatsDNSServer * obj;
1453 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
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);
1459 obj->isForCell = inForCell;
1460 if (inAddr->type == mDNSAddrType_IPv4)
1462 obj->isAddrV6 = mDNSfalse;
1463 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1467 obj->isAddrV6 = mDNStrue;
1468 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1472 err = mStatus_NoError;
1478 //===========================================================================================================================
1479 // ResolveStatsDNSServerFree
1480 //===========================================================================================================================
1482 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1487 //===========================================================================================================================
1488 // ResolveStatsDNSServerCreateAWDVersion
1489 //===========================================================================================================================
1491 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1494 AWDMDNSResponderResolveStatsDNSServer * server;
1495 NSData * addrBytes = nil;
1497 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1498 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1500 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1501 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1503 server.serverID = inServer->id;
1504 server.address = addrBytes;
1505 if (inServer->isForCell)
1507 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1511 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1514 *outServer = server;
1516 err = mStatus_NoError;
1519 [addrBytes release];
1524 //===========================================================================================================================
1525 // ResolveStatsIPv4AddrSetCreate
1526 //===========================================================================================================================
1528 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1531 ResolveStatsIPv4AddrSet * obj;
1533 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1534 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1537 err = mStatus_NoError;
1543 //===========================================================================================================================
1544 // ResolveStatsIPv4AddrSetFree
1545 //===========================================================================================================================
1547 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1552 //===========================================================================================================================
1553 // ResolveStatsIPv6AddressCreate
1554 //===========================================================================================================================
1556 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1559 ResolveStatsIPv6Addr * obj;
1561 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1562 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1564 obj->serverID = inServerID;
1565 memcpy(obj->addrBytes, inAddrBytes, 16);
1568 err = mStatus_NoError;
1574 //===========================================================================================================================
1575 // ResolveStatsIPv6AddressFree
1576 //===========================================================================================================================
1578 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1583 //===========================================================================================================================
1584 // ResolveStatsNegAAAASetCreate
1585 //===========================================================================================================================
1587 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1590 ResolveStatsNegAAAASet * obj;
1592 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1593 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1596 err = mStatus_NoError;
1602 //===========================================================================================================================
1603 // ResolveStatsNegAAAASetFree
1604 //===========================================================================================================================
1606 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1611 //===========================================================================================================================
1612 // ResolveStatsGetServerID
1613 //===========================================================================================================================
1615 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1618 ResolveStatsDNSServer ** p;
1619 ResolveStatsDNSServer * server;
1621 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1623 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1625 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1627 if (inServerAddr->type == mDNSAddrType_IPv4)
1629 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1633 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
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++;
1646 server->id = (uint8_t)gResolveStatsNextServerID++;
1647 server->next = gResolveStatsServerList;
1648 gResolveStatsServerList = server;
1650 else if (gResolveStatsServerList != server)
1653 server->next = gResolveStatsServerList;
1654 gResolveStatsServerList = server;
1657 *outServerID = server->id;
1658 err = mStatus_NoError;
1664 //===========================================================================================================================
1665 // DNSMessageSizeStatsCreate
1666 //===========================================================================================================================
1668 mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
1671 DNSMessageSizeStats * stats;
1673 stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
1674 require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
1677 err = mStatus_NoError;
1683 //===========================================================================================================================
1684 // DNSMessageSizeStatsFree
1685 //===========================================================================================================================
1687 mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
1692 //===========================================================================================================================
1693 // CreateQueryStatsList
1694 //===========================================================================================================================
1696 mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
1701 const QueryStatsArgs * args;
1702 const QueryStatsArgs * const end = kQueryStatsArgs + countof(kQueryStatsArgs);
1703 QueryStats * list = NULL;
1706 for (args = kQueryStatsArgs; args < end; ++args)
1708 err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
1709 require_noerr_quiet(err, exit);
1717 err = mStatus_NoError;
1720 QueryStatsFreeList(list);
1724 //===========================================================================================================================
1725 // CreateResolveStatsList
1726 //===========================================================================================================================
1728 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1732 ResolveStatsDomain * domain;
1733 ResolveStatsDomain ** p;
1734 ResolveStatsDomain * list = NULL;
1737 for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
1739 err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
1740 require_noerr_quiet(err, exit);
1748 err = mStatus_NoError;
1751 FreeResolveStatsList(list);
1755 //===========================================================================================================================
1756 // FreeResolveStatsList
1757 //===========================================================================================================================
1759 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1761 ResolveStatsDomain * domain;
1763 while ((domain = inList) != NULL)
1765 inList = domain->next;
1766 ResolveStatsDomainFree(domain);
1770 //===========================================================================================================================
1771 // FreeResolveStatsServerList
1772 //===========================================================================================================================
1774 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1776 ResolveStatsDNSServer * server;
1778 while ((server = inList) != NULL)
1780 inList = server->next;
1781 ResolveStatsDNSServerFree(server);
1785 //===========================================================================================================================
1787 //===========================================================================================================================
1789 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1795 case AWDMetricId_MDNSResponder_DNSStatistics:
1796 err = SubmitAWDMetricQueryStats();
1799 case AWDMetricId_MDNSResponder_ResolveStats:
1800 err = SubmitAWDMetricResolveStats();
1803 case AWDMetricId_MDNSResponder_ServicesStats:
1804 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
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;
1812 case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
1813 err = SubmitAWDMetricDNSMessageSizeStats();
1817 err = mStatus_UnsupportedErr;
1821 if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1825 //===========================================================================================================================
1826 // SubmitAWDMetricQueryStats
1827 //===========================================================================================================================
1829 mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
1830 mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
1832 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1837 QueryStats * statsList;
1838 QueryStats * newStatsList;
1839 AWDMetricContainer * container = nil;
1840 AWDMDNSResponderDNSStatistics * metric = nil;
1842 newStatsList = NULL;
1843 CreateQueryStatsList(&newStatsList);
1846 statsList = gQueryStatsList;
1847 gQueryStatsList = newStatsList;
1848 KQueueUnlock("SubmitAWDMetricQueryStats");
1850 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1851 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1853 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1854 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1856 while ((stats = statsList) != NULL)
1858 err = AddQueryStats(metric, stats);
1859 require_noerr_quiet(err, exit);
1861 statsList = stats->next;
1862 QueryStatsFree(stats);
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;
1872 [container release];
1873 QueryStatsFreeList(statsList);
1877 mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
1881 if (inStats->nonCellular)
1883 err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
1884 require_noerr_quiet(err, exit);
1886 if (inStats->cellular)
1888 err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
1889 require_noerr_quiet(err, exit);
1891 err = mStatus_NoError;
1897 mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1900 AWDDNSDomainStats * awdStats;
1904 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1905 require_noerr_quiet(err, exit);
1907 [inMetric addStats:awdStats];
1910 if (inSet->histAAAA)
1912 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1913 require_noerr_quiet(err, exit);
1915 [inMetric addStats:awdStats];
1918 err = mStatus_NoError;
1924 //===========================================================================================================================
1925 // SubmitAWDMetricResolveStats
1926 //===========================================================================================================================
1928 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
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;
1940 err = CreateResolveStatsList(&newResolveStatsList);
1941 require_noerr_quiet(err, exit);
1944 domainList = gResolveStatsList;
1945 serverList = gResolveStatsServerList;
1946 gResolveStatsList = newResolveStatsList;
1947 gResolveStatsServerList = NULL;
1948 gResolveStatsNextServerID = 0;
1949 gResolveStatsObjCount = 0;
1950 KQueueUnlock("SubmitAWDMetricResolveStats");
1952 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1953 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1955 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1956 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1958 while ((server = serverList) != NULL)
1960 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1962 serverList = server->next;
1963 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1964 ResolveStatsDNSServerFree(server);
1965 require_noerr_quiet(err, exit);
1967 [metric addServer:awdServer];
1968 [awdServer release];
1971 while ((domain = domainList) != NULL)
1973 AWDMDNSResponderResolveStatsDomain * awdDomain;
1975 domainList = domain->next;
1976 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1977 ResolveStatsDomainFree(domain);
1978 require_noerr_quiet(err, exit);
1980 [metric addDomain:awdDomain];
1981 [awdDomain release];
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;
1991 [container release];
1992 FreeResolveStatsList(domainList);
1993 FreeResolveStatsServerList(serverList);
1997 //===========================================================================================================================
1998 // SubmitAWDMetricDNSMessageSizeStats
1999 //===========================================================================================================================
2001 mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
2004 DNSMessageSizeStats * stats;
2005 DNSMessageSizeStats * newStats;
2006 AWDMetricContainer * container;
2007 AWDMDNSResponderDNSMessageSizeStats * metric = nil;
2011 DNSMessageSizeStatsCreate(&newStats);
2014 stats = gDNSMessageSizeStats;
2015 gDNSMessageSizeStats = newStats;
2016 KQueueUnlock("SubmitAWDMetricDNSMessageSizeStats");
2018 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSMessageSizeStats];
2019 require_action_quiet(container, exit, err = mStatus_UnknownErr);
2021 metric = [[AWDMDNSResponderDNSMessageSizeStatsSoft alloc] init];
2022 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
2027 uint32_t bins[Max(kQuerySizeBinCount, kResponseSizeBinCount)];
2029 // Set query size counts.
2031 binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
2032 [metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
2034 // Set response size counts.
2036 binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
2037 [metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
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;
2047 [container release];
2048 if (stats) DNSMessageSizeStatsFree(stats);
2052 //===========================================================================================================================
2053 // CreateAWDDNSDomainStats
2054 //===========================================================================================================================
2056 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
2059 AWDDNSDomainStats * awdStats = nil;
2060 NSString * domain = nil;
2062 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
2063 uint32_t latencyBins[kQueryStatsLatencyBinCount];
2065 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
2066 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
2068 domain = [[NSString alloc] initWithUTF8String:inDomain];
2069 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
2071 awdStats.domain = domain;
2072 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
2073 awdStats.recordType = inType;
2075 // Positively answered query send counts
2077 binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
2078 [awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
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.
2085 binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
2086 [awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2089 // Negatively answered query send counts
2091 binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2092 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2096 binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
2097 [awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2100 // Unanswered query send counts
2102 binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2103 [awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2107 binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
2108 [awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
2111 *outStats = awdStats;
2113 err = mStatus_NoError;
2121 //===========================================================================================================================
2123 //===========================================================================================================================
2125 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
2127 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
2128 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
2131 //===========================================================================================================================
2133 //===========================================================================================================================
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))
2140 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
2142 unsigned int totalAnswered;
2143 unsigned int totalNegAnswered;
2144 unsigned int totalUnanswered;
2148 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2150 totalAnswered += inHist->answeredQuerySendCountBins[i];
2153 totalNegAnswered = 0;
2154 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2156 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
2159 totalUnanswered = 0;
2160 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2162 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
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);
2174 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
2176 LogMsgNoIdent("--- Response times -----------");
2177 LogDNSHistLatencies(inHist->responseLatencyBins);
2180 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
2182 LogMsgNoIdent("--- Response times (NAQs) ----");
2183 LogDNSHistLatencies(inHist->negResponseLatencyBins);
2186 if (totalUnanswered > 0)
2188 LogMsgNoIdent("--- Unanswered query times ---");
2189 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
2193 //===========================================================================================================================
2194 // LogDNSHistSendCounts
2195 //===========================================================================================================================
2197 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
2204 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2206 total += inSendCountBins[i];
2211 uint32_t accumulator = 0;
2213 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2215 accumulator += inSendCountBins[i];
2216 if (i < (kQueryStatsSendCountBinCount - 1))
2218 snprintf(label, sizeof(label), "%2d ", i);
2222 snprintf(label, sizeof(label), "%2d+", i);
2224 LogStat(label, inSendCountBins[i], accumulator, total);
2225 if (accumulator == total) break;
2230 LogMsgNoIdent("No data.");
2234 //===========================================================================================================================
2235 // LogDNSHistLatencies
2236 //===========================================================================================================================
2238 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
2245 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2247 total += inLatencyBins[i];
2252 uint32_t accumulator = 0;
2254 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2256 accumulator += inLatencyBins[i];
2257 if (i < (int)countof(kResponseLatencyMsLimits))
2259 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
2263 snprintf(label, sizeof(label), "< ∞ ms");
2265 LogStat(label, inLatencyBins[i], accumulator, total);
2266 if (accumulator == total) break;
2271 LogMsgNoIdent("No data.");
2275 //===========================================================================================================================
2276 // LogDNSMessageSizeStats
2277 //===========================================================================================================================
2279 mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
2285 for (i = 0; i < inBinCount; ++i)
2292 uint32_t accumulator;
2293 unsigned int lower, upper;
2298 for (i = 0; i < inBinCount; ++i)
2300 accumulator += inBins[i];
2302 if (i < (inBinCount - 1))
2304 upper += inBinWidth;
2305 snprintf(label, sizeof(label), "%3u - %-3u", lower, upper);
2309 snprintf(label, sizeof(label), "%3u+ ", lower);
2311 LogStat(label, inBins[i], accumulator, total);
2312 if (accumulator == total) break;
2317 LogMsgNoIdent("No data.");
2321 //===========================================================================================================================
2322 // CopyHistogramBins
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 //===========================================================================================================================
2328 mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
2333 if (inBinCount == 0) return (0);
2336 for (i = 0; i < inBinCount; ++i)
2338 inDstBins[i] = inSrcBins[i];
2339 if (inDstBins[i] > 0) minCount = i + 1;
2344 #endif // TARGET_OS_IOS