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 kQueryStatsExpiredAnswerStateCount (ExpiredAnswer_EnumCount)
100 #define kResolveStatsMaxObjCount 2000
102 //===========================================================================================================================
104 //===========================================================================================================================
106 // Data structures for query stats.
108 typedef struct QueryStats QueryStats;
109 typedef struct DNSHistSet DNSHistSet;
110 typedef mDNSBool (*QueryNameTest_f)(const QueryStats *inStats, const domainname *inQueryName);
114 QueryStats * next; // Pointer to next domain stats in list.
115 const char * domainStr; // Domain (see below) as a C string.
116 uint8_t * domain; // Domain for which these stats are collected.
117 const char * altDomainStr; // Alt domain string to use in the AWD version of the stats instead of domainStr.
118 DNSHistSet * nonCellular; // Query stats for queries sent over non-cellular interfaces.
119 DNSHistSet * cellular; // Query stats for queries sent over cellular interfaces.
120 QueryNameTest_f test; // Function that tests whether a given query's stats belong based on the query name.
121 int labelCount; // Number of labels in domain name. Used for domain name comparisons.
122 mDNSBool terminal; // If true and test passes, then no other QueryStats on the list should be visited.
125 check_compile_time(sizeof(QueryStats) <= 64);
127 // DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
128 // <rdar://problem/23980546> MDNSResponder.proto update.
130 // answeredQuerySendCountBins
132 // 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
133 // was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times.
135 // unansweredQuerySendCountBins
137 // 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
138 // was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times.
140 // responseLatencyBins
142 // An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time
143 // interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are
144 // 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,
145 // 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
146 // 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞.
150 uint16_t unansweredQuerySendCountBins[kQueryStatsSendCountBinCount];
151 uint16_t unansweredQueryDurationBins[kQueryStatsLatencyBinCount];
152 uint16_t answeredQuerySendCountBins[kQueryStatsSendCountBinCount];
153 uint16_t responseLatencyBins[kQueryStatsLatencyBinCount];
154 uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
155 uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount];
156 uint16_t expiredAnswerStateBins[kQueryStatsExpiredAnswerStateCount];
160 check_compile_time(sizeof(DNSHist) <= 512);
161 check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
162 check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
163 check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
164 check_compile_time(countof_field(DNSHist, expiredAnswerStateBins) == (kQueryStatsExpiredAnswerStateCount));
166 // Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
167 // latency histogram bins to observe these time interval upper bounds.
169 static const mDNSu32 kResponseLatencyMsLimits[] =
172 10, 20, 30, 40, 50, 60, 70, 80, 90,
173 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
174 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
175 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
176 5000, 6000, 7000, 8000, 9000,
180 check_compile_time(countof(kResponseLatencyMsLimits) == 54);
181 check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1));
182 check_compile_time(countof_field(DNSHist, responseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
183 check_compile_time(countof_field(DNSHist, negResponseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
187 DNSHist * histA; // Histogram data for queries for A resource records.
188 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
193 const char * domainStr;
194 const char * altDomainStr;
195 QueryNameTest_f test;
200 // Data structures for resolve stats.
202 static const char * const kResolveStatsDomains[] =
210 check_compile_time(countof(kResolveStatsDomains) == 4);
212 typedef struct ResolveStatsDomain ResolveStatsDomain;
213 typedef struct ResolveStatsHostname ResolveStatsHostname;
214 typedef struct ResolveStatsDNSServer ResolveStatsDNSServer;
215 typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet;
216 typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr;
217 typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet;
219 struct ResolveStatsDomain
221 ResolveStatsDomain * next; // Next domain object in list.
222 const char * domainStr;
223 uint8_t * domain; // Domain for which these stats are collected.
224 int labelCount; // Number of labels in domain name. Used for domain name comparisons.
225 ResolveStatsHostname * hostnameList; // List of hostname objects in this domain.
228 check_compile_time(sizeof(ResolveStatsDomain) <= 40);
230 struct ResolveStatsHostname
232 ResolveStatsHostname * next; // Next hostname object in list.
233 ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved.
234 ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved.
235 ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects.
236 uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels.
239 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
241 struct ResolveStatsDNSServer
243 ResolveStatsDNSServer * next; // Next DNS server object in list.
244 uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects.
245 mDNSBool isForCell; // True if this DNS server belongs to a cellular interface.
246 mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4.
247 uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address.
250 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
254 uint16_t count; // Number of times this IPv4 address was provided as a resolution result.
255 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came.
257 uint8_t addrBytes[4]; // IPv4 address bytes.
261 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
263 struct ResolveStatsIPv4AddrSet
265 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
266 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
269 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
271 struct ResolveStatsIPv6Addr
273 ResolveStatsIPv6Addr * next; // Next IPv6 address object in list.
274 uint16_t count; // Number of times this IPv6 address was provided as a resolution result.
275 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came.
276 uint8_t addrBytes[16]; // IPv6 address bytes.
279 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
283 uint16_t count; // Number of times that a negative response was returned by a DNS server.
284 uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses.
288 check_compile_time(sizeof(NegAAAACounter) <= 4);
290 struct ResolveStatsNegAAAASet
292 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
293 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
296 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
300 kResponseType_IPv4Addr = 1,
301 kResponseType_IPv6Addr = 2,
302 kResponseType_NegA = 3,
303 kResponseType_NegAAAA = 4
310 const uint8_t * data;
314 // Data structures for DNS message size stats.
316 #define kQuerySizeBinWidth 16
317 #define kQuerySizeBinMax 512
318 #define kQuerySizeBinCount ((kQuerySizeBinMax / kQuerySizeBinWidth) + 1)
320 check_compile_time(kQuerySizeBinWidth > 0);
321 check_compile_time(kQuerySizeBinCount > 0);
322 check_compile_time((kQuerySizeBinMax % kQuerySizeBinWidth) == 0);
324 #define kResponseSizeBinWidth 16
325 #define kResponseSizeBinMax 512
326 #define kResponseSizeBinCount ((kResponseSizeBinMax / kResponseSizeBinWidth) + 1)
328 check_compile_time(kResponseSizeBinWidth > 0);
329 check_compile_time(kResponseSizeBinCount > 0);
330 check_compile_time((kResponseSizeBinMax % kResponseSizeBinWidth) == 0);
334 uint16_t querySizeBins[kQuerySizeBinCount];
335 uint16_t responseSizeBins[kResponseSizeBinCount];
337 } DNSMessageSizeStats;
339 check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
341 //===========================================================================================================================
343 //===========================================================================================================================
347 mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats);
348 mDNSlocal void QueryStatsFree(QueryStats *inStats);
349 mDNSlocal void QueryStatsFreeList(QueryStats *inList);
350 mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell);
351 mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats);
352 mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName);
353 mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName);
354 mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName);
355 mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName);
359 mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain);
360 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
361 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
362 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
364 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
365 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
366 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
367 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
369 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
370 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
371 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
373 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
374 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
376 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
377 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
379 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
380 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
381 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
383 // DNS message size stats
385 mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
386 mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
388 mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList);
389 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList);
390 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList);
391 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
392 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID);
393 mDNSlocal mStatus SubmitAWDMetricQueryStats(void);
394 mDNSlocal mStatus SubmitAWDMetricResolveStats(void);
395 mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void);
396 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
397 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
398 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
399 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
400 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
401 mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth);
403 mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
405 //===========================================================================================================================
407 //===========================================================================================================================
409 static AWDServerConnection * gAWDServerConnection = nil;
410 static QueryStats * gQueryStatsList = NULL;
411 static ResolveStatsDomain * gResolveStatsList = NULL;
412 static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
413 static unsigned int gResolveStatsNextServerID = 0;
414 static int gResolveStatsObjCount = 0;
415 static DNSMessageSizeStats * gDNSMessageSizeStats = NULL;
417 // Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
419 static const QueryStatsArgs kQueryStatsArgs[] =
421 { ".", NULL, QueryStatsDomainTest, mDNSfalse },
422 { "", "alt:*-courier.push.apple.com.", QueryStatsCourierPushTest, mDNSfalse },
423 { "apple.com.", NULL, QueryStatsDomainTest, mDNStrue },
424 { "gateway.icloud.com.", "alt:gateway.icloud.com", QueryStatsHostnameTest, mDNSfalse },
425 { "", "alt:*-content.icloud.com.", QueryStatsContentiCloudTest, mDNSfalse },
426 { "icloud.com.", NULL, QueryStatsDomainTest, mDNStrue },
427 { "mzstatic.com.", NULL, QueryStatsDomainTest, mDNStrue },
428 { "google.com.", NULL, QueryStatsDomainTest, mDNStrue },
429 { "baidu.com.", NULL, QueryStatsDomainTest, mDNStrue },
430 { "yahoo.com.", NULL, QueryStatsDomainTest, mDNStrue },
431 { "qq.com.", NULL, QueryStatsDomainTest, mDNStrue }
434 check_compile_time(countof(kQueryStatsArgs) == 11);
436 //===========================================================================================================================
438 //===========================================================================================================================
440 mStatus MetricsInit(void)
444 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
445 initWithComponentId: AWDComponentId_MDNSResponder
446 andBlockOnConfiguration: NO];
448 if (gAWDServerConnection)
450 [gAWDServerConnection
451 registerQueriableMetricCallback: ^(UInt32 inMetricID)
453 SubmitAWDMetric(inMetricID);
455 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
457 [gAWDServerConnection
458 registerQueriableMetricCallback: ^(UInt32 inMetricID)
460 SubmitAWDMetric(inMetricID);
462 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
464 [gAWDServerConnection
465 registerQueriableMetricCallback: ^(UInt32 inMetricID)
467 SubmitAWDMetric(inMetricID);
469 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
471 [gAWDServerConnection
472 registerQueriableMetricCallback: ^(UInt32 inMetricID)
474 SubmitAWDMetric(inMetricID);
476 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSMessageSizeStats];
480 LogMsg("MetricsInit: failed to create AWD server connection.");
484 if( gAWDServerConnection )
486 CreateQueryStatsList(&gQueryStatsList);
487 CreateResolveStatsList(&gResolveStatsList);
488 DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
491 return (mStatus_NoError);
494 //===========================================================================================================================
495 // MetricsUpdateDNSQueryStats
496 //===========================================================================================================================
498 mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell)
503 require_quiet(gAWDServerConnection, exit);
504 require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
506 for (stats = gQueryStatsList; stats; stats = stats->next)
508 match = stats->test(stats, inQueryName);
511 QueryStatsUpdate(stats, inType, inRR, inSendCount, inExpiredAnswerState, inLatencyMs, inForCell);
512 if (stats->terminal) break;
520 //===========================================================================================================================
521 // MetricsUpdateDNSResolveStats
522 //===========================================================================================================================
524 mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
526 ResolveStatsDomain * domainStats;
529 mDNSBool isQueryInDomain;
531 int skipCountLast = -1;
533 const domainname * queryParentDomain;
536 require_quiet(gAWDServerConnection, exit);
537 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
538 require_quiet(inRR->rDNSServer, exit);
540 queryLabelCount = CountLabels(inQueryName);
542 for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
544 isQueryInDomain = mDNSfalse;
545 skipCount = queryLabelCount - domainStats->labelCount;
548 if (skipCount != skipCountLast)
550 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
551 skipCountLast = skipCount;
553 isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
555 if (!isQueryInDomain) continue;
557 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
558 if (hostnameLen >= sizeof(hostname.c)) continue;
560 memcpy(hostname.c, inQueryName->c, hostnameLen);
561 hostname.c[hostnameLen] = 0;
563 if (inRR->RecordType == kDNSRecordTypePacketNegative)
565 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
566 response.data = NULL;
570 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
571 response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
573 ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
580 //===========================================================================================================================
581 // MetricsUpdateDNSQuerySize
582 //===========================================================================================================================
584 mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
586 mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
588 if (!gDNSMessageSizeStats) return;
589 UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
592 mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
596 if (inSize == 0) return;
597 i = (inSize - 1) / inBinWidth;
598 if (i >= inBinCount) i = inBinCount - 1;
599 increment_saturate(inBins[i], UINT16_MAX);
602 //===========================================================================================================================
603 // MetricsUpdateDNSResponseSize
604 //===========================================================================================================================
606 mDNSexport void MetricsUpdateDNSResponseSize(mDNSu32 inSize)
608 if (!gDNSMessageSizeStats) return;
609 UpdateMessageSizeCounts(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth, inSize);
612 //===========================================================================================================================
614 //===========================================================================================================================
616 mDNSexport void LogMetrics(void)
619 const ResolveStatsDomain * domain;
620 const ResolveStatsHostname * hostname;
621 const ResolveStatsDNSServer * server;
622 const ResolveStatsIPv4AddrSet * addrV4;
623 const ResolveStatsIPv6Addr * addrV6;
624 const ResolveStatsNegAAAASet * negV6;
627 unsigned int serverID;
628 int serverObjCount = 0;
629 int hostnameObjCount = 0;
630 int addrObjCount = 0;
632 LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
633 LogMsgNoIdent("---- DNS query stats by domain -----");
635 for (stats = gQueryStatsList; stats; stats = stats->next)
637 if (!stats->nonCellular && !stats->cellular)
639 LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
642 if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
643 if (stats->cellular) LogDNSHistSet(stats->cellular, QueryStatsGetDomainString(stats), mDNStrue);
646 LogMsgNoIdent("---- DNS resolve stats by domain -----");
648 LogMsgNoIdent("Servers:");
649 for (server = gResolveStatsServerList; server; server = server->next)
652 LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
653 server->id, server->isForCell ? " C" : "NC", server->addrBytes);
656 for (domain = gResolveStatsList; domain; domain = domain->next)
659 for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
660 hostnameObjCount += hostnameCount;
662 LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
664 for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
666 LogMsgNoIdent(" %##s", hostname->name);
667 for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
669 for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
671 if (serverID == 0) addrObjCount++;
672 for (i = 0; i < (int)countof(addrV4->counters); ++i)
674 const IPv4AddrCounter * counter;
676 counter = &addrV4->counters[i];
677 if (counter->count == 0) break;
678 if (counter->serverID == serverID)
680 if (counter->isNegative)
682 LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
686 LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
691 for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
693 if (serverID == 0) addrObjCount++;
694 if (addrV6->serverID == serverID)
696 LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
699 for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
701 if (serverID == 0) addrObjCount++;
702 for (i = 0; i < (int)countof(negV6->counters); ++i)
704 const NegAAAACounter * counter;
706 counter = &negV6->counters[i];
707 if (counter->count == 0) break;
708 if (counter->serverID == serverID)
710 LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
717 LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
718 serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
720 LogMsgNoIdent("---- Num of Services Registered -----");
721 LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
722 curr_num_regservices, max_num_regservices);
724 if (gDNSMessageSizeStats)
726 LogMsgNoIdent("---- DNS query size stats ---");
727 LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
729 LogMsgNoIdent("-- DNS response size stats --");
730 LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
734 LogMsgNoIdent("No DNS message size stats.");
738 //===========================================================================================================================
740 //===========================================================================================================================
742 mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName);
744 mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats)
749 obj = (QueryStats *)calloc(1, sizeof(*obj));
750 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
752 obj->domainStr = inDomainStr;
753 err = StringToDomainName(obj->domainStr, &obj->domain);
754 require_noerr_quiet(err, exit);
756 obj->altDomainStr = inAltDomainStr;
758 obj->labelCount = CountLabels((const domainname *)obj->domain);
759 obj->terminal = inTerminal;
763 err = mStatus_NoError;
766 if (obj) QueryStatsFree(obj);
770 mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName)
773 uint8_t * domainPtr = NULL;
778 if (strcmp(inString, ".") == 0)
784 ptr = MakeDomainNameFromDNSNameString(&domain, inString);
785 require_action_quiet(ptr, exit, err = mStatus_BadParamErr);
787 domainLen = DomainNameLength(&domain);
789 domainPtr = (uint8_t *)malloc(domainLen);
790 require_action_quiet(domainPtr, exit, err = mStatus_NoMemoryErr);
792 memcpy(domainPtr, domain.c, domainLen);
794 *outDomainName = domainPtr;
796 err = mStatus_NoError;
802 //===========================================================================================================================
804 //===========================================================================================================================
806 mDNSlocal void QueryStatsFree(QueryStats *inStats)
808 ForgetMem(&inStats->domain);
809 if (inStats->nonCellular)
811 ForgetMem(&inStats->nonCellular->histA);
812 ForgetMem(&inStats->nonCellular->histAAAA);
813 free(inStats->nonCellular);
814 inStats->nonCellular = NULL;
816 if (inStats->cellular)
818 ForgetMem(&inStats->cellular->histA);
819 ForgetMem(&inStats->cellular->histAAAA);
820 free(inStats->cellular);
821 inStats->cellular = NULL;
826 //===========================================================================================================================
827 // QueryStatsFreeList
828 //===========================================================================================================================
830 mDNSlocal void QueryStatsFreeList(QueryStats *inList)
834 while ((stats = inList) != NULL)
836 inList = stats->next;
837 QueryStatsFree(stats);
841 //===========================================================================================================================
843 //===========================================================================================================================
845 mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell)
854 require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError);
855 require_action_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit, err = mStatus_NoError);
857 pSet = inForCell ? &inStats->cellular : &inStats->nonCellular;
858 if ((set = *pSet) == NULL)
860 set = (DNSHistSet *)calloc(1, sizeof(*set));
861 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
864 pHist = (inType == kDNSType_A) ? &set->histA : &set->histAAAA;
865 if ((hist = *pHist) == NULL)
867 hist = (DNSHist *)calloc(1, sizeof(*hist));
868 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
874 uint16_t * sendCountBins;
875 uint16_t * latencyBins;
876 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
878 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
880 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
881 increment_saturate(sendCountBins[i], UINT16_MAX);
883 if (inQuerySendCount > 0)
885 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
886 latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
887 increment_saturate(latencyBins[i], UINT16_MAX);
892 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
893 increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
895 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
896 increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
898 increment_saturate(hist->expiredAnswerStateBins[Min(inExpiredAnswerState, (kQueryStatsExpiredAnswerStateCount-1))], UINT16_MAX);
899 err = mStatus_NoError;
905 //===========================================================================================================================
906 // QueryStatsGetDomainString
907 //===========================================================================================================================
909 mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats)
911 return (inStats->altDomainStr ? inStats->altDomainStr : inStats->domainStr);
914 //===========================================================================================================================
915 // QueryStatsDomainTest
916 //===========================================================================================================================
918 mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName)
920 const domainname * parentDomain;
923 if (inStats->domain[0] == 0) return (mDNStrue);
925 labelCount = CountLabels(inQueryName);
926 if (labelCount < inStats->labelCount) return (mDNSfalse);
928 parentDomain = SkipLeadingLabels(inQueryName, labelCount - inStats->labelCount);
929 return (SameDomainName(parentDomain, (const domainname *)inStats->domain));
932 //===========================================================================================================================
933 // QueryStatsHostnameTest
934 //===========================================================================================================================
936 mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName)
938 return (SameDomainName(inQueryName, (const domainname *)inStats->domain));
941 //===========================================================================================================================
942 // QueryStatsContentiCloudTest
943 //===========================================================================================================================
945 mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen);
947 #define kContentSuffixStr "-content"
949 mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName)
951 const mDNSu8 * const firstLabel = inQueryName->c;
952 const uint8_t * suffix;
953 const domainname * parentDomain;
956 (void) inStats; // Unused.
958 labelCount = CountLabels(inQueryName);
959 if (labelCount != 3) return (mDNSfalse);
961 suffix = LocateLabelSuffix(firstLabel, (const uint8_t *)kContentSuffixStr, sizeof_string(kContentSuffixStr));
962 if (suffix && (suffix > &firstLabel[1]))
964 parentDomain = SkipLeadingLabels(inQueryName, 1);
965 if (SameDomainName(parentDomain, (const domainname *)"\x6" "icloud" "\x3" "com"))
974 mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen)
980 const size_t labelLen = inLabel[0];
982 if (labelLen < inSuffixLen) return (NULL);
984 ptr = &inLabel[1 + labelLen - inSuffixLen];
987 for (len = inSuffixLen; len > 0; --len)
989 if (tolower(*lp) != tolower(*sp)) return (NULL);
997 //===========================================================================================================================
998 // QueryStatsCourierPushTest
999 //===========================================================================================================================
1001 #define kCourierSuffixStr "-courier"
1003 mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName)
1005 const mDNSu8 * const firstLabel = inQueryName->c;
1006 const uint8_t * suffix;
1007 const uint8_t * ptr;
1008 const domainname * parentDomain;
1011 (void) inStats; // Unused.
1013 labelCount = CountLabels(inQueryName);
1014 if (labelCount != 4) return (mDNSfalse);
1016 suffix = LocateLabelSuffix(firstLabel, (const mDNSu8 *)kCourierSuffixStr, sizeof_string(kCourierSuffixStr));
1017 if (suffix && (suffix > &firstLabel[1]))
1019 for (ptr = &firstLabel[1]; ptr < suffix; ++ptr)
1021 if (!isdigit(*ptr)) break;
1025 parentDomain = SkipLeadingLabels(inQueryName, 1);
1026 if (SameDomainName(parentDomain, (const domainname *)"\x4" "push" "\x5" "apple" "\x3" "com"))
1036 //===========================================================================================================================
1037 // ResolveStatsDomainCreate
1038 //===========================================================================================================================
1040 mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
1043 ResolveStatsDomain * obj;
1045 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
1046 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1048 obj->domainStr = inDomainStr;
1049 err = StringToDomainName(obj->domainStr, &obj->domain);
1050 require_noerr_quiet(err, exit);
1052 obj->labelCount = CountLabels((const domainname *)obj->domain);
1056 err = mStatus_NoError;
1059 if (obj) ResolveStatsDomainFree(obj);
1063 //===========================================================================================================================
1064 // ResolveStatsDomainFree
1065 //===========================================================================================================================
1067 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
1069 ResolveStatsHostname * hostname;
1071 ForgetMem(&inDomain->domain);
1072 while ((hostname = inDomain->hostnameList) != NULL)
1074 inDomain->hostnameList = hostname->next;
1075 ResolveStatsHostnameFree(hostname);
1080 //===========================================================================================================================
1081 // ResolveStatsDomainUpdate
1082 //===========================================================================================================================
1084 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
1087 ResolveStatsHostname ** p;
1088 ResolveStatsHostname * hostname;
1091 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
1093 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
1098 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1099 err = ResolveStatsHostnameCreate(inHostname, &hostname);
1100 require_noerr_quiet(err, exit);
1101 gResolveStatsObjCount++;
1105 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
1106 require_noerr_quiet(err, exit);
1108 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
1109 require_noerr_quiet(err, exit);
1115 //===========================================================================================================================
1116 // ResolveStatsHostnameCreate
1117 //===========================================================================================================================
1119 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
1122 ResolveStatsHostname * obj;
1125 nameLen = DomainNameLength(inName);
1126 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
1128 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
1129 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1131 memcpy(obj->name, inName, nameLen);
1134 err = mStatus_NoError;
1140 //===========================================================================================================================
1141 // ResolveStatsDomainCreateAWDVersion
1142 //===========================================================================================================================
1144 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
1147 AWDMDNSResponderResolveStatsDomain * domain;
1148 ResolveStatsHostname * hostname;
1149 AWDMDNSResponderResolveStatsHostname * awdHostname;
1152 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
1153 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1155 name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
1156 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1162 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
1164 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
1165 require_noerr_quiet(err, exit);
1167 [domain addHostname:awdHostname];
1168 [awdHostname release];
1172 *outDomain = domain;
1174 err = mStatus_NoError;
1181 //===========================================================================================================================
1182 // ResolveStatsHostnameFree
1183 //===========================================================================================================================
1185 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
1187 ResolveStatsIPv4AddrSet * addrV4;
1188 ResolveStatsIPv6Addr * addrV6;
1189 ResolveStatsNegAAAASet * negV6;
1191 while ((addrV4 = inHostname->addrV4List) != NULL)
1193 inHostname->addrV4List = addrV4->next;
1194 ResolveStatsIPv4AddrSetFree(addrV4);
1196 while ((addrV6 = inHostname->addrV6List) != NULL)
1198 inHostname->addrV6List = addrV6->next;
1199 ResolveStatsIPv6AddressFree(addrV6);
1201 while ((negV6 = inHostname->negV6List) != NULL)
1203 inHostname->negV6List = negV6->next;
1204 ResolveStatsNegAAAASetFree(negV6);
1209 //===========================================================================================================================
1210 // ResolveStatsHostnameUpdate
1211 //===========================================================================================================================
1213 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
1217 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
1219 ResolveStatsIPv4AddrSet ** p;
1220 ResolveStatsIPv4AddrSet * addrV4;
1222 IPv4AddrCounter * counter;
1224 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
1226 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1228 counter = &addrV4->counters[i];
1229 if (counter->count == 0) break;
1230 if (counter->serverID != inServerID) continue;
1231 if (inResp->type == kResponseType_NegA)
1233 if (counter->isNegative) break;
1237 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
1240 if (i < (int)countof(addrV4->counters)) break;
1244 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1245 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
1246 require_noerr_quiet(err, exit);
1247 gResolveStatsObjCount++;
1250 counter = &addrV4->counters[0];
1252 if (counter->count == 0)
1254 counter->serverID = inServerID;
1255 if (inResp->type == kResponseType_NegA)
1257 counter->isNegative = 1;
1261 counter->isNegative = 0;
1262 memcpy(counter->addrBytes, inResp->data, 4);
1265 increment_saturate(counter->count, UINT16_MAX);
1266 err = mStatus_NoError;
1268 else if (inResp->type == kResponseType_IPv6Addr)
1270 ResolveStatsIPv6Addr ** p;
1271 ResolveStatsIPv6Addr * addrV6;
1273 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
1275 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
1279 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1280 err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
1281 require_noerr_quiet(err, exit);
1282 gResolveStatsObjCount++;
1286 increment_saturate(addrV6->count, UINT16_MAX);
1287 err = mStatus_NoError;
1289 else if (inResp->type == kResponseType_NegAAAA)
1291 ResolveStatsNegAAAASet ** p;
1292 ResolveStatsNegAAAASet * negV6;
1294 NegAAAACounter * counter;
1296 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1298 for (i = 0; i < (int)countof(negV6->counters); ++i)
1300 counter = &negV6->counters[i];
1301 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1303 if (i < (int)countof(negV6->counters)) break;
1307 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1308 err = ResolveStatsNegAAAASetCreate(&negV6);
1309 require_noerr_quiet(err, exit);
1310 gResolveStatsObjCount++;
1313 counter = &negV6->counters[0];
1315 if (counter->count == 0) counter->serverID = inServerID;
1316 increment_saturate(counter->count, UINT16_MAX);
1317 err = mStatus_NoError;
1321 err = mStatus_Invalid;
1328 //===========================================================================================================================
1329 // ResolveStatsHostnameCreateAWDVersion
1330 //===========================================================================================================================
1332 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1335 AWDMDNSResponderResolveStatsHostname * hostname;
1337 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1339 ResolveStatsIPv4AddrSet * addrV4;
1340 ResolveStatsIPv6Addr * addrV6;
1341 ResolveStatsNegAAAASet * negV6;
1342 AWDMDNSResponderResolveStatsResult * result = nil;
1345 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1346 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1348 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1349 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1351 name = [[NSString alloc] initWithUTF8String:nameBuf];
1352 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1354 hostname.name = name;
1358 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1360 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1362 const IPv4AddrCounter * counter;
1365 counter = &addrV4->counters[i];
1366 if (counter->count == 0) break;
1368 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1369 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1371 if (counter->isNegative)
1373 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1377 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1378 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1380 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1381 result.data = addrBytes;
1382 [addrBytes release];
1384 result.count = counter->count;
1385 result.serverID = counter->serverID;
1387 [hostname addResult:result];
1393 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1397 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1398 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1400 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1401 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1403 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1404 result.count = addrV6->count;
1405 result.serverID = addrV6->serverID;
1406 result.data = addrBytes;
1408 [addrBytes release];
1410 [hostname addResult:result];
1415 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1417 for (i = 0; i < (int)countof(negV6->counters); ++i)
1419 const NegAAAACounter * counter;
1421 counter = &negV6->counters[i];
1422 if (counter->count == 0) break;
1424 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1425 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1427 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1428 result.count = counter->count;
1429 result.serverID = counter->serverID;
1431 [hostname addResult:result];
1437 *outHostname = hostname;
1439 err = mStatus_NoError;
1447 //===========================================================================================================================
1448 // ResolveStatsDNSServerCreate
1449 //===========================================================================================================================
1451 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1454 ResolveStatsDNSServer * obj;
1457 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1459 addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
1460 obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
1461 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1463 obj->isForCell = inForCell;
1464 if (inAddr->type == mDNSAddrType_IPv4)
1466 obj->isAddrV6 = mDNSfalse;
1467 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1471 obj->isAddrV6 = mDNStrue;
1472 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1476 err = mStatus_NoError;
1482 //===========================================================================================================================
1483 // ResolveStatsDNSServerFree
1484 //===========================================================================================================================
1486 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1491 //===========================================================================================================================
1492 // ResolveStatsDNSServerCreateAWDVersion
1493 //===========================================================================================================================
1495 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1498 AWDMDNSResponderResolveStatsDNSServer * server;
1499 NSData * addrBytes = nil;
1501 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1502 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1504 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1505 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1507 server.serverID = inServer->id;
1508 server.address = addrBytes;
1509 if (inServer->isForCell)
1511 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1515 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1518 *outServer = server;
1520 err = mStatus_NoError;
1523 [addrBytes release];
1528 //===========================================================================================================================
1529 // ResolveStatsIPv4AddrSetCreate
1530 //===========================================================================================================================
1532 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1535 ResolveStatsIPv4AddrSet * obj;
1537 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1538 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1541 err = mStatus_NoError;
1547 //===========================================================================================================================
1548 // ResolveStatsIPv4AddrSetFree
1549 //===========================================================================================================================
1551 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1556 //===========================================================================================================================
1557 // ResolveStatsIPv6AddressCreate
1558 //===========================================================================================================================
1560 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1563 ResolveStatsIPv6Addr * obj;
1565 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1566 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1568 obj->serverID = inServerID;
1569 memcpy(obj->addrBytes, inAddrBytes, 16);
1572 err = mStatus_NoError;
1578 //===========================================================================================================================
1579 // ResolveStatsIPv6AddressFree
1580 //===========================================================================================================================
1582 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1587 //===========================================================================================================================
1588 // ResolveStatsNegAAAASetCreate
1589 //===========================================================================================================================
1591 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1594 ResolveStatsNegAAAASet * obj;
1596 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1597 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1600 err = mStatus_NoError;
1606 //===========================================================================================================================
1607 // ResolveStatsNegAAAASetFree
1608 //===========================================================================================================================
1610 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1615 //===========================================================================================================================
1616 // ResolveStatsGetServerID
1617 //===========================================================================================================================
1619 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1622 ResolveStatsDNSServer ** p;
1623 ResolveStatsDNSServer * server;
1625 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1627 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1629 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1631 if (inServerAddr->type == mDNSAddrType_IPv4)
1633 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1637 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1644 require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
1645 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1646 err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
1647 require_noerr_quiet(err, exit);
1648 gResolveStatsObjCount++;
1650 server->id = (uint8_t)gResolveStatsNextServerID++;
1651 server->next = gResolveStatsServerList;
1652 gResolveStatsServerList = server;
1654 else if (gResolveStatsServerList != server)
1657 server->next = gResolveStatsServerList;
1658 gResolveStatsServerList = server;
1661 *outServerID = server->id;
1662 err = mStatus_NoError;
1668 //===========================================================================================================================
1669 // DNSMessageSizeStatsCreate
1670 //===========================================================================================================================
1672 mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
1675 DNSMessageSizeStats * stats;
1677 stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
1678 require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
1681 err = mStatus_NoError;
1687 //===========================================================================================================================
1688 // DNSMessageSizeStatsFree
1689 //===========================================================================================================================
1691 mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
1696 //===========================================================================================================================
1697 // CreateQueryStatsList
1698 //===========================================================================================================================
1700 mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
1705 const QueryStatsArgs * args;
1706 const QueryStatsArgs * const end = kQueryStatsArgs + countof(kQueryStatsArgs);
1707 QueryStats * list = NULL;
1710 for (args = kQueryStatsArgs; args < end; ++args)
1712 err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
1713 require_noerr_quiet(err, exit);
1721 err = mStatus_NoError;
1724 QueryStatsFreeList(list);
1728 //===========================================================================================================================
1729 // CreateResolveStatsList
1730 //===========================================================================================================================
1732 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1736 ResolveStatsDomain * domain;
1737 ResolveStatsDomain ** p;
1738 ResolveStatsDomain * list = NULL;
1741 for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
1743 err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
1744 require_noerr_quiet(err, exit);
1752 err = mStatus_NoError;
1755 FreeResolveStatsList(list);
1759 //===========================================================================================================================
1760 // FreeResolveStatsList
1761 //===========================================================================================================================
1763 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1765 ResolveStatsDomain * domain;
1767 while ((domain = inList) != NULL)
1769 inList = domain->next;
1770 ResolveStatsDomainFree(domain);
1774 //===========================================================================================================================
1775 // FreeResolveStatsServerList
1776 //===========================================================================================================================
1778 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1780 ResolveStatsDNSServer * server;
1782 while ((server = inList) != NULL)
1784 inList = server->next;
1785 ResolveStatsDNSServerFree(server);
1789 //===========================================================================================================================
1791 //===========================================================================================================================
1793 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1799 case AWDMetricId_MDNSResponder_DNSStatistics:
1800 err = SubmitAWDMetricQueryStats();
1803 case AWDMetricId_MDNSResponder_ResolveStats:
1804 err = SubmitAWDMetricResolveStats();
1807 case AWDMetricId_MDNSResponder_ServicesStats:
1808 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
1810 // reset the no of max services since we want to collect the max no of services registered per AWD submission period
1811 max_num_regservices = curr_num_regservices;
1812 KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
1813 err = mStatus_NoError;
1816 case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
1817 err = SubmitAWDMetricDNSMessageSizeStats();
1821 err = mStatus_UnsupportedErr;
1825 if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1829 //===========================================================================================================================
1830 // SubmitAWDMetricQueryStats
1831 //===========================================================================================================================
1833 mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
1834 mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
1836 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1841 QueryStats * statsList;
1842 QueryStats * newStatsList;
1843 AWDMetricContainer * container = nil;
1844 AWDMDNSResponderDNSStatistics * metric = nil;
1846 newStatsList = NULL;
1847 CreateQueryStatsList(&newStatsList);
1850 statsList = gQueryStatsList;
1851 gQueryStatsList = newStatsList;
1852 KQueueUnlock("SubmitAWDMetricQueryStats");
1854 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1855 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1857 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1858 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1860 while ((stats = statsList) != NULL)
1862 err = AddQueryStats(metric, stats);
1863 require_noerr_quiet(err, exit);
1865 statsList = stats->next;
1866 QueryStatsFree(stats);
1869 container.metric = metric;
1870 success = [gAWDServerConnection submitMetric:container];
1871 LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
1872 err = success ? mStatus_NoError : mStatus_UnknownErr;
1876 [container release];
1877 QueryStatsFreeList(statsList);
1881 mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
1885 if (inStats->nonCellular)
1887 err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
1888 require_noerr_quiet(err, exit);
1890 if (inStats->cellular)
1892 err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
1893 require_noerr_quiet(err, exit);
1895 err = mStatus_NoError;
1901 mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1904 AWDDNSDomainStats * awdStats;
1908 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1909 require_noerr_quiet(err, exit);
1911 [inMetric addStats:awdStats];
1914 if (inSet->histAAAA)
1916 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1917 require_noerr_quiet(err, exit);
1919 [inMetric addStats:awdStats];
1922 err = mStatus_NoError;
1928 //===========================================================================================================================
1929 // SubmitAWDMetricResolveStats
1930 //===========================================================================================================================
1932 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1935 ResolveStatsDomain * newResolveStatsList;
1936 ResolveStatsDomain * domainList = NULL;
1937 ResolveStatsDNSServer * serverList = NULL;
1938 AWDMetricContainer * container = nil;
1939 AWDMDNSResponderResolveStats * metric = nil;
1940 ResolveStatsDNSServer * server;
1941 ResolveStatsDomain * domain;
1944 err = CreateResolveStatsList(&newResolveStatsList);
1945 require_noerr_quiet(err, exit);
1948 domainList = gResolveStatsList;
1949 serverList = gResolveStatsServerList;
1950 gResolveStatsList = newResolveStatsList;
1951 gResolveStatsServerList = NULL;
1952 gResolveStatsNextServerID = 0;
1953 gResolveStatsObjCount = 0;
1954 KQueueUnlock("SubmitAWDMetricResolveStats");
1956 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1957 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1959 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1960 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1962 while ((server = serverList) != NULL)
1964 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1966 serverList = server->next;
1967 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1968 ResolveStatsDNSServerFree(server);
1969 require_noerr_quiet(err, exit);
1971 [metric addServer:awdServer];
1972 [awdServer release];
1975 while ((domain = domainList) != NULL)
1977 AWDMDNSResponderResolveStatsDomain * awdDomain;
1979 domainList = domain->next;
1980 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1981 ResolveStatsDomainFree(domain);
1982 require_noerr_quiet(err, exit);
1984 [metric addDomain:awdDomain];
1985 [awdDomain release];
1988 container.metric = metric;
1989 success = [gAWDServerConnection submitMetric:container];
1990 LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed");
1991 err = success ? mStatus_NoError : mStatus_UnknownErr;
1995 [container release];
1996 FreeResolveStatsList(domainList);
1997 FreeResolveStatsServerList(serverList);
2001 //===========================================================================================================================
2002 // SubmitAWDMetricDNSMessageSizeStats
2003 //===========================================================================================================================
2005 mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
2008 DNSMessageSizeStats * stats;
2009 DNSMessageSizeStats * newStats;
2010 AWDMetricContainer * container;
2011 AWDMDNSResponderDNSMessageSizeStats * metric = nil;
2015 DNSMessageSizeStatsCreate(&newStats);
2018 stats = gDNSMessageSizeStats;
2019 gDNSMessageSizeStats = newStats;
2020 KQueueUnlock("SubmitAWDMetricDNSMessageSizeStats");
2022 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSMessageSizeStats];
2023 require_action_quiet(container, exit, err = mStatus_UnknownErr);
2025 metric = [[AWDMDNSResponderDNSMessageSizeStatsSoft alloc] init];
2026 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
2031 uint32_t bins[Max(kQuerySizeBinCount, kResponseSizeBinCount)];
2033 // Set query size counts.
2035 binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
2036 [metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
2038 // Set response size counts.
2040 binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
2041 [metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
2044 container.metric = metric;
2045 success = [gAWDServerConnection submitMetric:container];
2046 LogMsg("SubmitAWDMetricDNSMessageSizeStats: metric submission %s.", success ? "succeeded" : "failed");
2047 err = success ? mStatus_NoError : mStatus_UnknownErr;
2051 [container release];
2052 if (stats) DNSMessageSizeStatsFree(stats);
2056 //===========================================================================================================================
2057 // CreateAWDDNSDomainStats
2058 //===========================================================================================================================
2060 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
2063 AWDDNSDomainStats * awdStats = nil;
2064 NSString * domain = nil;
2066 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
2067 uint32_t latencyBins[kQueryStatsLatencyBinCount];
2068 uint32_t expiredAnswerBins[kQueryStatsExpiredAnswerStateCount];
2070 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
2071 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
2073 domain = [[NSString alloc] initWithUTF8String:inDomain];
2074 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
2076 awdStats.domain = domain;
2077 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
2078 awdStats.recordType = inType;
2080 // Positively answered query send counts
2082 binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
2083 [awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2085 // 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
2086 // was sent out on the wire. In that case, include the associated latency bins as well.
2090 binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
2091 [awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2094 // Negatively answered query send counts
2096 binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2097 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2101 binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
2102 [awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2105 // Unanswered query send counts
2107 binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2108 [awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2112 binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
2113 [awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
2116 // Expired answers states
2118 binCount = CopyHistogramBins(expiredAnswerBins, inHist->expiredAnswerStateBins, kQueryStatsExpiredAnswerStateCount);
2119 [awdStats setExpiredAnswerStates:expiredAnswerBins count:(NSUInteger)binCount];
2121 *outStats = awdStats;
2123 err = mStatus_NoError;
2131 //===========================================================================================================================
2133 //===========================================================================================================================
2135 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
2137 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
2138 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
2141 //===========================================================================================================================
2143 //===========================================================================================================================
2145 #define Percent(N, D) (((N) * 100) / (D)), ((((N) * 10000) / (D)) % 100)
2146 #define PercentFmt "%3u.%02u"
2147 #define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
2148 LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
2150 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
2152 unsigned int totalAnswered;
2153 unsigned int totalNegAnswered;
2154 unsigned int totalUnanswered;
2158 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2160 totalAnswered += inHist->answeredQuerySendCountBins[i];
2163 totalNegAnswered = 0;
2164 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2166 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
2169 totalUnanswered = 0;
2170 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2172 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
2175 LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
2176 LogMsgNoIdent("Answered questions %4u", totalAnswered);
2177 LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
2178 LogMsgNoIdent("Unanswered questions %4u", totalUnanswered);
2179 LogMsgNoIdent("Expired - no cached answer %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_Allowed]);
2180 LogMsgNoIdent("Expired - answered from cache %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithExpired]);
2181 LogMsgNoIdent("Expired - cache changed %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_ExpiredAnswerChanged]);
2182 LogMsgNoIdent("-- Query send counts ---------");
2183 LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
2184 LogMsgNoIdent("-- Query send counts (NAQs) --");
2185 LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
2187 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
2189 LogMsgNoIdent("--- Response times -----------");
2190 LogDNSHistLatencies(inHist->responseLatencyBins);
2193 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
2195 LogMsgNoIdent("--- Response times (NAQs) ----");
2196 LogDNSHistLatencies(inHist->negResponseLatencyBins);
2199 if (totalUnanswered > 0)
2201 LogMsgNoIdent("--- Unanswered query times ---");
2202 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
2206 //===========================================================================================================================
2207 // LogDNSHistSendCounts
2208 //===========================================================================================================================
2210 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
2217 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2219 total += inSendCountBins[i];
2224 uint32_t accumulator = 0;
2226 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2228 accumulator += inSendCountBins[i];
2229 if (i < (kQueryStatsSendCountBinCount - 1))
2231 snprintf(label, sizeof(label), "%2d ", i);
2235 snprintf(label, sizeof(label), "%2d+", i);
2237 LogStat(label, inSendCountBins[i], accumulator, total);
2238 if (accumulator == total) break;
2243 LogMsgNoIdent("No data.");
2247 //===========================================================================================================================
2248 // LogDNSHistLatencies
2249 //===========================================================================================================================
2251 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
2258 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2260 total += inLatencyBins[i];
2265 uint32_t accumulator = 0;
2267 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2269 accumulator += inLatencyBins[i];
2270 if (i < (int)countof(kResponseLatencyMsLimits))
2272 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
2276 snprintf(label, sizeof(label), "< ∞ ms");
2278 LogStat(label, inLatencyBins[i], accumulator, total);
2279 if (accumulator == total) break;
2284 LogMsgNoIdent("No data.");
2288 //===========================================================================================================================
2289 // LogDNSMessageSizeStats
2290 //===========================================================================================================================
2292 mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
2298 for (i = 0; i < inBinCount; ++i)
2305 uint32_t accumulator;
2306 unsigned int lower, upper;
2311 for (i = 0; i < inBinCount; ++i)
2313 accumulator += inBins[i];
2315 if (i < (inBinCount - 1))
2317 upper += inBinWidth;
2318 snprintf(label, sizeof(label), "%3u - %-3u", lower, upper);
2322 snprintf(label, sizeof(label), "%3u+ ", lower);
2324 LogStat(label, inBins[i], accumulator, total);
2325 if (accumulator == total) break;
2330 LogMsgNoIdent("No data.");
2334 //===========================================================================================================================
2335 // CopyHistogramBins
2337 // Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
2338 // bin and all bins with non-zero values.
2339 //===========================================================================================================================
2341 mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
2346 if (inBinCount == 0) return (0);
2349 for (i = 0; i < inBinCount; ++i)
2351 inDstBins[i] = inSrcBins[i];
2352 if (inDstBins[i] > 0) minCount = i + 1;
2357 #endif // TARGET_OS_IOS