1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 #if (TARGET_OS_EMBEDDED)
21 #import <CoreUtils/SoftLinking.h>
22 #import <WirelessDiagnostics/AWDDNSDomainStats.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/AWDMetricIds_MDNSResponder.h>
30 #import <WirelessDiagnostics/WirelessDiagnostics.h>
31 #import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
34 #import "mDNSMacOSX.h"
35 #import "DebugServices.h"
37 //===========================================================================================================================
38 // External Frameworks
39 //===========================================================================================================================
41 SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics)
43 SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
44 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics)
45 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats)
46 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer)
47 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain)
48 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname)
49 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult)
50 SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection)
51 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
53 #define AWDDNSDomainStatsSoft getAWDDNSDomainStatsClass()
54 #define AWDMDNSResponderDNSStatisticsSoft getAWDMDNSResponderDNSStatisticsClass()
55 #define AWDMDNSResponderResolveStatsSoft getAWDMDNSResponderResolveStatsClass()
56 #define AWDMDNSResponderResolveStatsResultSoft getAWDMDNSResponderResolveStatsResultClass()
57 #define AWDMDNSResponderResolveStatsDNSServerSoft getAWDMDNSResponderResolveStatsDNSServerClass()
58 #define AWDMDNSResponderResolveStatsDomainSoft getAWDMDNSResponderResolveStatsDomainClass()
59 #define AWDMDNSResponderResolveStatsHostnameSoft getAWDMDNSResponderResolveStatsHostnameClass()
60 #define AWDServerConnectionSoft getAWDServerConnectionClass()
61 #define AWDMetricManagerSoft getAWDMetricManagerClass()
63 //===========================================================================================================================
65 //===========================================================================================================================
67 #define countof(X) (sizeof(X) / sizeof(X[0]))
68 #define countof_field(TYPE, FIELD) countof(((TYPE *)0)->FIELD)
69 #define increment_saturate(VAR, MAX) do {if ((VAR) < (MAX)) {++(VAR);}} while (0)
70 #define ForgetMem(X) do {if(*(X)) {free(*(X)); *(X) = NULL;}} while(0)
72 //===========================================================================================================================
74 //===========================================================================================================================
76 #define kQueryStatsMaxQuerySendCount 10
77 #define kQueryStatsSendCountBinCount (kQueryStatsMaxQuerySendCount + 1)
78 #define kQueryStatsLatencyBinCount 55
79 #define kResolveStatsMaxObjCount 2000
81 //===========================================================================================================================
83 //===========================================================================================================================
87 const char * cstr; // Name of domain as a c-string.
88 const domainname * name; // Name of domain as length-prefixed labels.
89 int labelCount; // Number of labels in domain name. Used for domain name comparisons.
93 // Important: Do not add to this list without getting privacy approval beforehand. See <rdar://problem/24155761&26397203>.
94 // If you get approval and do add a domain to this list, make sure it passes ValidateDNSStatsDomains() below.
96 static const Domain kQueryStatsDomains[] =
98 { ".", (domainname *)"", 0 },
99 { "apple.com.", (domainname *)"\x5" "apple" "\x3" "com", 2 },
100 { "icloud.com.", (domainname *)"\x6" "icloud" "\x3" "com", 2 },
101 { "mzstatic.com.", (domainname *)"\x8" "mzstatic" "\x3" "com", 2 },
102 { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 },
103 { "google.com.", (domainname *)"\x6" "google" "\x3" "com", 2 },
104 { "youtube.com.", (domainname *)"\x7" "youtube" "\x3" "com", 2 },
105 { "facebook.com.", (domainname *)"\x8" "facebook" "\x3" "com", 2 },
106 { "baidu.com.", (domainname *)"\x5" "baidu" "\x3" "com", 2 },
107 { "yahoo.com.", (domainname *)"\x5" "yahoo" "\x3" "com", 2 },
108 { "qq.com.", (domainname *)"\x2" "qq" "\x3" "com", 2 },
111 check_compile_time(countof(kQueryStatsDomains) == 11);
113 // DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
114 // <rdar://problem/23980546> MDNSResponder.proto update.
116 // answeredQuerySendCountBins
118 // 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
119 // was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times.
121 // unansweredQuerySendCountBins
123 // 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
124 // was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times.
126 // responseLatencyBins
128 // An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time
129 // interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are
130 // 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,
131 // 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
132 // 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞.
136 uint16_t unansweredQuerySendCountBins[kQueryStatsSendCountBinCount];
137 uint16_t unansweredQueryDurationBins[kQueryStatsLatencyBinCount];
138 uint16_t answeredQuerySendCountBins[kQueryStatsSendCountBinCount];
139 uint16_t responseLatencyBins[kQueryStatsLatencyBinCount];
140 uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
141 uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount];
145 check_compile_time(sizeof(DNSHist) <= 512);
146 check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
147 check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
148 check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
150 // Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
151 // latency histogram bins to observe these time interval upper bounds.
153 static const mDNSu32 kResponseLatencyMsLimits[] =
156 10, 20, 30, 40, 50, 60, 70, 80, 90,
157 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
158 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
159 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
160 5000, 6000, 7000, 8000, 9000,
164 check_compile_time(countof(kResponseLatencyMsLimits) == 54);
165 check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1));
166 check_compile_time(countof_field(DNSHist, responseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
167 check_compile_time(countof_field(DNSHist, negResponseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
171 DNSHist * histAny; // Histogram data for queries of any resource record type.
172 DNSHist * histA; // Histogram data for queries for A resource records.
173 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
177 typedef struct DNSDomainStats DNSDomainStats;
178 struct DNSDomainStats
180 DNSDomainStats * next; // Pointer to next domain stats in list.
181 const Domain * domain; // Domain for which these stats are collected.
182 DNSHistSet * nonCellular; // Query stats for queries sent over non-cellular interfaces.
183 DNSHistSet * cellular; // Query stats for queries sent over cellular interfaces.
186 check_compile_time(sizeof(struct DNSDomainStats) <= 32);
188 static const Domain kResolveStatsDomains[] =
190 { "apple.com.", (domainname *)"\x5" "apple" "\x3" "com", 2 },
191 { "icloud.com.", (domainname *)"\x6" "icloud" "\x3" "com", 2 },
192 { "mzstatic.com.", (domainname *)"\x8" "mzstatic" "\x3" "com", 2 },
193 { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 },
196 check_compile_time(countof(kResolveStatsDomains) == 4);
198 typedef struct ResolveStatsDomain ResolveStatsDomain;
199 typedef struct ResolveStatsHostname ResolveStatsHostname;
200 typedef struct ResolveStatsDNSServer ResolveStatsDNSServer;
201 typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet;
202 typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr;
203 typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet;
205 struct ResolveStatsDomain
207 ResolveStatsDomain * next; // Next domain object in list.
208 ResolveStatsHostname * hostnameList; // List of hostname objects in this domain.
209 const Domain * domainInfo; // Pointer to domain info.
212 struct ResolveStatsHostname
214 ResolveStatsHostname * next; // Next hostname object in list.
215 ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved.
216 ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved.
217 ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects.
218 uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels.
221 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
223 struct ResolveStatsDNSServer
225 ResolveStatsDNSServer * next; // Next DNS server object in list.
226 uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects.
227 mDNSBool isForCell; // True if this DNS server belongs to a cellular interface.
228 mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4.
229 uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address.
232 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
236 uint16_t count; // Number of times this IPv4 address was provided as a resolution result.
237 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came.
239 uint8_t addrBytes[4]; // IPv4 address bytes.
243 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
245 struct ResolveStatsIPv4AddrSet
247 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
248 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
251 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
253 struct ResolveStatsIPv6Addr
255 ResolveStatsIPv6Addr * next; // Next IPv6 address object in list.
256 uint16_t count; // Number of times this IPv6 address was provided as a resolution result.
257 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came.
258 uint8_t addrBytes[16]; // IPv6 address bytes.
261 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
265 uint16_t count; // Number of times that a negative response was returned by a DNS server.
266 uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses.
270 check_compile_time(sizeof(NegAAAACounter) <= 4);
272 struct ResolveStatsNegAAAASet
274 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
275 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
278 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
282 kResponseType_IPv4Addr = 1,
283 kResponseType_IPv6Addr = 2,
284 kResponseType_NegA = 3,
285 kResponseType_NegAAAA = 4
292 const uint8_t * data;
296 //===========================================================================================================================
298 //===========================================================================================================================
300 extern mDNS mDNSStorage;
302 static DNSDomainStats * gDomainStatsList = NULL;
303 static ResolveStatsDomain * gResolveStatsList = NULL;
304 static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
305 static unsigned int gResolveStatsNextServerID = 0;
306 static int gResolveStatsObjCount = 0;
307 static AWDServerConnection * gAWDServerConnection = nil;
309 //===========================================================================================================================
311 //===========================================================================================================================
313 mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats);
314 mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats);
315 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList);
316 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, uint16_t inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
318 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain);
319 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
320 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
321 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
323 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
324 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
325 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
326 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
328 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
329 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
330 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
332 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
333 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
335 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
336 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
338 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
339 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
340 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
342 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList);
343 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList);
344 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList);
345 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
346 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID);
347 mDNSlocal mStatus SubmitAWDMetricQueryStats(void);
348 mDNSlocal mStatus SubmitAWDMetricResolveStats(void);
349 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
350 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
351 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
352 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
353 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
354 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
355 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
356 mDNSlocal void ValidateDNSStatsDomains(void);
359 //===========================================================================================================================
361 //===========================================================================================================================
363 mStatus MetricsInit(void)
367 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
368 ValidateDNSStatsDomains();
371 err = CreateDomainStatsList(&gDomainStatsList);
372 require_noerr_quiet(err, exit);
374 err = CreateResolveStatsList(&gResolveStatsList);
375 require_noerr_quiet(err, exit);
379 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
380 initWithComponentId: AWDComponentId_MDNSResponder
381 andBlockOnConfiguration: NO];
383 if (gAWDServerConnection)
385 [gAWDServerConnection
386 registerQueriableMetricCallback: ^(UInt32 inMetricID)
388 SubmitAWDMetric(inMetricID);
390 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
392 [gAWDServerConnection
393 registerQueriableMetricCallback: ^(UInt32 inMetricID)
395 SubmitAWDMetric(inMetricID);
397 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
399 [gAWDServerConnection
400 registerQueriableMetricCallback: ^(UInt32 inMetricID)
402 SubmitAWDMetric(inMetricID);
404 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
408 LogMsg("MetricsInit: failed to create AWD server connection.");
415 //===========================================================================================================================
416 // MetricsUpdateUDNSQueryStats
417 //===========================================================================================================================
419 mDNSexport void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
421 DNSDomainStats * stats;
423 const domainname * queryParentDomain;
424 mDNSBool isQueryInDomain;
426 int skipCountLast = -1;
428 queryLabelCount = CountLabels(inQueryName);
430 for (stats = gDomainStatsList; stats; stats = stats->next)
432 isQueryInDomain = mDNSfalse;
433 if (strcmp(stats->domain->cstr, ".") == 0)
435 // All queries are in the root domain.
436 isQueryInDomain = mDNStrue;
440 skipCount = queryLabelCount - stats->domain->labelCount;
443 if (skipCount != skipCountLast)
445 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
446 skipCountLast = skipCount;
448 isQueryInDomain = SameDomainName(queryParentDomain, stats->domain->name);
454 DNSDomainStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
460 //===========================================================================================================================
461 // MetricsUpdateUDNSResolveStats
462 //===========================================================================================================================
464 mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
466 ResolveStatsDomain * domain;
469 mDNSBool isQueryInDomain;
471 int skipCountLast = -1;
473 const domainname * queryParentDomain;
476 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
477 require_quiet(inRR->rDNSServer, exit);
479 queryLabelCount = CountLabels(inQueryName);
481 for (domain = gResolveStatsList; domain; domain = domain->next)
483 isQueryInDomain = mDNSfalse;
484 skipCount = queryLabelCount - domain->domainInfo->labelCount;
487 if (skipCount != skipCountLast)
489 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
490 skipCountLast = skipCount;
492 isQueryInDomain = SameDomainName(queryParentDomain, domain->domainInfo->name);
494 if (!isQueryInDomain) continue;
496 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
497 if (hostnameLen >= sizeof(hostname.c)) continue;
499 memcpy(hostname.c, inQueryName->c, hostnameLen);
500 hostname.c[hostnameLen] = 0;
502 if (inRR->RecordType == kDNSRecordTypePacketNegative)
504 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
505 response.data = NULL;
509 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
510 response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
512 ResolveStatsDomainUpdate(domain, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
519 //===========================================================================================================================
521 //===========================================================================================================================
523 mDNSexport void LogMetrics(void)
525 DNSDomainStats * stats;
526 const ResolveStatsDomain * domain;
527 const ResolveStatsHostname * hostname;
528 const ResolveStatsDNSServer * server;
529 const ResolveStatsIPv4AddrSet * addrV4;
530 const ResolveStatsIPv6Addr * addrV6;
531 const ResolveStatsNegAAAASet * negV6;
534 unsigned int serverID;
535 int serverObjCount = 0;
536 int hostnameObjCount = 0;
537 int addrObjCount = 0;
539 LogMsgNoIdent("---- DNS query stats by domain -----");
541 for (stats = gDomainStatsList; stats; stats = stats->next)
543 if (!stats->nonCellular && !stats->cellular)
545 LogMsgNoIdent("No data for %s", stats->domain->cstr);
548 if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, stats->domain->cstr, mDNSfalse);
549 if (stats->cellular) LogDNSHistSet(stats->cellular, stats->domain->cstr, mDNStrue);
552 LogMsgNoIdent("---- DNS resolve stats by domain -----");
554 LogMsgNoIdent("Servers:");
555 for (server = gResolveStatsServerList; server; server = server->next)
558 LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
559 server->id, server->isForCell ? " C" : "NC", server->addrBytes);
562 for (domain = gResolveStatsList; domain; domain = domain->next)
565 for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
566 hostnameObjCount += hostnameCount;
568 LogMsgNoIdent("%##s (%d hostname%s)", domain->domainInfo->name, hostnameCount, (hostnameCount == 1) ? "" : "s");
570 for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
572 LogMsgNoIdent(" %##s", hostname->name);
573 for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
575 for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
577 if (serverID == 0) addrObjCount++;
578 for (i = 0; i < (int)countof(addrV4->counters); ++i)
580 const IPv4AddrCounter * counter;
582 counter = &addrV4->counters[i];
583 if (counter->count == 0) break;
584 if (counter->serverID == serverID)
586 if (counter->isNegative)
588 LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
592 LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
597 for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
599 if (serverID == 0) addrObjCount++;
600 if (addrV6->serverID == serverID)
602 LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
605 for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
607 if (serverID == 0) addrObjCount++;
608 for (i = 0; i < (int)countof(negV6->counters); ++i)
610 const NegAAAACounter * counter;
612 counter = &negV6->counters[i];
613 if (counter->count == 0) break;
614 if (counter->serverID == serverID)
616 LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
623 LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
624 serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
626 LogMsgNoIdent("---- Num of Services Registered -----");
627 LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
628 curr_num_regservices, max_num_regservices);
631 //===========================================================================================================================
632 // DNSDomainStatsCreate
633 //===========================================================================================================================
635 mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats)
638 DNSDomainStats * obj;
640 obj = (DNSDomainStats *)calloc(1, sizeof(*obj));
641 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
643 obj->domain = inDomain;
646 err = mStatus_NoError;
652 //===========================================================================================================================
653 // DNSDomainStatsFree
654 //===========================================================================================================================
656 mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats)
658 if (inStats->nonCellular)
660 ForgetMem(&inStats->nonCellular->histAny);
661 ForgetMem(&inStats->nonCellular->histA);
662 ForgetMem(&inStats->nonCellular->histAAAA);
663 free(inStats->nonCellular);
664 inStats->nonCellular = NULL;
666 if (inStats->cellular)
668 ForgetMem(&inStats->cellular->histAny);
669 ForgetMem(&inStats->cellular->histA);
670 ForgetMem(&inStats->cellular->histAAAA);
671 free(inStats->cellular);
672 inStats->cellular = NULL;
677 //===========================================================================================================================
678 // DNSDomainStatsFreeList
679 //===========================================================================================================================
681 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList)
683 DNSDomainStats * stats;
685 while ((stats = inList) != NULL)
687 inList = stats->next;
688 DNSDomainStatsFree(stats);
692 //===========================================================================================================================
693 // DNSDomainStatsUpdate
694 //===========================================================================================================================
696 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, uint16_t inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
705 require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError);
707 p = inForCell ? &inStats->cellular : &inStats->nonCellular;
708 if ((set = *p) == NULL)
710 set = (DNSHistSet *)calloc(1, sizeof(*set));
711 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
714 if ((histAny = set->histAny) == NULL)
716 histAny = (DNSHist *)calloc(1, sizeof(*histAny));
717 require_action_quiet(histAny, exit, err = mStatus_NoMemoryErr);
718 set->histAny = histAny;
720 if (inType == kDNSType_A)
722 if ((hist = set->histA) == NULL)
724 hist = (DNSHist *)calloc(1, sizeof(*hist));
725 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
729 else if (inType == kDNSType_AAAA)
731 if ((hist = set->histAAAA) == NULL)
733 hist = (DNSHist *)calloc(1, sizeof(*hist));
734 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
735 set->histAAAA = hist;
745 uint16_t * sendCountBins;
746 uint16_t * latencyBins;
747 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
749 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
751 sendCountBins = isNegative ? histAny->negAnsweredQuerySendCountBins : histAny->answeredQuerySendCountBins;
752 increment_saturate(sendCountBins[i], UINT16_MAX);
755 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
756 increment_saturate(sendCountBins[i], UINT16_MAX);
759 if (inQuerySendCount > 0)
761 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
762 latencyBins = isNegative ? histAny->negResponseLatencyBins : histAny->responseLatencyBins;
763 increment_saturate(latencyBins[i], UINT16_MAX);
766 latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
767 increment_saturate(latencyBins[i], UINT16_MAX);
773 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
774 increment_saturate(histAny->unansweredQuerySendCountBins[i], UINT16_MAX);
775 if (hist) increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
777 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
778 increment_saturate(histAny->unansweredQueryDurationBins[i], UINT16_MAX);
779 if (hist) increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
781 err = mStatus_NoError;
787 //===========================================================================================================================
788 // ResolveStatsDomainCreate
789 //===========================================================================================================================
791 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain)
794 ResolveStatsDomain * obj;
796 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
797 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
799 obj->domainInfo = inDomain;
802 err = mStatus_NoError;
808 //===========================================================================================================================
809 // ResolveStatsDomainFree
810 //===========================================================================================================================
812 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
814 ResolveStatsHostname * hostname;
816 while ((hostname = inDomain->hostnameList) != NULL)
818 inDomain->hostnameList = hostname->next;
819 ResolveStatsHostnameFree(hostname);
824 //===========================================================================================================================
825 // ResolveStatsDomainUpdate
826 //===========================================================================================================================
828 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
831 ResolveStatsHostname ** p;
832 ResolveStatsHostname * hostname;
835 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
837 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
842 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
843 err = ResolveStatsHostnameCreate(inHostname, &hostname);
844 require_noerr_quiet(err, exit);
845 gResolveStatsObjCount++;
849 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
850 require_noerr_quiet(err, exit);
852 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
853 require_noerr_quiet(err, exit);
859 //===========================================================================================================================
860 // ResolveStatsHostnameCreate
861 //===========================================================================================================================
863 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
866 ResolveStatsHostname * obj;
869 nameLen = DomainNameLength(inName);
870 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
872 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
873 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
875 memcpy(obj->name, inName, nameLen);
878 err = mStatus_NoError;
884 //===========================================================================================================================
885 // ResolveStatsDomainCreateAWDVersion
886 //===========================================================================================================================
888 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
891 AWDMDNSResponderResolveStatsDomain * domain;
892 ResolveStatsHostname * hostname;
893 AWDMDNSResponderResolveStatsHostname * awdHostname;
896 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
897 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
899 name = [[NSString alloc] initWithUTF8String:inDomain->domainInfo->cstr];
900 require_action_quiet(name, exit, err = mStatus_UnknownErr);
906 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
908 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
909 require_noerr_quiet(err, exit);
911 [domain addHostname:awdHostname];
912 [awdHostname release];
918 err = mStatus_NoError;
925 //===========================================================================================================================
926 // ResolveStatsHostnameFree
927 //===========================================================================================================================
929 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
931 ResolveStatsIPv4AddrSet * addrV4;
932 ResolveStatsIPv6Addr * addrV6;
933 ResolveStatsNegAAAASet * negV6;
935 while ((addrV4 = inHostname->addrV4List) != NULL)
937 inHostname->addrV4List = addrV4->next;
938 ResolveStatsIPv4AddrSetFree(addrV4);
940 while ((addrV6 = inHostname->addrV6List) != NULL)
942 inHostname->addrV6List = addrV6->next;
943 ResolveStatsIPv6AddressFree(addrV6);
945 while ((negV6 = inHostname->negV6List) != NULL)
947 inHostname->negV6List = negV6->next;
948 ResolveStatsNegAAAASetFree(negV6);
953 //===========================================================================================================================
954 // ResolveStatsHostnameUpdate
955 //===========================================================================================================================
957 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
961 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
963 ResolveStatsIPv4AddrSet ** p;
964 ResolveStatsIPv4AddrSet * addrV4;
966 IPv4AddrCounter * counter;
968 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
970 for (i = 0; i < (int)countof(addrV4->counters); ++i)
972 counter = &addrV4->counters[i];
973 if (counter->count == 0) break;
974 if (counter->serverID != inServerID) continue;
975 if (inResp->type == kResponseType_NegA)
977 if (counter->isNegative) break;
981 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
984 if (i < (int)countof(addrV4->counters)) break;
988 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
989 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
990 require_noerr_quiet(err, exit);
991 gResolveStatsObjCount++;
994 counter = &addrV4->counters[0];
996 if (counter->count == 0)
998 counter->serverID = inServerID;
999 if (inResp->type == kResponseType_NegA)
1001 counter->isNegative = 1;
1005 counter->isNegative = 0;
1006 memcpy(counter->addrBytes, inResp->data, 4);
1009 increment_saturate(counter->count, UINT16_MAX);
1010 err = mStatus_NoError;
1012 else if (inResp->type == kResponseType_IPv6Addr)
1014 ResolveStatsIPv6Addr ** p;
1015 ResolveStatsIPv6Addr * addrV6;
1017 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
1019 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
1023 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1024 err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
1025 require_noerr_quiet(err, exit);
1026 gResolveStatsObjCount++;
1030 increment_saturate(addrV6->count, UINT16_MAX);
1031 err = mStatus_NoError;
1033 else if (inResp->type == kResponseType_NegAAAA)
1035 ResolveStatsNegAAAASet ** p;
1036 ResolveStatsNegAAAASet * negV6;
1038 NegAAAACounter * counter;
1040 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1042 for (i = 0; i < (int)countof(negV6->counters); ++i)
1044 counter = &negV6->counters[i];
1045 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1047 if (i < (int)countof(negV6->counters)) break;
1051 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1052 err = ResolveStatsNegAAAASetCreate(&negV6);
1053 require_noerr_quiet(err, exit);
1054 gResolveStatsObjCount++;
1057 counter = &negV6->counters[0];
1059 if (counter->count == 0) counter->serverID = inServerID;
1060 increment_saturate(counter->count, UINT16_MAX);
1061 err = mStatus_NoError;
1065 err = mStatus_Invalid;
1072 //===========================================================================================================================
1073 // ResolveStatsHostnameCreateAWDVersion
1074 //===========================================================================================================================
1076 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1079 AWDMDNSResponderResolveStatsHostname * hostname;
1081 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1083 ResolveStatsIPv4AddrSet * addrV4;
1084 ResolveStatsIPv6Addr * addrV6;
1085 ResolveStatsNegAAAASet * negV6;
1086 AWDMDNSResponderResolveStatsResult * result = nil;
1089 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1090 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1092 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1093 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1095 name = [[NSString alloc] initWithUTF8String:nameBuf];
1096 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1098 hostname.name = name;
1102 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1104 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1106 const IPv4AddrCounter * counter;
1109 counter = &addrV4->counters[i];
1110 if (counter->count == 0) break;
1112 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1113 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1115 if (counter->isNegative)
1117 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1121 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1122 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1124 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1125 result.data = addrBytes;
1126 [addrBytes release];
1128 result.count = counter->count;
1129 result.serverID = counter->serverID;
1131 [hostname addResult:result];
1137 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1141 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1142 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1144 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1145 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1147 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1148 result.count = addrV6->count;
1149 result.serverID = addrV6->serverID;
1150 result.data = addrBytes;
1152 [addrBytes release];
1154 [hostname addResult:result];
1159 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1161 for (i = 0; i < (int)countof(negV6->counters); ++i)
1163 const NegAAAACounter * counter;
1165 counter = &negV6->counters[i];
1166 if (counter->count == 0) break;
1168 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1169 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1171 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1172 result.count = counter->count;
1173 result.serverID = counter->serverID;
1175 [hostname addResult:result];
1181 *outHostname = hostname;
1183 err = mStatus_NoError;
1191 //===========================================================================================================================
1192 // ResolveStatsDNSServerCreate
1193 //===========================================================================================================================
1195 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1198 ResolveStatsDNSServer * obj;
1201 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1203 addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
1204 obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
1205 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1207 obj->isForCell = inForCell;
1208 if (inAddr->type == mDNSAddrType_IPv4)
1210 obj->isAddrV6 = mDNSfalse;
1211 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1215 obj->isAddrV6 = mDNStrue;
1216 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1220 err = mStatus_NoError;
1226 //===========================================================================================================================
1227 // ResolveStatsDNSServerFree
1228 //===========================================================================================================================
1230 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1235 //===========================================================================================================================
1236 // ResolveStatsDNSServerCreateAWDVersion
1237 //===========================================================================================================================
1239 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1242 AWDMDNSResponderResolveStatsDNSServer * server;
1243 NSData * addrBytes = nil;
1245 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1246 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1248 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1249 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1251 server.serverID = inServer->id;
1252 server.address = addrBytes;
1253 if (inServer->isForCell)
1255 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1259 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1262 *outServer = server;
1264 err = mStatus_NoError;
1267 [addrBytes release];
1272 //===========================================================================================================================
1273 // ResolveStatsIPv4AddrSetCreate
1274 //===========================================================================================================================
1276 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1279 ResolveStatsIPv4AddrSet * obj;
1281 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1282 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1285 err = mStatus_NoError;
1291 //===========================================================================================================================
1292 // ResolveStatsIPv4AddrSetFree
1293 //===========================================================================================================================
1295 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1300 //===========================================================================================================================
1301 // ResolveStatsIPv6AddressCreate
1302 //===========================================================================================================================
1304 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1307 ResolveStatsIPv6Addr * obj;
1309 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1310 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1312 obj->serverID = inServerID;
1313 memcpy(obj->addrBytes, inAddrBytes, 16);
1316 err = mStatus_NoError;
1322 //===========================================================================================================================
1323 // ResolveStatsIPv6AddressFree
1324 //===========================================================================================================================
1326 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1331 //===========================================================================================================================
1332 // ResolveStatsNegAAAASetCreate
1333 //===========================================================================================================================
1335 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1338 ResolveStatsNegAAAASet * obj;
1340 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1341 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1344 err = mStatus_NoError;
1350 //===========================================================================================================================
1351 // ResolveStatsNegAAAASetFree
1352 //===========================================================================================================================
1354 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1359 //===========================================================================================================================
1360 // ResolveStatsGetServerID
1361 //===========================================================================================================================
1363 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1366 ResolveStatsDNSServer ** p;
1367 ResolveStatsDNSServer * server;
1369 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1371 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1373 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1375 if (inServerAddr->type == mDNSAddrType_IPv4)
1377 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1381 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1388 require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
1389 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1390 err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
1391 require_noerr_quiet(err, exit);
1392 gResolveStatsObjCount++;
1394 server->id = gResolveStatsNextServerID++;
1395 server->next = gResolveStatsServerList;
1396 gResolveStatsServerList = server;
1398 else if (gResolveStatsServerList != server)
1401 server->next = gResolveStatsServerList;
1402 gResolveStatsServerList = server;
1405 *outServerID = server->id;
1406 err = mStatus_NoError;
1412 //===========================================================================================================================
1413 // CreateDomainStatsList
1414 //===========================================================================================================================
1416 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList)
1420 DNSDomainStats * stats;
1421 DNSDomainStats ** p;
1422 DNSDomainStats * list = NULL;
1425 for (i = 0; i < (int)countof(kQueryStatsDomains); ++i)
1427 err = DNSDomainStatsCreate(&kQueryStatsDomains[i], &stats);
1428 require_noerr_quiet(err, exit);
1438 DNSDomainStatsFreeList(list);
1442 //===========================================================================================================================
1443 // CreateResolveStatsList
1444 //===========================================================================================================================
1446 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1450 ResolveStatsDomain * domain;
1451 ResolveStatsDomain ** p;
1452 ResolveStatsDomain * list = NULL;
1455 for (i = 0; i < (int)countof(kResolveStatsDomains); ++i)
1457 err = ResolveStatsDomainCreate(&kResolveStatsDomains[i], &domain);
1458 require_noerr_quiet(err, exit);
1468 FreeResolveStatsList(list);
1472 //===========================================================================================================================
1473 // FreeResolveStatsList
1474 //===========================================================================================================================
1476 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1478 ResolveStatsDomain * domain;
1480 while ((domain = inList) != NULL)
1482 inList = domain->next;
1483 ResolveStatsDomainFree(domain);
1487 //===========================================================================================================================
1488 // FreeResolveStatsServerList
1489 //===========================================================================================================================
1491 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1493 ResolveStatsDNSServer * server;
1495 while ((server = inList) != NULL)
1497 inList = server->next;
1498 ResolveStatsDNSServerFree(server);
1502 //===========================================================================================================================
1504 //===========================================================================================================================
1506 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1508 mStatus err = mStatus_NoError;
1512 case AWDMetricId_MDNSResponder_DNSStatistics:
1513 err = SubmitAWDMetricQueryStats();
1516 case AWDMetricId_MDNSResponder_ResolveStats:
1517 err = SubmitAWDMetricResolveStats();
1520 case AWDMetricId_MDNSResponder_ServicesStats:
1521 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats integerValue:max_num_regservices];
1522 KQueueLock(&mDNSStorage);
1523 // reset the no of max services since we want to collect the max no of services registered per AWD submission period
1524 max_num_regservices = curr_num_regservices;
1525 KQueueUnlock(&mDNSStorage, "SubmitAWDSimpleMetricServiceStats");
1529 err = mStatus_UnsupportedErr;
1534 LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1538 //===========================================================================================================================
1539 // SubmitAWDMetricQueryStats
1540 //===========================================================================================================================
1542 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1546 DNSDomainStats * stats;
1547 DNSDomainStats * newDomainStatsList;
1548 DNSDomainStats * domainStatsList = NULL;
1549 AWDMetricContainer * container = nil;
1550 AWDMDNSResponderDNSStatistics * metric = nil;
1552 err = CreateDomainStatsList(&newDomainStatsList);
1553 require_noerr_quiet(err, exit);
1555 domainStatsList = gDomainStatsList;
1557 KQueueLock(&mDNSStorage);
1558 gDomainStatsList = newDomainStatsList;
1559 KQueueUnlock(&mDNSStorage, "SubmitAWDMetricQueryStats");
1561 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1562 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1564 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1565 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1567 while ((stats = domainStatsList) != NULL)
1569 if (stats->nonCellular)
1571 err = AddAWDDNSDomainStats(metric, stats->nonCellular, stats->domain->cstr, mDNSfalse);
1572 require_noerr_quiet(err, exit);
1574 if (stats->cellular)
1576 err = AddAWDDNSDomainStats(metric, stats->cellular, stats->domain->cstr, mDNStrue);
1577 require_noerr_quiet(err, exit);
1579 domainStatsList = stats->next;
1580 DNSDomainStatsFree(stats);
1583 container.metric = metric;
1584 success = [gAWDServerConnection submitMetric:container];
1585 LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed" );
1586 err = success ? mStatus_NoError : mStatus_UnknownErr;
1590 [container release];
1591 DNSDomainStatsFreeList(domainStatsList);
1595 //===========================================================================================================================
1596 // SubmitAWDMetricResolveStats
1597 //===========================================================================================================================
1599 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1602 ResolveStatsDomain * newResolveStatsList;
1603 ResolveStatsDomain * domainList = NULL;
1604 ResolveStatsDNSServer * serverList = NULL;
1605 AWDMetricContainer * container = nil;
1606 AWDMDNSResponderResolveStats * metric = nil;
1607 ResolveStatsDNSServer * server;
1608 ResolveStatsDomain * domain;
1611 err = CreateResolveStatsList(&newResolveStatsList);
1612 require_noerr_quiet(err, exit);
1614 domainList = gResolveStatsList;
1615 serverList = gResolveStatsServerList;
1617 KQueueLock(&mDNSStorage);
1618 gResolveStatsList = newResolveStatsList;
1619 gResolveStatsServerList = NULL;
1620 gResolveStatsNextServerID = 0;
1621 gResolveStatsObjCount = 0;
1622 KQueueUnlock(&mDNSStorage, "SubmitAWDMetricResolveStats");
1624 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1625 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1627 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1628 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1630 while ((server = serverList) != NULL)
1632 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1634 serverList = server->next;
1635 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1636 ResolveStatsDNSServerFree(server);
1637 require_noerr_quiet(err, exit);
1639 [metric addServer:awdServer];
1640 [awdServer release];
1643 while ((domain = domainList) != NULL)
1645 AWDMDNSResponderResolveStatsDomain * awdDomain;
1647 domainList = domain->next;
1648 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1649 ResolveStatsDomainFree(domain);
1650 require_noerr_quiet(err, exit);
1652 [metric addDomain:awdDomain];
1653 [awdDomain release];
1656 container.metric = metric;
1657 success = [gAWDServerConnection submitMetric:container];
1658 LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed" );
1659 err = success ? mStatus_NoError : mStatus_UnknownErr;
1663 [container release];
1664 FreeResolveStatsList(domainList);
1665 FreeResolveStatsServerList(serverList);
1669 //===========================================================================================================================
1670 // CreateAWDDNSDomainStats
1671 //===========================================================================================================================
1673 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
1676 AWDDNSDomainStats * awdStats = nil;
1677 NSString * domain = nil;
1678 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
1679 uint32_t latencyBins[kQueryStatsLatencyBinCount];
1681 unsigned int totalAnswered;
1682 unsigned int totalNegAnswered;
1683 unsigned int totalUnanswered;
1685 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
1686 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
1688 domain = [[NSString alloc] initWithUTF8String:inDomain];
1689 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1691 awdStats.domain = domain;
1692 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
1693 awdStats.recordType = inType;
1696 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1698 sendCountBins[i] = inHist->answeredQuerySendCountBins[i];
1699 totalAnswered += inHist->answeredQuerySendCountBins[i];
1701 [awdStats setAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1703 totalNegAnswered = 0;
1704 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1706 sendCountBins[i] = inHist->negAnsweredQuerySendCountBins[i];
1707 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1709 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1711 totalUnanswered = 0;
1712 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1714 sendCountBins[i] = inHist->unansweredQuerySendCountBins[i];
1715 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1717 [awdStats setUnansweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1719 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1721 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1723 latencyBins[i] = inHist->responseLatencyBins[i];
1725 [awdStats setResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1728 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1730 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1732 latencyBins[i] = inHist->negResponseLatencyBins[i];
1734 [awdStats setNegResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1737 if (totalUnanswered > 0)
1739 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1741 latencyBins[i] = inHist->unansweredQueryDurationBins[i];
1743 [awdStats setUnansweredQueryDurationMs:latencyBins count:kQueryStatsLatencyBinCount];
1746 *outStats = awdStats;
1748 err = mStatus_NoError;
1756 //===========================================================================================================================
1757 // AddAWDDNSDomainStats
1758 //===========================================================================================================================
1760 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1763 AWDDNSDomainStats * awdStats;
1767 err = CreateAWDDNSDomainStats(inSet->histAny, inDomain, inForCell, AWDDNSDomainStats_RecordType_Any, &awdStats);
1768 require_noerr_quiet(err, exit);
1770 [inMetric addStats:awdStats];
1775 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1776 require_noerr_quiet(err, exit);
1778 [inMetric addStats:awdStats];
1781 if (inSet->histAAAA)
1783 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1784 require_noerr_quiet(err, exit);
1786 [inMetric addStats:awdStats];
1789 err = mStatus_NoError;
1795 //===========================================================================================================================
1797 //===========================================================================================================================
1799 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1801 if (inSet->histAny) LogDNSHist(inSet->histAny, inDomain, inForCell, "Any");
1802 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
1803 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
1806 //===========================================================================================================================
1808 //===========================================================================================================================
1810 #define Percent(N, D) ((N) * 100) / (D), (((N) * 10000) / (D)) % 100
1811 #define PercentFmt "%3u.%02u"
1812 #define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
1813 LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
1815 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
1817 unsigned int totalAnswered;
1818 unsigned int totalNegAnswered;
1819 unsigned int totalUnanswered;
1823 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1825 totalAnswered += inHist->answeredQuerySendCountBins[i];
1828 totalNegAnswered = 0;
1829 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1831 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1834 totalUnanswered = 0;
1835 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1837 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1840 LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
1841 LogMsgNoIdent("Answered questions %4u", totalAnswered);
1842 LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
1843 LogMsgNoIdent("Unanswered questions %4u", totalUnanswered);
1844 LogMsgNoIdent("-- Query send counts ---------");
1845 LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
1846 LogMsgNoIdent("-- Query send counts (NAQs) --");
1847 LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
1849 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1851 LogMsgNoIdent("--- Response times -----------");
1852 LogDNSHistLatencies(inHist->responseLatencyBins);
1855 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1857 LogMsgNoIdent("--- Response times (NAQs) ----");
1858 LogDNSHistLatencies(inHist->negResponseLatencyBins);
1861 if (totalUnanswered > 0)
1863 LogMsgNoIdent("--- Unanswered query times ---");
1864 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
1868 //===========================================================================================================================
1869 // LogDNSHistSendCounts
1870 //===========================================================================================================================
1872 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
1879 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1881 total += inSendCountBins[i];
1886 uint32_t accumulator = 0;
1888 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1890 accumulator += inSendCountBins[i];
1891 if (i < (kQueryStatsSendCountBinCount - 1))
1893 snprintf(label, sizeof(label), "%2d ", i);
1897 snprintf(label, sizeof(label), "%2d+", i);
1899 LogStat(label, inSendCountBins[i], accumulator, total);
1900 if (accumulator == total) break;
1905 LogMsgNoIdent("No data.");
1909 //===========================================================================================================================
1910 // LogDNSHistLatencies
1911 //===========================================================================================================================
1913 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
1920 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1922 total += inLatencyBins[i];
1927 uint32_t accumulator = 0;
1929 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1931 accumulator += inLatencyBins[i];
1932 if (i < (int)countof(kResponseLatencyMsLimits))
1934 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
1938 snprintf(label, sizeof(label), "< ∞ ms");
1940 LogStat(label, inLatencyBins[i], accumulator, total);
1941 if (accumulator == total) break;
1946 LogMsgNoIdent("No data.");
1950 //===========================================================================================================================
1951 // ValidateDNSStatsDomains
1952 //===========================================================================================================================
1954 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
1955 #warning "Do not include ValidateDNSStatsDomains() in customer release!"
1956 mDNSlocal void ValidateDNSStatsDomains(void)
1959 const Domain * domain;
1961 domainname domainNameExpected;
1962 int labelCountExpected;
1963 mDNSBool domainNamesEqual;
1964 mDNSBool failed = mDNSfalse;
1966 for (i = 0; i < countof(kQueryStatsDomains); ++i)
1968 domain = &kQueryStatsDomains[i];
1970 if (strcmp(domain->cstr, ".") == 0)
1972 domainNameExpected.c[0] = 0;
1976 ptr = MakeDomainNameFromDNSNameString(&domainNameExpected, domain->cstr);
1979 LogMsg("ValidateDNSStatsDomains: Failed to make domain name for \"%s\".", domain->cstr);
1985 domainNamesEqual = SameDomainName(domain->name, &domainNameExpected);
1986 labelCountExpected = CountLabels(&domainNameExpected);
1987 if (domainNamesEqual && (domain->labelCount == labelCountExpected))
1989 LogMsg("ValidateDNSStatsDomains: \"%s\" passed.", domain->cstr);
1993 if (!domainNamesEqual)
1995 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect domain name.", domain->cstr);
1997 if (domain->labelCount != labelCountExpected)
1999 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect label count. Actual %d, expected %d.",
2000 domain->cstr, domain->labelCount, labelCountExpected);
2007 if (failed) abort();
2010 #endif // TARGET_OS_EMBEDDED