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 { "google.com.", (domainname *)"\x6" "google" "\x3" "com", 2 },
103 { "facebook.com.", (domainname *)"\x8" "facebook" "\x3" "com", 2 },
104 { "baidu.com.", (domainname *)"\x5" "baidu" "\x3" "com", 2 },
105 { "yahoo.com.", (domainname *)"\x5" "yahoo" "\x3" "com", 2 },
106 { "qq.com.", (domainname *)"\x2" "qq" "\x3" "com", 2 },
109 check_compile_time(countof(kQueryStatsDomains) == 9);
111 // DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
112 // <rdar://problem/23980546> MDNSResponder.proto update.
114 // answeredQuerySendCountBins
116 // 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
117 // was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times.
119 // unansweredQuerySendCountBins
121 // 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
122 // was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times.
124 // responseLatencyBins
126 // An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time
127 // interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are
128 // 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,
129 // 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
130 // 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞.
134 uint16_t unansweredQuerySendCountBins[kQueryStatsSendCountBinCount];
135 uint16_t unansweredQueryDurationBins[kQueryStatsLatencyBinCount];
136 uint16_t answeredQuerySendCountBins[kQueryStatsSendCountBinCount];
137 uint16_t responseLatencyBins[kQueryStatsLatencyBinCount];
138 uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
139 uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount];
143 check_compile_time(sizeof(DNSHist) <= 512);
144 check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
145 check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
146 check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
148 // Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
149 // latency histogram bins to observe these time interval upper bounds.
151 static const mDNSu32 kResponseLatencyMsLimits[] =
154 10, 20, 30, 40, 50, 60, 70, 80, 90,
155 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
156 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
157 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
158 5000, 6000, 7000, 8000, 9000,
162 check_compile_time(countof(kResponseLatencyMsLimits) == 54);
163 check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1));
164 check_compile_time(countof_field(DNSHist, responseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
165 check_compile_time(countof_field(DNSHist, negResponseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
169 DNSHist * histA; // Histogram data for queries for A resource records.
170 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
174 typedef struct DNSDomainStats DNSDomainStats;
175 struct DNSDomainStats
177 DNSDomainStats * next; // Pointer to next domain stats in list.
178 const Domain * domain; // Domain for which these stats are collected.
179 DNSHistSet * nonCellular; // Query stats for queries sent over non-cellular interfaces.
180 DNSHistSet * cellular; // Query stats for queries sent over cellular interfaces.
183 check_compile_time(sizeof(struct DNSDomainStats) <= 32);
185 static const Domain kResolveStatsDomains[] =
187 { "apple.com.", (domainname *)"\x5" "apple" "\x3" "com", 2 },
188 { "icloud.com.", (domainname *)"\x6" "icloud" "\x3" "com", 2 },
189 { "mzstatic.com.", (domainname *)"\x8" "mzstatic" "\x3" "com", 2 },
190 { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 },
193 check_compile_time(countof(kResolveStatsDomains) == 4);
195 typedef struct ResolveStatsDomain ResolveStatsDomain;
196 typedef struct ResolveStatsHostname ResolveStatsHostname;
197 typedef struct ResolveStatsDNSServer ResolveStatsDNSServer;
198 typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet;
199 typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr;
200 typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet;
202 struct ResolveStatsDomain
204 ResolveStatsDomain * next; // Next domain object in list.
205 ResolveStatsHostname * hostnameList; // List of hostname objects in this domain.
206 const Domain * domainInfo; // Pointer to domain info.
209 struct ResolveStatsHostname
211 ResolveStatsHostname * next; // Next hostname object in list.
212 ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved.
213 ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved.
214 ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects.
215 uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels.
218 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
220 struct ResolveStatsDNSServer
222 ResolveStatsDNSServer * next; // Next DNS server object in list.
223 uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects.
224 mDNSBool isForCell; // True if this DNS server belongs to a cellular interface.
225 mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4.
226 uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address.
229 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
233 uint16_t count; // Number of times this IPv4 address was provided as a resolution result.
234 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came.
236 uint8_t addrBytes[4]; // IPv4 address bytes.
240 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
242 struct ResolveStatsIPv4AddrSet
244 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
245 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
248 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
250 struct ResolveStatsIPv6Addr
252 ResolveStatsIPv6Addr * next; // Next IPv6 address object in list.
253 uint16_t count; // Number of times this IPv6 address was provided as a resolution result.
254 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came.
255 uint8_t addrBytes[16]; // IPv6 address bytes.
258 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
262 uint16_t count; // Number of times that a negative response was returned by a DNS server.
263 uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses.
267 check_compile_time(sizeof(NegAAAACounter) <= 4);
269 struct ResolveStatsNegAAAASet
271 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
272 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
275 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
279 kResponseType_IPv4Addr = 1,
280 kResponseType_IPv6Addr = 2,
281 kResponseType_NegA = 3,
282 kResponseType_NegAAAA = 4
289 const uint8_t * data;
293 //===========================================================================================================================
295 //===========================================================================================================================
297 static DNSDomainStats * gDomainStatsList = NULL;
298 static ResolveStatsDomain * gResolveStatsList = NULL;
299 static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
300 static unsigned int gResolveStatsNextServerID = 0;
301 static int gResolveStatsObjCount = 0;
302 static AWDServerConnection * gAWDServerConnection = nil;
304 //===========================================================================================================================
306 //===========================================================================================================================
308 mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats);
309 mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats);
310 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList);
311 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
313 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain);
314 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
315 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
316 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
318 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
319 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
320 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
321 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
323 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
324 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
325 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
327 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
328 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
330 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
331 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
333 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
334 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
335 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
337 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList);
338 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList);
339 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList);
340 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
341 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID);
342 mDNSlocal mStatus SubmitAWDMetricQueryStats(void);
343 mDNSlocal mStatus SubmitAWDMetricResolveStats(void);
344 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
345 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
346 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
347 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
348 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
349 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
350 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
351 mDNSlocal void ValidateDNSStatsDomains(void);
354 //===========================================================================================================================
356 //===========================================================================================================================
358 mStatus MetricsInit(void)
360 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
361 ValidateDNSStatsDomains();
366 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
367 initWithComponentId: AWDComponentId_MDNSResponder
368 andBlockOnConfiguration: NO];
370 if (gAWDServerConnection)
372 [gAWDServerConnection
373 registerQueriableMetricCallback: ^(UInt32 inMetricID)
375 SubmitAWDMetric(inMetricID);
377 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
379 [gAWDServerConnection
380 registerQueriableMetricCallback: ^(UInt32 inMetricID)
382 SubmitAWDMetric(inMetricID);
384 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
386 [gAWDServerConnection
387 registerQueriableMetricCallback: ^(UInt32 inMetricID)
389 SubmitAWDMetric(inMetricID);
391 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
395 LogMsg("MetricsInit: failed to create AWD server connection.");
399 if( gAWDServerConnection )
401 CreateDomainStatsList(&gDomainStatsList);
402 CreateResolveStatsList(&gResolveStatsList);
405 return (mStatus_NoError);
408 //===========================================================================================================================
409 // MetricsUpdateUDNSQueryStats
410 //===========================================================================================================================
412 mDNSexport void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
414 DNSDomainStats * stats;
416 const domainname * queryParentDomain;
417 mDNSBool isQueryInDomain;
419 int skipCountLast = -1;
421 require_quiet(gAWDServerConnection, exit);
422 require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
424 queryLabelCount = CountLabels(inQueryName);
426 for (stats = gDomainStatsList; stats; stats = stats->next)
428 isQueryInDomain = mDNSfalse;
429 if (strcmp(stats->domain->cstr, ".") == 0)
431 // All queries are in the root domain.
432 isQueryInDomain = mDNStrue;
436 skipCount = queryLabelCount - stats->domain->labelCount;
439 if (skipCount != skipCountLast)
441 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
442 skipCountLast = skipCount;
444 isQueryInDomain = SameDomainName(queryParentDomain, stats->domain->name);
450 DNSDomainStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
458 //===========================================================================================================================
459 // MetricsUpdateUDNSResolveStats
460 //===========================================================================================================================
462 mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
464 ResolveStatsDomain * domain;
467 mDNSBool isQueryInDomain;
469 int skipCountLast = -1;
471 const domainname * queryParentDomain;
474 require_quiet(gAWDServerConnection, exit);
475 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
476 require_quiet(inRR->rDNSServer, exit);
478 queryLabelCount = CountLabels(inQueryName);
480 for (domain = gResolveStatsList; domain; domain = domain->next)
482 isQueryInDomain = mDNSfalse;
483 skipCount = queryLabelCount - domain->domainInfo->labelCount;
486 if (skipCount != skipCountLast)
488 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
489 skipCountLast = skipCount;
491 isQueryInDomain = SameDomainName(queryParentDomain, domain->domainInfo->name);
493 if (!isQueryInDomain) continue;
495 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
496 if (hostnameLen >= sizeof(hostname.c)) continue;
498 memcpy(hostname.c, inQueryName->c, hostnameLen);
499 hostname.c[hostnameLen] = 0;
501 if (inRR->RecordType == kDNSRecordTypePacketNegative)
503 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
504 response.data = NULL;
508 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
509 response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
511 ResolveStatsDomainUpdate(domain, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
518 //===========================================================================================================================
520 //===========================================================================================================================
522 mDNSexport void LogMetrics(void)
524 DNSDomainStats * stats;
525 const ResolveStatsDomain * domain;
526 const ResolveStatsHostname * hostname;
527 const ResolveStatsDNSServer * server;
528 const ResolveStatsIPv4AddrSet * addrV4;
529 const ResolveStatsIPv6Addr * addrV6;
530 const ResolveStatsNegAAAASet * negV6;
533 unsigned int serverID;
534 int serverObjCount = 0;
535 int hostnameObjCount = 0;
536 int addrObjCount = 0;
538 LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
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->histA);
661 ForgetMem(&inStats->nonCellular->histAAAA);
662 free(inStats->nonCellular);
663 inStats->nonCellular = NULL;
665 if (inStats->cellular)
667 ForgetMem(&inStats->cellular->histA);
668 ForgetMem(&inStats->cellular->histAAAA);
669 free(inStats->cellular);
670 inStats->cellular = NULL;
675 //===========================================================================================================================
676 // DNSDomainStatsFreeList
677 //===========================================================================================================================
679 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList)
681 DNSDomainStats * stats;
683 while ((stats = inList) != NULL)
685 inList = stats->next;
686 DNSDomainStatsFree(stats);
690 //===========================================================================================================================
691 // DNSDomainStatsUpdate
692 //===========================================================================================================================
694 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
703 require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError);
704 require_action_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit, err = mStatus_NoError);
706 pSet = inForCell ? &inStats->cellular : &inStats->nonCellular;
707 if ((set = *pSet) == NULL)
709 set = (DNSHistSet *)calloc(1, sizeof(*set));
710 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
713 pHist = (inType == kDNSType_A) ? &set->histA : &set->histAAAA;
714 if ((hist = *pHist) == NULL)
716 hist = (DNSHist *)calloc(1, sizeof(*hist));
717 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
723 uint16_t * sendCountBins;
724 uint16_t * latencyBins;
725 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
727 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
729 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
730 increment_saturate(sendCountBins[i], UINT16_MAX);
732 if (inQuerySendCount > 0)
734 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
735 latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
736 increment_saturate(latencyBins[i], UINT16_MAX);
741 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
742 increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
744 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
745 increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
747 err = mStatus_NoError;
753 //===========================================================================================================================
754 // ResolveStatsDomainCreate
755 //===========================================================================================================================
757 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain)
760 ResolveStatsDomain * obj;
762 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
763 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
765 obj->domainInfo = inDomain;
768 err = mStatus_NoError;
774 //===========================================================================================================================
775 // ResolveStatsDomainFree
776 //===========================================================================================================================
778 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
780 ResolveStatsHostname * hostname;
782 while ((hostname = inDomain->hostnameList) != NULL)
784 inDomain->hostnameList = hostname->next;
785 ResolveStatsHostnameFree(hostname);
790 //===========================================================================================================================
791 // ResolveStatsDomainUpdate
792 //===========================================================================================================================
794 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
797 ResolveStatsHostname ** p;
798 ResolveStatsHostname * hostname;
801 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
803 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
808 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
809 err = ResolveStatsHostnameCreate(inHostname, &hostname);
810 require_noerr_quiet(err, exit);
811 gResolveStatsObjCount++;
815 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
816 require_noerr_quiet(err, exit);
818 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
819 require_noerr_quiet(err, exit);
825 //===========================================================================================================================
826 // ResolveStatsHostnameCreate
827 //===========================================================================================================================
829 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
832 ResolveStatsHostname * obj;
835 nameLen = DomainNameLength(inName);
836 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
838 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
839 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
841 memcpy(obj->name, inName, nameLen);
844 err = mStatus_NoError;
850 //===========================================================================================================================
851 // ResolveStatsDomainCreateAWDVersion
852 //===========================================================================================================================
854 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
857 AWDMDNSResponderResolveStatsDomain * domain;
858 ResolveStatsHostname * hostname;
859 AWDMDNSResponderResolveStatsHostname * awdHostname;
862 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
863 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
865 name = [[NSString alloc] initWithUTF8String:inDomain->domainInfo->cstr];
866 require_action_quiet(name, exit, err = mStatus_UnknownErr);
872 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
874 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
875 require_noerr_quiet(err, exit);
877 [domain addHostname:awdHostname];
878 [awdHostname release];
884 err = mStatus_NoError;
891 //===========================================================================================================================
892 // ResolveStatsHostnameFree
893 //===========================================================================================================================
895 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
897 ResolveStatsIPv4AddrSet * addrV4;
898 ResolveStatsIPv6Addr * addrV6;
899 ResolveStatsNegAAAASet * negV6;
901 while ((addrV4 = inHostname->addrV4List) != NULL)
903 inHostname->addrV4List = addrV4->next;
904 ResolveStatsIPv4AddrSetFree(addrV4);
906 while ((addrV6 = inHostname->addrV6List) != NULL)
908 inHostname->addrV6List = addrV6->next;
909 ResolveStatsIPv6AddressFree(addrV6);
911 while ((negV6 = inHostname->negV6List) != NULL)
913 inHostname->negV6List = negV6->next;
914 ResolveStatsNegAAAASetFree(negV6);
919 //===========================================================================================================================
920 // ResolveStatsHostnameUpdate
921 //===========================================================================================================================
923 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
927 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
929 ResolveStatsIPv4AddrSet ** p;
930 ResolveStatsIPv4AddrSet * addrV4;
932 IPv4AddrCounter * counter;
934 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
936 for (i = 0; i < (int)countof(addrV4->counters); ++i)
938 counter = &addrV4->counters[i];
939 if (counter->count == 0) break;
940 if (counter->serverID != inServerID) continue;
941 if (inResp->type == kResponseType_NegA)
943 if (counter->isNegative) break;
947 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
950 if (i < (int)countof(addrV4->counters)) break;
954 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
955 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
956 require_noerr_quiet(err, exit);
957 gResolveStatsObjCount++;
960 counter = &addrV4->counters[0];
962 if (counter->count == 0)
964 counter->serverID = inServerID;
965 if (inResp->type == kResponseType_NegA)
967 counter->isNegative = 1;
971 counter->isNegative = 0;
972 memcpy(counter->addrBytes, inResp->data, 4);
975 increment_saturate(counter->count, UINT16_MAX);
976 err = mStatus_NoError;
978 else if (inResp->type == kResponseType_IPv6Addr)
980 ResolveStatsIPv6Addr ** p;
981 ResolveStatsIPv6Addr * addrV6;
983 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
985 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
989 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
990 err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
991 require_noerr_quiet(err, exit);
992 gResolveStatsObjCount++;
996 increment_saturate(addrV6->count, UINT16_MAX);
997 err = mStatus_NoError;
999 else if (inResp->type == kResponseType_NegAAAA)
1001 ResolveStatsNegAAAASet ** p;
1002 ResolveStatsNegAAAASet * negV6;
1004 NegAAAACounter * counter;
1006 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1008 for (i = 0; i < (int)countof(negV6->counters); ++i)
1010 counter = &negV6->counters[i];
1011 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1013 if (i < (int)countof(negV6->counters)) break;
1017 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1018 err = ResolveStatsNegAAAASetCreate(&negV6);
1019 require_noerr_quiet(err, exit);
1020 gResolveStatsObjCount++;
1023 counter = &negV6->counters[0];
1025 if (counter->count == 0) counter->serverID = inServerID;
1026 increment_saturate(counter->count, UINT16_MAX);
1027 err = mStatus_NoError;
1031 err = mStatus_Invalid;
1038 //===========================================================================================================================
1039 // ResolveStatsHostnameCreateAWDVersion
1040 //===========================================================================================================================
1042 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1045 AWDMDNSResponderResolveStatsHostname * hostname;
1047 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1049 ResolveStatsIPv4AddrSet * addrV4;
1050 ResolveStatsIPv6Addr * addrV6;
1051 ResolveStatsNegAAAASet * negV6;
1052 AWDMDNSResponderResolveStatsResult * result = nil;
1055 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1056 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1058 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1059 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1061 name = [[NSString alloc] initWithUTF8String:nameBuf];
1062 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1064 hostname.name = name;
1068 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1070 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1072 const IPv4AddrCounter * counter;
1075 counter = &addrV4->counters[i];
1076 if (counter->count == 0) break;
1078 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1079 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1081 if (counter->isNegative)
1083 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1087 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1088 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1090 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1091 result.data = addrBytes;
1092 [addrBytes release];
1094 result.count = counter->count;
1095 result.serverID = counter->serverID;
1097 [hostname addResult:result];
1103 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1107 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1108 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1110 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1111 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1113 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1114 result.count = addrV6->count;
1115 result.serverID = addrV6->serverID;
1116 result.data = addrBytes;
1118 [addrBytes release];
1120 [hostname addResult:result];
1125 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1127 for (i = 0; i < (int)countof(negV6->counters); ++i)
1129 const NegAAAACounter * counter;
1131 counter = &negV6->counters[i];
1132 if (counter->count == 0) break;
1134 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1135 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1137 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1138 result.count = counter->count;
1139 result.serverID = counter->serverID;
1141 [hostname addResult:result];
1147 *outHostname = hostname;
1149 err = mStatus_NoError;
1157 //===========================================================================================================================
1158 // ResolveStatsDNSServerCreate
1159 //===========================================================================================================================
1161 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1164 ResolveStatsDNSServer * obj;
1167 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1169 addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
1170 obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
1171 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1173 obj->isForCell = inForCell;
1174 if (inAddr->type == mDNSAddrType_IPv4)
1176 obj->isAddrV6 = mDNSfalse;
1177 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1181 obj->isAddrV6 = mDNStrue;
1182 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1186 err = mStatus_NoError;
1192 //===========================================================================================================================
1193 // ResolveStatsDNSServerFree
1194 //===========================================================================================================================
1196 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1201 //===========================================================================================================================
1202 // ResolveStatsDNSServerCreateAWDVersion
1203 //===========================================================================================================================
1205 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1208 AWDMDNSResponderResolveStatsDNSServer * server;
1209 NSData * addrBytes = nil;
1211 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1212 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1214 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1215 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1217 server.serverID = inServer->id;
1218 server.address = addrBytes;
1219 if (inServer->isForCell)
1221 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1225 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1228 *outServer = server;
1230 err = mStatus_NoError;
1233 [addrBytes release];
1238 //===========================================================================================================================
1239 // ResolveStatsIPv4AddrSetCreate
1240 //===========================================================================================================================
1242 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1245 ResolveStatsIPv4AddrSet * obj;
1247 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1248 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1251 err = mStatus_NoError;
1257 //===========================================================================================================================
1258 // ResolveStatsIPv4AddrSetFree
1259 //===========================================================================================================================
1261 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1266 //===========================================================================================================================
1267 // ResolveStatsIPv6AddressCreate
1268 //===========================================================================================================================
1270 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1273 ResolveStatsIPv6Addr * obj;
1275 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1276 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1278 obj->serverID = inServerID;
1279 memcpy(obj->addrBytes, inAddrBytes, 16);
1282 err = mStatus_NoError;
1288 //===========================================================================================================================
1289 // ResolveStatsIPv6AddressFree
1290 //===========================================================================================================================
1292 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1297 //===========================================================================================================================
1298 // ResolveStatsNegAAAASetCreate
1299 //===========================================================================================================================
1301 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1304 ResolveStatsNegAAAASet * obj;
1306 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1307 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1310 err = mStatus_NoError;
1316 //===========================================================================================================================
1317 // ResolveStatsNegAAAASetFree
1318 //===========================================================================================================================
1320 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1325 //===========================================================================================================================
1326 // ResolveStatsGetServerID
1327 //===========================================================================================================================
1329 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1332 ResolveStatsDNSServer ** p;
1333 ResolveStatsDNSServer * server;
1335 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1337 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1339 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1341 if (inServerAddr->type == mDNSAddrType_IPv4)
1343 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1347 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1354 require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
1355 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1356 err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
1357 require_noerr_quiet(err, exit);
1358 gResolveStatsObjCount++;
1360 server->id = gResolveStatsNextServerID++;
1361 server->next = gResolveStatsServerList;
1362 gResolveStatsServerList = server;
1364 else if (gResolveStatsServerList != server)
1367 server->next = gResolveStatsServerList;
1368 gResolveStatsServerList = server;
1371 *outServerID = server->id;
1372 err = mStatus_NoError;
1378 //===========================================================================================================================
1379 // CreateDomainStatsList
1380 //===========================================================================================================================
1382 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList)
1386 DNSDomainStats * stats;
1387 DNSDomainStats ** p;
1388 DNSDomainStats * list = NULL;
1391 for (i = 0; i < (int)countof(kQueryStatsDomains); ++i)
1393 err = DNSDomainStatsCreate(&kQueryStatsDomains[i], &stats);
1394 require_noerr_quiet(err, exit);
1404 DNSDomainStatsFreeList(list);
1408 //===========================================================================================================================
1409 // CreateResolveStatsList
1410 //===========================================================================================================================
1412 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1416 ResolveStatsDomain * domain;
1417 ResolveStatsDomain ** p;
1418 ResolveStatsDomain * list = NULL;
1421 for (i = 0; i < (int)countof(kResolveStatsDomains); ++i)
1423 err = ResolveStatsDomainCreate(&kResolveStatsDomains[i], &domain);
1424 require_noerr_quiet(err, exit);
1434 FreeResolveStatsList(list);
1438 //===========================================================================================================================
1439 // FreeResolveStatsList
1440 //===========================================================================================================================
1442 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1444 ResolveStatsDomain * domain;
1446 while ((domain = inList) != NULL)
1448 inList = domain->next;
1449 ResolveStatsDomainFree(domain);
1453 //===========================================================================================================================
1454 // FreeResolveStatsServerList
1455 //===========================================================================================================================
1457 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1459 ResolveStatsDNSServer * server;
1461 while ((server = inList) != NULL)
1463 inList = server->next;
1464 ResolveStatsDNSServerFree(server);
1468 //===========================================================================================================================
1470 //===========================================================================================================================
1472 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1478 case AWDMetricId_MDNSResponder_DNSStatistics:
1479 err = SubmitAWDMetricQueryStats();
1482 case AWDMetricId_MDNSResponder_ResolveStats:
1483 err = SubmitAWDMetricResolveStats();
1486 case AWDMetricId_MDNSResponder_ServicesStats:
1487 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
1489 // reset the no of max services since we want to collect the max no of services registered per AWD submission period
1490 max_num_regservices = curr_num_regservices;
1491 KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
1492 err = mStatus_NoError;
1496 err = mStatus_UnsupportedErr;
1500 if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1504 //===========================================================================================================================
1505 // SubmitAWDMetricQueryStats
1506 //===========================================================================================================================
1508 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1512 DNSDomainStats * stats;
1513 DNSDomainStats * newDomainStatsList;
1514 DNSDomainStats * domainStatsList = NULL;
1515 AWDMetricContainer * container = nil;
1516 AWDMDNSResponderDNSStatistics * metric = nil;
1518 err = CreateDomainStatsList(&newDomainStatsList);
1519 require_noerr_quiet(err, exit);
1522 domainStatsList = gDomainStatsList;
1523 gDomainStatsList = newDomainStatsList;
1524 KQueueUnlock("SubmitAWDMetricQueryStats");
1526 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1527 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1529 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1530 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1532 while ((stats = domainStatsList) != NULL)
1534 if (stats->nonCellular)
1536 err = AddAWDDNSDomainStats(metric, stats->nonCellular, stats->domain->cstr, mDNSfalse);
1537 require_noerr_quiet(err, exit);
1539 if (stats->cellular)
1541 err = AddAWDDNSDomainStats(metric, stats->cellular, stats->domain->cstr, mDNStrue);
1542 require_noerr_quiet(err, exit);
1544 domainStatsList = stats->next;
1545 DNSDomainStatsFree(stats);
1548 container.metric = metric;
1549 success = [gAWDServerConnection submitMetric:container];
1550 LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed" );
1551 err = success ? mStatus_NoError : mStatus_UnknownErr;
1555 [container release];
1556 DNSDomainStatsFreeList(domainStatsList);
1560 //===========================================================================================================================
1561 // SubmitAWDMetricResolveStats
1562 //===========================================================================================================================
1564 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1567 ResolveStatsDomain * newResolveStatsList;
1568 ResolveStatsDomain * domainList = NULL;
1569 ResolveStatsDNSServer * serverList = NULL;
1570 AWDMetricContainer * container = nil;
1571 AWDMDNSResponderResolveStats * metric = nil;
1572 ResolveStatsDNSServer * server;
1573 ResolveStatsDomain * domain;
1576 err = CreateResolveStatsList(&newResolveStatsList);
1577 require_noerr_quiet(err, exit);
1580 domainList = gResolveStatsList;
1581 serverList = gResolveStatsServerList;
1582 gResolveStatsList = newResolveStatsList;
1583 gResolveStatsServerList = NULL;
1584 gResolveStatsNextServerID = 0;
1585 gResolveStatsObjCount = 0;
1586 KQueueUnlock("SubmitAWDMetricResolveStats");
1588 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1589 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1591 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1592 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1594 while ((server = serverList) != NULL)
1596 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1598 serverList = server->next;
1599 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1600 ResolveStatsDNSServerFree(server);
1601 require_noerr_quiet(err, exit);
1603 [metric addServer:awdServer];
1604 [awdServer release];
1607 while ((domain = domainList) != NULL)
1609 AWDMDNSResponderResolveStatsDomain * awdDomain;
1611 domainList = domain->next;
1612 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1613 ResolveStatsDomainFree(domain);
1614 require_noerr_quiet(err, exit);
1616 [metric addDomain:awdDomain];
1617 [awdDomain release];
1620 container.metric = metric;
1621 success = [gAWDServerConnection submitMetric:container];
1622 LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed" );
1623 err = success ? mStatus_NoError : mStatus_UnknownErr;
1627 [container release];
1628 FreeResolveStatsList(domainList);
1629 FreeResolveStatsServerList(serverList);
1633 //===========================================================================================================================
1634 // CreateAWDDNSDomainStats
1635 //===========================================================================================================================
1637 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
1640 AWDDNSDomainStats * awdStats = nil;
1641 NSString * domain = nil;
1642 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
1643 uint32_t latencyBins[kQueryStatsLatencyBinCount];
1645 unsigned int totalAnswered;
1646 unsigned int totalNegAnswered;
1647 unsigned int totalUnanswered;
1649 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
1650 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
1652 domain = [[NSString alloc] initWithUTF8String:inDomain];
1653 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1655 awdStats.domain = domain;
1656 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
1657 awdStats.recordType = inType;
1660 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1662 sendCountBins[i] = inHist->answeredQuerySendCountBins[i];
1663 totalAnswered += inHist->answeredQuerySendCountBins[i];
1665 [awdStats setAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1667 totalNegAnswered = 0;
1668 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1670 sendCountBins[i] = inHist->negAnsweredQuerySendCountBins[i];
1671 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1673 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1675 totalUnanswered = 0;
1676 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1678 sendCountBins[i] = inHist->unansweredQuerySendCountBins[i];
1679 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1681 [awdStats setUnansweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1683 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1685 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1687 latencyBins[i] = inHist->responseLatencyBins[i];
1689 [awdStats setResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1692 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1694 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1696 latencyBins[i] = inHist->negResponseLatencyBins[i];
1698 [awdStats setNegResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1701 if (totalUnanswered > 0)
1703 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1705 latencyBins[i] = inHist->unansweredQueryDurationBins[i];
1707 [awdStats setUnansweredQueryDurationMs:latencyBins count:kQueryStatsLatencyBinCount];
1710 *outStats = awdStats;
1712 err = mStatus_NoError;
1720 //===========================================================================================================================
1721 // AddAWDDNSDomainStats
1722 //===========================================================================================================================
1724 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1727 AWDDNSDomainStats * awdStats;
1731 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1732 require_noerr_quiet(err, exit);
1734 [inMetric addStats:awdStats];
1737 if (inSet->histAAAA)
1739 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1740 require_noerr_quiet(err, exit);
1742 [inMetric addStats:awdStats];
1745 err = mStatus_NoError;
1751 //===========================================================================================================================
1753 //===========================================================================================================================
1755 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1757 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
1758 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
1761 //===========================================================================================================================
1763 //===========================================================================================================================
1765 #define Percent(N, D) ((N) * 100) / (D), (((N) * 10000) / (D)) % 100
1766 #define PercentFmt "%3u.%02u"
1767 #define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
1768 LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
1770 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
1772 unsigned int totalAnswered;
1773 unsigned int totalNegAnswered;
1774 unsigned int totalUnanswered;
1778 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1780 totalAnswered += inHist->answeredQuerySendCountBins[i];
1783 totalNegAnswered = 0;
1784 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1786 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1789 totalUnanswered = 0;
1790 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1792 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1795 LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
1796 LogMsgNoIdent("Answered questions %4u", totalAnswered);
1797 LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
1798 LogMsgNoIdent("Unanswered questions %4u", totalUnanswered);
1799 LogMsgNoIdent("-- Query send counts ---------");
1800 LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
1801 LogMsgNoIdent("-- Query send counts (NAQs) --");
1802 LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
1804 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1806 LogMsgNoIdent("--- Response times -----------");
1807 LogDNSHistLatencies(inHist->responseLatencyBins);
1810 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1812 LogMsgNoIdent("--- Response times (NAQs) ----");
1813 LogDNSHistLatencies(inHist->negResponseLatencyBins);
1816 if (totalUnanswered > 0)
1818 LogMsgNoIdent("--- Unanswered query times ---");
1819 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
1823 //===========================================================================================================================
1824 // LogDNSHistSendCounts
1825 //===========================================================================================================================
1827 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
1834 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1836 total += inSendCountBins[i];
1841 uint32_t accumulator = 0;
1843 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1845 accumulator += inSendCountBins[i];
1846 if (i < (kQueryStatsSendCountBinCount - 1))
1848 snprintf(label, sizeof(label), "%2d ", i);
1852 snprintf(label, sizeof(label), "%2d+", i);
1854 LogStat(label, inSendCountBins[i], accumulator, total);
1855 if (accumulator == total) break;
1860 LogMsgNoIdent("No data.");
1864 //===========================================================================================================================
1865 // LogDNSHistLatencies
1866 //===========================================================================================================================
1868 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
1875 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1877 total += inLatencyBins[i];
1882 uint32_t accumulator = 0;
1884 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1886 accumulator += inLatencyBins[i];
1887 if (i < (int)countof(kResponseLatencyMsLimits))
1889 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
1893 snprintf(label, sizeof(label), "< ∞ ms");
1895 LogStat(label, inLatencyBins[i], accumulator, total);
1896 if (accumulator == total) break;
1901 LogMsgNoIdent("No data.");
1905 //===========================================================================================================================
1906 // ValidateDNSStatsDomains
1907 //===========================================================================================================================
1909 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
1910 #warning "Do not include ValidateDNSStatsDomains() in customer release!"
1911 mDNSlocal void ValidateDNSStatsDomains(void)
1914 const Domain * domain;
1916 domainname domainNameExpected;
1917 int labelCountExpected;
1918 mDNSBool domainNamesEqual;
1919 mDNSBool failed = mDNSfalse;
1921 for (i = 0; i < countof(kQueryStatsDomains); ++i)
1923 domain = &kQueryStatsDomains[i];
1925 if (strcmp(domain->cstr, ".") == 0)
1927 domainNameExpected.c[0] = 0;
1931 ptr = MakeDomainNameFromDNSNameString(&domainNameExpected, domain->cstr);
1934 LogMsg("ValidateDNSStatsDomains: Failed to make domain name for \"%s\".", domain->cstr);
1940 domainNamesEqual = SameDomainName(domain->name, &domainNameExpected);
1941 labelCountExpected = CountLabels(&domainNameExpected);
1942 if (domainNamesEqual && (domain->labelCount == labelCountExpected))
1944 LogMsg("ValidateDNSStatsDomains: \"%s\" passed.", domain->cstr);
1948 if (!domainNamesEqual)
1950 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect domain name.", domain->cstr);
1952 if (domain->labelCount != labelCountExpected)
1954 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect label count. Actual %d, expected %d.",
1955 domain->cstr, domain->labelCount, labelCountExpected);
1962 if (failed) abort();
1965 #endif // TARGET_OS_EMBEDDED