]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Metrics.m
mDNSResponder-878.1.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Metrics.m
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18 #import "Metrics.h"
19
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>
32
33 #import "DNSCommon.h"
34 #import "mDNSMacOSX.h"
35 #import "DebugServices.h"
36
37 //===========================================================================================================================
38 // External Frameworks
39 //===========================================================================================================================
40
41 SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics)
42
43 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)
52
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()
62
63 //===========================================================================================================================
64 // Macros
65 //===========================================================================================================================
66
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)
71
72 //===========================================================================================================================
73 // Constants
74 //===========================================================================================================================
75
76 #define kQueryStatsMaxQuerySendCount 10
77 #define kQueryStatsSendCountBinCount (kQueryStatsMaxQuerySendCount + 1)
78 #define kQueryStatsLatencyBinCount 55
79 #define kResolveStatsMaxObjCount 2000
80
81 //===========================================================================================================================
82 // Data structures
83 //===========================================================================================================================
84
85 typedef struct
86 {
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.
90
91 } Domain;
92
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.
95
96 static const Domain kQueryStatsDomains[] =
97 {
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 },
107 };
108
109 check_compile_time(countof(kQueryStatsDomains) == 9);
110
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.
113 //
114 // answeredQuerySendCountBins
115 //
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.
118 //
119 // unansweredQuerySendCountBins
120 //
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.
123 //
124 // responseLatencyBins
125 //
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, ∞.
131
132 typedef struct
133 {
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];
140
141 } DNSHist;
142
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));
147
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.
150
151 static const mDNSu32 kResponseLatencyMsLimits[] =
152 {
153 1, 2, 3, 4, 5,
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,
159 10000
160 };
161
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));
166
167 typedef struct
168 {
169 DNSHist * histA; // Histogram data for queries for A resource records.
170 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
171
172 } DNSHistSet;
173
174 typedef struct DNSDomainStats DNSDomainStats;
175 struct DNSDomainStats
176 {
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.
181 };
182
183 check_compile_time(sizeof(struct DNSDomainStats) <= 32);
184
185 static const Domain kResolveStatsDomains[] =
186 {
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 },
191 };
192
193 check_compile_time(countof(kResolveStatsDomains) == 4);
194
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;
201
202 struct ResolveStatsDomain
203 {
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.
207 };
208
209 struct ResolveStatsHostname
210 {
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.
216 };
217
218 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
219
220 struct ResolveStatsDNSServer
221 {
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.
227 };
228
229 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
230
231 typedef struct
232 {
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.
235 uint8_t isNegative;
236 uint8_t addrBytes[4]; // IPv4 address bytes.
237
238 } IPv4AddrCounter;
239
240 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
241
242 struct ResolveStatsIPv4AddrSet
243 {
244 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
245 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
246 };
247
248 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
249
250 struct ResolveStatsIPv6Addr
251 {
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.
256 };
257
258 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
259
260 typedef struct
261 {
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.
264
265 } NegAAAACounter;
266
267 check_compile_time(sizeof(NegAAAACounter) <= 4);
268
269 struct ResolveStatsNegAAAASet
270 {
271 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
272 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
273 };
274
275 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
276
277 typedef enum
278 {
279 kResponseType_IPv4Addr = 1,
280 kResponseType_IPv6Addr = 2,
281 kResponseType_NegA = 3,
282 kResponseType_NegAAAA = 4
283
284 } ResponseType;
285
286 typedef struct
287 {
288 ResponseType type;
289 const uint8_t * data;
290
291 } Response;
292
293 //===========================================================================================================================
294 // Globals
295 //===========================================================================================================================
296
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;
303
304 //===========================================================================================================================
305 // Local Prototypes
306 //===========================================================================================================================
307
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);
312
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);
317
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);
322
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);
326
327 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
328 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
329
330 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
331 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
332
333 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
334 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
335 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
336
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);
352 #endif
353
354 //===========================================================================================================================
355 // MetricsInit
356 //===========================================================================================================================
357
358 mStatus MetricsInit(void)
359 {
360 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
361 ValidateDNSStatsDomains();
362 #endif
363
364 @autoreleasepool
365 {
366 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
367 initWithComponentId: AWDComponentId_MDNSResponder
368 andBlockOnConfiguration: NO];
369
370 if (gAWDServerConnection)
371 {
372 [gAWDServerConnection
373 registerQueriableMetricCallback: ^(UInt32 inMetricID)
374 {
375 SubmitAWDMetric(inMetricID);
376 }
377 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
378
379 [gAWDServerConnection
380 registerQueriableMetricCallback: ^(UInt32 inMetricID)
381 {
382 SubmitAWDMetric(inMetricID);
383 }
384 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
385
386 [gAWDServerConnection
387 registerQueriableMetricCallback: ^(UInt32 inMetricID)
388 {
389 SubmitAWDMetric(inMetricID);
390 }
391 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
392 }
393 else
394 {
395 LogMsg("MetricsInit: failed to create AWD server connection.");
396 }
397 }
398
399 if( gAWDServerConnection )
400 {
401 CreateDomainStatsList(&gDomainStatsList);
402 CreateResolveStatsList(&gResolveStatsList);
403 }
404
405 return (mStatus_NoError);
406 }
407
408 //===========================================================================================================================
409 // MetricsUpdateUDNSQueryStats
410 //===========================================================================================================================
411
412 mDNSexport void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
413 {
414 DNSDomainStats * stats;
415 int queryLabelCount;
416 const domainname * queryParentDomain;
417 mDNSBool isQueryInDomain;
418 int skipCount;
419 int skipCountLast = -1;
420
421 require_quiet(gAWDServerConnection, exit);
422 require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
423
424 queryLabelCount = CountLabels(inQueryName);
425
426 for (stats = gDomainStatsList; stats; stats = stats->next)
427 {
428 isQueryInDomain = mDNSfalse;
429 if (strcmp(stats->domain->cstr, ".") == 0)
430 {
431 // All queries are in the root domain.
432 isQueryInDomain = mDNStrue;
433 }
434 else
435 {
436 skipCount = queryLabelCount - stats->domain->labelCount;
437 if (skipCount >= 0)
438 {
439 if (skipCount != skipCountLast)
440 {
441 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
442 skipCountLast = skipCount;
443 }
444 isQueryInDomain = SameDomainName(queryParentDomain, stats->domain->name);
445 }
446 }
447
448 if (isQueryInDomain)
449 {
450 DNSDomainStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
451 }
452 }
453
454 exit:
455 return;
456 }
457
458 //===========================================================================================================================
459 // MetricsUpdateUDNSResolveStats
460 //===========================================================================================================================
461
462 mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
463 {
464 ResolveStatsDomain * domain;
465 domainname hostname;
466 size_t hostnameLen;
467 mDNSBool isQueryInDomain;
468 int skipCount;
469 int skipCountLast = -1;
470 int queryLabelCount;
471 const domainname * queryParentDomain;
472 Response response;
473
474 require_quiet(gAWDServerConnection, exit);
475 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
476 require_quiet(inRR->rDNSServer, exit);
477
478 queryLabelCount = CountLabels(inQueryName);
479
480 for (domain = gResolveStatsList; domain; domain = domain->next)
481 {
482 isQueryInDomain = mDNSfalse;
483 skipCount = queryLabelCount - domain->domainInfo->labelCount;
484 if (skipCount >= 0)
485 {
486 if (skipCount != skipCountLast)
487 {
488 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
489 skipCountLast = skipCount;
490 }
491 isQueryInDomain = SameDomainName(queryParentDomain, domain->domainInfo->name);
492 }
493 if (!isQueryInDomain) continue;
494
495 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
496 if (hostnameLen >= sizeof(hostname.c)) continue;
497
498 memcpy(hostname.c, inQueryName->c, hostnameLen);
499 hostname.c[hostnameLen] = 0;
500
501 if (inRR->RecordType == kDNSRecordTypePacketNegative)
502 {
503 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
504 response.data = NULL;
505 }
506 else
507 {
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;
510 }
511 ResolveStatsDomainUpdate(domain, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
512 }
513
514 exit:
515 return;
516 }
517
518 //===========================================================================================================================
519 // LogMetrics
520 //===========================================================================================================================
521
522 mDNSexport void LogMetrics(void)
523 {
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;
531 int hostnameCount;
532 int i;
533 unsigned int serverID;
534 int serverObjCount = 0;
535 int hostnameObjCount = 0;
536 int addrObjCount = 0;
537
538 LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
539 LogMsgNoIdent("---- DNS query stats by domain -----");
540
541 for (stats = gDomainStatsList; stats; stats = stats->next)
542 {
543 if (!stats->nonCellular && !stats->cellular)
544 {
545 LogMsgNoIdent("No data for %s", stats->domain->cstr);
546 continue;
547 }
548 if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, stats->domain->cstr, mDNSfalse);
549 if (stats->cellular) LogDNSHistSet(stats->cellular, stats->domain->cstr, mDNStrue);
550 }
551
552 LogMsgNoIdent("---- DNS resolve stats by domain -----");
553
554 LogMsgNoIdent("Servers:");
555 for (server = gResolveStatsServerList; server; server = server->next)
556 {
557 serverObjCount++;
558 LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
559 server->id, server->isForCell ? " C" : "NC", server->addrBytes);
560 }
561
562 for (domain = gResolveStatsList; domain; domain = domain->next)
563 {
564 hostnameCount = 0;
565 for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
566 hostnameObjCount += hostnameCount;
567
568 LogMsgNoIdent("%##s (%d hostname%s)", domain->domainInfo->name, hostnameCount, (hostnameCount == 1) ? "" : "s");
569
570 for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
571 {
572 LogMsgNoIdent(" %##s", hostname->name);
573 for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
574 {
575 for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
576 {
577 if (serverID == 0) addrObjCount++;
578 for (i = 0; i < (int)countof(addrV4->counters); ++i)
579 {
580 const IPv4AddrCounter * counter;
581
582 counter = &addrV4->counters[i];
583 if (counter->count == 0) break;
584 if (counter->serverID == serverID)
585 {
586 if (counter->isNegative)
587 {
588 LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
589 }
590 else
591 {
592 LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
593 }
594 }
595 }
596 }
597 for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
598 {
599 if (serverID == 0) addrObjCount++;
600 if (addrV6->serverID == serverID)
601 {
602 LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
603 }
604 }
605 for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
606 {
607 if (serverID == 0) addrObjCount++;
608 for (i = 0; i < (int)countof(negV6->counters); ++i)
609 {
610 const NegAAAACounter * counter;
611
612 counter = &negV6->counters[i];
613 if (counter->count == 0) break;
614 if (counter->serverID == serverID)
615 {
616 LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
617 }
618 }
619 }
620 }
621 }
622 }
623 LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
624 serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
625
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);
629 }
630
631 //===========================================================================================================================
632 // DNSDomainStatsCreate
633 //===========================================================================================================================
634
635 mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats)
636 {
637 mStatus err;
638 DNSDomainStats * obj;
639
640 obj = (DNSDomainStats *)calloc(1, sizeof(*obj));
641 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
642
643 obj->domain = inDomain;
644
645 *outStats = obj;
646 err = mStatus_NoError;
647
648 exit:
649 return (err);
650 }
651
652 //===========================================================================================================================
653 // DNSDomainStatsFree
654 //===========================================================================================================================
655
656 mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats)
657 {
658 if (inStats->nonCellular)
659 {
660 ForgetMem(&inStats->nonCellular->histA);
661 ForgetMem(&inStats->nonCellular->histAAAA);
662 free(inStats->nonCellular);
663 inStats->nonCellular = NULL;
664 }
665 if (inStats->cellular)
666 {
667 ForgetMem(&inStats->cellular->histA);
668 ForgetMem(&inStats->cellular->histAAAA);
669 free(inStats->cellular);
670 inStats->cellular = NULL;
671 }
672 free(inStats);
673 }
674
675 //===========================================================================================================================
676 // DNSDomainStatsFreeList
677 //===========================================================================================================================
678
679 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList)
680 {
681 DNSDomainStats * stats;
682
683 while ((stats = inList) != NULL)
684 {
685 inList = stats->next;
686 DNSDomainStatsFree(stats);
687 }
688 }
689
690 //===========================================================================================================================
691 // DNSDomainStatsUpdate
692 //===========================================================================================================================
693
694 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
695 {
696 mStatus err;
697 DNSHistSet * set;
698 DNSHistSet ** pSet;
699 DNSHist * hist;
700 DNSHist ** pHist;
701 int i;
702
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);
705
706 pSet = inForCell ? &inStats->cellular : &inStats->nonCellular;
707 if ((set = *pSet) == NULL)
708 {
709 set = (DNSHistSet *)calloc(1, sizeof(*set));
710 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
711 *pSet = set;
712 }
713 pHist = (inType == kDNSType_A) ? &set->histA : &set->histAAAA;
714 if ((hist = *pHist) == NULL)
715 {
716 hist = (DNSHist *)calloc(1, sizeof(*hist));
717 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
718 *pHist = hist;
719 }
720
721 if (inRR)
722 {
723 uint16_t * sendCountBins;
724 uint16_t * latencyBins;
725 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
726
727 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
728
729 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
730 increment_saturate(sendCountBins[i], UINT16_MAX);
731
732 if (inQuerySendCount > 0)
733 {
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);
737 }
738 }
739 else
740 {
741 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
742 increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
743
744 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
745 increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
746 }
747 err = mStatus_NoError;
748
749 exit:
750 return (err);
751 }
752
753 //===========================================================================================================================
754 // ResolveStatsDomainCreate
755 //===========================================================================================================================
756
757 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain)
758 {
759 mStatus err;
760 ResolveStatsDomain * obj;
761
762 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
763 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
764
765 obj->domainInfo = inDomain;
766
767 *outDomain = obj;
768 err = mStatus_NoError;
769
770 exit:
771 return (err);
772 }
773
774 //===========================================================================================================================
775 // ResolveStatsDomainFree
776 //===========================================================================================================================
777
778 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
779 {
780 ResolveStatsHostname * hostname;
781
782 while ((hostname = inDomain->hostnameList) != NULL)
783 {
784 inDomain->hostnameList = hostname->next;
785 ResolveStatsHostnameFree(hostname);
786 }
787 free(inDomain);
788 }
789
790 //===========================================================================================================================
791 // ResolveStatsDomainUpdate
792 //===========================================================================================================================
793
794 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
795 {
796 mStatus err;
797 ResolveStatsHostname ** p;
798 ResolveStatsHostname * hostname;
799 uint8_t serverID;
800
801 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
802 {
803 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
804 }
805
806 if (!hostname)
807 {
808 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
809 err = ResolveStatsHostnameCreate(inHostname, &hostname);
810 require_noerr_quiet(err, exit);
811 gResolveStatsObjCount++;
812 *p = hostname;
813 }
814
815 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
816 require_noerr_quiet(err, exit);
817
818 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
819 require_noerr_quiet(err, exit);
820
821 exit:
822 return (err);
823 }
824
825 //===========================================================================================================================
826 // ResolveStatsHostnameCreate
827 //===========================================================================================================================
828
829 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
830 {
831 mStatus err;
832 ResolveStatsHostname * obj;
833 size_t nameLen;
834
835 nameLen = DomainNameLength(inName);
836 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
837
838 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
839 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
840
841 memcpy(obj->name, inName, nameLen);
842
843 *outHostname = obj;
844 err = mStatus_NoError;
845
846 exit:
847 return (err);
848 }
849
850 //===========================================================================================================================
851 // ResolveStatsDomainCreateAWDVersion
852 //===========================================================================================================================
853
854 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
855 {
856 mStatus err;
857 AWDMDNSResponderResolveStatsDomain * domain;
858 ResolveStatsHostname * hostname;
859 AWDMDNSResponderResolveStatsHostname * awdHostname;
860 NSString * name;
861
862 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
863 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
864
865 name = [[NSString alloc] initWithUTF8String:inDomain->domainInfo->cstr];
866 require_action_quiet(name, exit, err = mStatus_UnknownErr);
867
868 domain.name = name;
869 [name release];
870 name = nil;
871
872 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
873 {
874 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
875 require_noerr_quiet(err, exit);
876
877 [domain addHostname:awdHostname];
878 [awdHostname release];
879 awdHostname = nil;
880 }
881
882 *outDomain = domain;
883 domain = nil;
884 err = mStatus_NoError;
885
886 exit:
887 [domain release];
888 return (err);
889 }
890
891 //===========================================================================================================================
892 // ResolveStatsHostnameFree
893 //===========================================================================================================================
894
895 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
896 {
897 ResolveStatsIPv4AddrSet * addrV4;
898 ResolveStatsIPv6Addr * addrV6;
899 ResolveStatsNegAAAASet * negV6;
900
901 while ((addrV4 = inHostname->addrV4List) != NULL)
902 {
903 inHostname->addrV4List = addrV4->next;
904 ResolveStatsIPv4AddrSetFree(addrV4);
905 }
906 while ((addrV6 = inHostname->addrV6List) != NULL)
907 {
908 inHostname->addrV6List = addrV6->next;
909 ResolveStatsIPv6AddressFree(addrV6);
910 }
911 while ((negV6 = inHostname->negV6List) != NULL)
912 {
913 inHostname->negV6List = negV6->next;
914 ResolveStatsNegAAAASetFree(negV6);
915 }
916 free(inHostname);
917 }
918
919 //===========================================================================================================================
920 // ResolveStatsHostnameUpdate
921 //===========================================================================================================================
922
923 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
924 {
925 mStatus err;
926
927 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
928 {
929 ResolveStatsIPv4AddrSet ** p;
930 ResolveStatsIPv4AddrSet * addrV4;
931 int i;
932 IPv4AddrCounter * counter;
933
934 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
935 {
936 for (i = 0; i < (int)countof(addrV4->counters); ++i)
937 {
938 counter = &addrV4->counters[i];
939 if (counter->count == 0) break;
940 if (counter->serverID != inServerID) continue;
941 if (inResp->type == kResponseType_NegA)
942 {
943 if (counter->isNegative) break;
944 }
945 else
946 {
947 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
948 }
949 }
950 if (i < (int)countof(addrV4->counters)) break;
951 }
952 if (!addrV4)
953 {
954 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
955 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
956 require_noerr_quiet(err, exit);
957 gResolveStatsObjCount++;
958
959 *p = addrV4;
960 counter = &addrV4->counters[0];
961 }
962 if (counter->count == 0)
963 {
964 counter->serverID = inServerID;
965 if (inResp->type == kResponseType_NegA)
966 {
967 counter->isNegative = 1;
968 }
969 else
970 {
971 counter->isNegative = 0;
972 memcpy(counter->addrBytes, inResp->data, 4);
973 }
974 }
975 increment_saturate(counter->count, UINT16_MAX);
976 err = mStatus_NoError;
977 }
978 else if (inResp->type == kResponseType_IPv6Addr)
979 {
980 ResolveStatsIPv6Addr ** p;
981 ResolveStatsIPv6Addr * addrV6;
982
983 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
984 {
985 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
986 }
987 if (!addrV6)
988 {
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++;
993
994 *p = addrV6;
995 }
996 increment_saturate(addrV6->count, UINT16_MAX);
997 err = mStatus_NoError;
998 }
999 else if (inResp->type == kResponseType_NegAAAA)
1000 {
1001 ResolveStatsNegAAAASet ** p;
1002 ResolveStatsNegAAAASet * negV6;
1003 int i;
1004 NegAAAACounter * counter;
1005
1006 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1007 {
1008 for (i = 0; i < (int)countof(negV6->counters); ++i)
1009 {
1010 counter = &negV6->counters[i];
1011 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1012 }
1013 if (i < (int)countof(negV6->counters)) break;
1014 }
1015 if (!negV6)
1016 {
1017 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1018 err = ResolveStatsNegAAAASetCreate(&negV6);
1019 require_noerr_quiet(err, exit);
1020 gResolveStatsObjCount++;
1021
1022 *p = negV6;
1023 counter = &negV6->counters[0];
1024 }
1025 if (counter->count == 0) counter->serverID = inServerID;
1026 increment_saturate(counter->count, UINT16_MAX);
1027 err = mStatus_NoError;
1028 }
1029 else
1030 {
1031 err = mStatus_Invalid;
1032 }
1033
1034 exit:
1035 return (err);
1036 }
1037
1038 //===========================================================================================================================
1039 // ResolveStatsHostnameCreateAWDVersion
1040 //===========================================================================================================================
1041
1042 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1043 {
1044 mStatus err;
1045 AWDMDNSResponderResolveStatsHostname * hostname;
1046 NSString * name;
1047 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1048 const char * ptr;
1049 ResolveStatsIPv4AddrSet * addrV4;
1050 ResolveStatsIPv6Addr * addrV6;
1051 ResolveStatsNegAAAASet * negV6;
1052 AWDMDNSResponderResolveStatsResult * result = nil;
1053 int i;
1054
1055 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1056 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1057
1058 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1059 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1060
1061 name = [[NSString alloc] initWithUTF8String:nameBuf];
1062 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1063
1064 hostname.name = name;
1065 [name release];
1066 name = nil;
1067
1068 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1069 {
1070 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1071 {
1072 const IPv4AddrCounter * counter;
1073 NSData * addrBytes;
1074
1075 counter = &addrV4->counters[i];
1076 if (counter->count == 0) break;
1077
1078 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1079 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1080
1081 if (counter->isNegative)
1082 {
1083 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1084 }
1085 else
1086 {
1087 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1088 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1089
1090 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1091 result.data = addrBytes;
1092 [addrBytes release];
1093 }
1094 result.count = counter->count;
1095 result.serverID = counter->serverID;
1096
1097 [hostname addResult:result];
1098 [result release];
1099 result = nil;
1100 }
1101 }
1102
1103 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1104 {
1105 NSData * addrBytes;
1106
1107 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1108 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1109
1110 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1111 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1112
1113 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1114 result.count = addrV6->count;
1115 result.serverID = addrV6->serverID;
1116 result.data = addrBytes;
1117
1118 [addrBytes release];
1119
1120 [hostname addResult:result];
1121 [result release];
1122 result = nil;
1123 }
1124
1125 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1126 {
1127 for (i = 0; i < (int)countof(negV6->counters); ++i)
1128 {
1129 const NegAAAACounter * counter;
1130
1131 counter = &negV6->counters[i];
1132 if (counter->count == 0) break;
1133
1134 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1135 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1136
1137 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1138 result.count = counter->count;
1139 result.serverID = counter->serverID;
1140
1141 [hostname addResult:result];
1142 [result release];
1143 result = nil;
1144 }
1145 }
1146
1147 *outHostname = hostname;
1148 hostname = nil;
1149 err = mStatus_NoError;
1150
1151 exit:
1152 [result release];
1153 [hostname release];
1154 return (err);
1155 }
1156
1157 //===========================================================================================================================
1158 // ResolveStatsDNSServerCreate
1159 //===========================================================================================================================
1160
1161 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1162 {
1163 mStatus err;
1164 ResolveStatsDNSServer * obj;
1165 size_t addrLen;
1166
1167 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1168
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);
1172
1173 obj->isForCell = inForCell;
1174 if (inAddr->type == mDNSAddrType_IPv4)
1175 {
1176 obj->isAddrV6 = mDNSfalse;
1177 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1178 }
1179 else
1180 {
1181 obj->isAddrV6 = mDNStrue;
1182 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1183 }
1184
1185 *outServer = obj;
1186 err = mStatus_NoError;
1187
1188 exit:
1189 return (err);
1190 }
1191
1192 //===========================================================================================================================
1193 // ResolveStatsDNSServerFree
1194 //===========================================================================================================================
1195
1196 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1197 {
1198 free(inServer);
1199 }
1200
1201 //===========================================================================================================================
1202 // ResolveStatsDNSServerCreateAWDVersion
1203 //===========================================================================================================================
1204
1205 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1206 {
1207 mStatus err;
1208 AWDMDNSResponderResolveStatsDNSServer * server;
1209 NSData * addrBytes = nil;
1210
1211 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1212 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1213
1214 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1215 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1216
1217 server.serverID = inServer->id;
1218 server.address = addrBytes;
1219 if (inServer->isForCell)
1220 {
1221 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1222 }
1223 else
1224 {
1225 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1226 }
1227
1228 *outServer = server;
1229 server = nil;
1230 err = mStatus_NoError;
1231
1232 exit:
1233 [addrBytes release];
1234 [server release];
1235 return (err);
1236 }
1237
1238 //===========================================================================================================================
1239 // ResolveStatsIPv4AddrSetCreate
1240 //===========================================================================================================================
1241
1242 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1243 {
1244 mStatus err;
1245 ResolveStatsIPv4AddrSet * obj;
1246
1247 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1248 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1249
1250 *outSet = obj;
1251 err = mStatus_NoError;
1252
1253 exit:
1254 return (err);
1255 }
1256
1257 //===========================================================================================================================
1258 // ResolveStatsIPv4AddrSetFree
1259 //===========================================================================================================================
1260
1261 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1262 {
1263 free(inSet);
1264 }
1265
1266 //===========================================================================================================================
1267 // ResolveStatsIPv6AddressCreate
1268 //===========================================================================================================================
1269
1270 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1271 {
1272 mStatus err;
1273 ResolveStatsIPv6Addr * obj;
1274
1275 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1276 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1277
1278 obj->serverID = inServerID;
1279 memcpy(obj->addrBytes, inAddrBytes, 16);
1280
1281 *outAddr = obj;
1282 err = mStatus_NoError;
1283
1284 exit:
1285 return (err);
1286 }
1287
1288 //===========================================================================================================================
1289 // ResolveStatsIPv6AddressFree
1290 //===========================================================================================================================
1291
1292 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1293 {
1294 free(inAddr);
1295 }
1296
1297 //===========================================================================================================================
1298 // ResolveStatsNegAAAASetCreate
1299 //===========================================================================================================================
1300
1301 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1302 {
1303 mStatus err;
1304 ResolveStatsNegAAAASet * obj;
1305
1306 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1307 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1308
1309 *outSet = obj;
1310 err = mStatus_NoError;
1311
1312 exit:
1313 return (err);
1314 }
1315
1316 //===========================================================================================================================
1317 // ResolveStatsNegAAAASetFree
1318 //===========================================================================================================================
1319
1320 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1321 {
1322 free(inSet);
1323 }
1324
1325 //===========================================================================================================================
1326 // ResolveStatsGetServerID
1327 //===========================================================================================================================
1328
1329 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1330 {
1331 mStatus err;
1332 ResolveStatsDNSServer ** p;
1333 ResolveStatsDNSServer * server;
1334
1335 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1336
1337 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1338 {
1339 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1340 {
1341 if (inServerAddr->type == mDNSAddrType_IPv4)
1342 {
1343 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1344 }
1345 else
1346 {
1347 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1348 }
1349 }
1350 }
1351
1352 if (!server)
1353 {
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++;
1359
1360 server->id = gResolveStatsNextServerID++;
1361 server->next = gResolveStatsServerList;
1362 gResolveStatsServerList = server;
1363 }
1364 else if (gResolveStatsServerList != server)
1365 {
1366 *p = server->next;
1367 server->next = gResolveStatsServerList;
1368 gResolveStatsServerList = server;
1369 }
1370
1371 *outServerID = server->id;
1372 err = mStatus_NoError;
1373
1374 exit:
1375 return (err);
1376 }
1377
1378 //===========================================================================================================================
1379 // CreateDomainStatsList
1380 //===========================================================================================================================
1381
1382 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList)
1383 {
1384 mStatus err;
1385 int i;
1386 DNSDomainStats * stats;
1387 DNSDomainStats ** p;
1388 DNSDomainStats * list = NULL;
1389
1390 p = &list;
1391 for (i = 0; i < (int)countof(kQueryStatsDomains); ++i)
1392 {
1393 err = DNSDomainStatsCreate(&kQueryStatsDomains[i], &stats);
1394 require_noerr_quiet(err, exit);
1395
1396 *p = stats;
1397 p = &stats->next;
1398 }
1399
1400 *outList = list;
1401 list = NULL;
1402
1403 exit:
1404 DNSDomainStatsFreeList(list);
1405 return (err);
1406 }
1407
1408 //===========================================================================================================================
1409 // CreateResolveStatsList
1410 //===========================================================================================================================
1411
1412 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1413 {
1414 mStatus err;
1415 int i;
1416 ResolveStatsDomain * domain;
1417 ResolveStatsDomain ** p;
1418 ResolveStatsDomain * list = NULL;
1419
1420 p = &list;
1421 for (i = 0; i < (int)countof(kResolveStatsDomains); ++i)
1422 {
1423 err = ResolveStatsDomainCreate(&kResolveStatsDomains[i], &domain);
1424 require_noerr_quiet(err, exit);
1425
1426 *p = domain;
1427 p = &domain->next;
1428 }
1429
1430 *outList = list;
1431 list = NULL;
1432
1433 exit:
1434 FreeResolveStatsList(list);
1435 return (err);
1436 }
1437
1438 //===========================================================================================================================
1439 // FreeResolveStatsList
1440 //===========================================================================================================================
1441
1442 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1443 {
1444 ResolveStatsDomain * domain;
1445
1446 while ((domain = inList) != NULL)
1447 {
1448 inList = domain->next;
1449 ResolveStatsDomainFree(domain);
1450 }
1451 }
1452
1453 //===========================================================================================================================
1454 // FreeResolveStatsServerList
1455 //===========================================================================================================================
1456
1457 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1458 {
1459 ResolveStatsDNSServer * server;
1460
1461 while ((server = inList) != NULL)
1462 {
1463 inList = server->next;
1464 ResolveStatsDNSServerFree(server);
1465 }
1466 }
1467
1468 //===========================================================================================================================
1469 // SubmitAWDMetric
1470 //===========================================================================================================================
1471
1472 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1473 {
1474 mStatus err;
1475
1476 switch (inMetricID)
1477 {
1478 case AWDMetricId_MDNSResponder_DNSStatistics:
1479 err = SubmitAWDMetricQueryStats();
1480 break;
1481
1482 case AWDMetricId_MDNSResponder_ResolveStats:
1483 err = SubmitAWDMetricResolveStats();
1484 break;
1485
1486 case AWDMetricId_MDNSResponder_ServicesStats:
1487 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
1488 KQueueLock();
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;
1493 break;
1494
1495 default:
1496 err = mStatus_UnsupportedErr;
1497 break;
1498 }
1499
1500 if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1501 return (err);
1502 }
1503
1504 //===========================================================================================================================
1505 // SubmitAWDMetricQueryStats
1506 //===========================================================================================================================
1507
1508 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1509 {
1510 mStatus err;
1511 BOOL success;
1512 DNSDomainStats * stats;
1513 DNSDomainStats * newDomainStatsList;
1514 DNSDomainStats * domainStatsList = NULL;
1515 AWDMetricContainer * container = nil;
1516 AWDMDNSResponderDNSStatistics * metric = nil;
1517
1518 err = CreateDomainStatsList(&newDomainStatsList);
1519 require_noerr_quiet(err, exit);
1520
1521 KQueueLock();
1522 domainStatsList = gDomainStatsList;
1523 gDomainStatsList = newDomainStatsList;
1524 KQueueUnlock("SubmitAWDMetricQueryStats");
1525
1526 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1527 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1528
1529 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1530 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1531
1532 while ((stats = domainStatsList) != NULL)
1533 {
1534 if (stats->nonCellular)
1535 {
1536 err = AddAWDDNSDomainStats(metric, stats->nonCellular, stats->domain->cstr, mDNSfalse);
1537 require_noerr_quiet(err, exit);
1538 }
1539 if (stats->cellular)
1540 {
1541 err = AddAWDDNSDomainStats(metric, stats->cellular, stats->domain->cstr, mDNStrue);
1542 require_noerr_quiet(err, exit);
1543 }
1544 domainStatsList = stats->next;
1545 DNSDomainStatsFree(stats);
1546 }
1547
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;
1552
1553 exit:
1554 [metric release];
1555 [container release];
1556 DNSDomainStatsFreeList(domainStatsList);
1557 return (err);
1558 }
1559
1560 //===========================================================================================================================
1561 // SubmitAWDMetricResolveStats
1562 //===========================================================================================================================
1563
1564 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1565 {
1566 mStatus err;
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;
1574 BOOL success;
1575
1576 err = CreateResolveStatsList(&newResolveStatsList);
1577 require_noerr_quiet(err, exit);
1578
1579 KQueueLock();
1580 domainList = gResolveStatsList;
1581 serverList = gResolveStatsServerList;
1582 gResolveStatsList = newResolveStatsList;
1583 gResolveStatsServerList = NULL;
1584 gResolveStatsNextServerID = 0;
1585 gResolveStatsObjCount = 0;
1586 KQueueUnlock("SubmitAWDMetricResolveStats");
1587
1588 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1589 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1590
1591 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1592 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1593
1594 while ((server = serverList) != NULL)
1595 {
1596 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1597
1598 serverList = server->next;
1599 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1600 ResolveStatsDNSServerFree(server);
1601 require_noerr_quiet(err, exit);
1602
1603 [metric addServer:awdServer];
1604 [awdServer release];
1605 }
1606
1607 while ((domain = domainList) != NULL)
1608 {
1609 AWDMDNSResponderResolveStatsDomain * awdDomain;
1610
1611 domainList = domain->next;
1612 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1613 ResolveStatsDomainFree(domain);
1614 require_noerr_quiet(err, exit);
1615
1616 [metric addDomain:awdDomain];
1617 [awdDomain release];
1618 }
1619
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;
1624
1625 exit:
1626 [metric release];
1627 [container release];
1628 FreeResolveStatsList(domainList);
1629 FreeResolveStatsServerList(serverList);
1630 return (err);
1631 }
1632
1633 //===========================================================================================================================
1634 // CreateAWDDNSDomainStats
1635 //===========================================================================================================================
1636
1637 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
1638 {
1639 mStatus err;
1640 AWDDNSDomainStats * awdStats = nil;
1641 NSString * domain = nil;
1642 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
1643 uint32_t latencyBins[kQueryStatsLatencyBinCount];
1644 int i;
1645 unsigned int totalAnswered;
1646 unsigned int totalNegAnswered;
1647 unsigned int totalUnanswered;
1648
1649 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
1650 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
1651
1652 domain = [[NSString alloc] initWithUTF8String:inDomain];
1653 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1654
1655 awdStats.domain = domain;
1656 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
1657 awdStats.recordType = inType;
1658
1659 totalAnswered = 0;
1660 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1661 {
1662 sendCountBins[i] = inHist->answeredQuerySendCountBins[i];
1663 totalAnswered += inHist->answeredQuerySendCountBins[i];
1664 }
1665 [awdStats setAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1666
1667 totalNegAnswered = 0;
1668 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1669 {
1670 sendCountBins[i] = inHist->negAnsweredQuerySendCountBins[i];
1671 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1672 }
1673 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1674
1675 totalUnanswered = 0;
1676 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1677 {
1678 sendCountBins[i] = inHist->unansweredQuerySendCountBins[i];
1679 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1680 }
1681 [awdStats setUnansweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1682
1683 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1684 {
1685 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1686 {
1687 latencyBins[i] = inHist->responseLatencyBins[i];
1688 }
1689 [awdStats setResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1690 }
1691
1692 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1693 {
1694 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1695 {
1696 latencyBins[i] = inHist->negResponseLatencyBins[i];
1697 }
1698 [awdStats setNegResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1699 }
1700
1701 if (totalUnanswered > 0)
1702 {
1703 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1704 {
1705 latencyBins[i] = inHist->unansweredQueryDurationBins[i];
1706 }
1707 [awdStats setUnansweredQueryDurationMs:latencyBins count:kQueryStatsLatencyBinCount];
1708 }
1709
1710 *outStats = awdStats;
1711 awdStats = nil;
1712 err = mStatus_NoError;
1713
1714 exit:
1715 [domain release];
1716 [awdStats release];
1717 return (err);
1718 }
1719
1720 //===========================================================================================================================
1721 // AddAWDDNSDomainStats
1722 //===========================================================================================================================
1723
1724 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1725 {
1726 mStatus err;
1727 AWDDNSDomainStats * awdStats;
1728
1729 if (inSet->histA)
1730 {
1731 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1732 require_noerr_quiet(err, exit);
1733
1734 [inMetric addStats:awdStats];
1735 [awdStats release];
1736 }
1737 if (inSet->histAAAA)
1738 {
1739 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1740 require_noerr_quiet(err, exit);
1741
1742 [inMetric addStats:awdStats];
1743 [awdStats release];
1744 }
1745 err = mStatus_NoError;
1746
1747 exit:
1748 return (err);
1749 }
1750
1751 //===========================================================================================================================
1752 // LogDNSHistSet
1753 //===========================================================================================================================
1754
1755 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1756 {
1757 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
1758 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
1759 }
1760
1761 //===========================================================================================================================
1762 // LogDNSHist
1763 //===========================================================================================================================
1764
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))
1769
1770 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
1771 {
1772 unsigned int totalAnswered;
1773 unsigned int totalNegAnswered;
1774 unsigned int totalUnanswered;
1775 int i;
1776
1777 totalAnswered = 0;
1778 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1779 {
1780 totalAnswered += inHist->answeredQuerySendCountBins[i];
1781 }
1782
1783 totalNegAnswered = 0;
1784 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1785 {
1786 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1787 }
1788
1789 totalUnanswered = 0;
1790 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1791 {
1792 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1793 }
1794
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);
1803
1804 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1805 {
1806 LogMsgNoIdent("--- Response times -----------");
1807 LogDNSHistLatencies(inHist->responseLatencyBins);
1808 }
1809
1810 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1811 {
1812 LogMsgNoIdent("--- Response times (NAQs) ----");
1813 LogDNSHistLatencies(inHist->negResponseLatencyBins);
1814 }
1815
1816 if (totalUnanswered > 0)
1817 {
1818 LogMsgNoIdent("--- Unanswered query times ---");
1819 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
1820 }
1821 }
1822
1823 //===========================================================================================================================
1824 // LogDNSHistSendCounts
1825 //===========================================================================================================================
1826
1827 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
1828 {
1829 uint32_t total;
1830 char label[16];
1831 int i;
1832
1833 total = 0;
1834 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1835 {
1836 total += inSendCountBins[i];
1837 }
1838
1839 if (total > 0)
1840 {
1841 uint32_t accumulator = 0;
1842
1843 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1844 {
1845 accumulator += inSendCountBins[i];
1846 if (i < (kQueryStatsSendCountBinCount - 1))
1847 {
1848 snprintf(label, sizeof(label), "%2d ", i);
1849 }
1850 else
1851 {
1852 snprintf(label, sizeof(label), "%2d+", i);
1853 }
1854 LogStat(label, inSendCountBins[i], accumulator, total);
1855 if (accumulator == total) break;
1856 }
1857 }
1858 else
1859 {
1860 LogMsgNoIdent("No data.");
1861 }
1862 }
1863
1864 //===========================================================================================================================
1865 // LogDNSHistLatencies
1866 //===========================================================================================================================
1867
1868 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
1869 {
1870 uint32_t total;
1871 int i;
1872 char label[16];
1873
1874 total = 0;
1875 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1876 {
1877 total += inLatencyBins[i];
1878 }
1879
1880 if (total > 0)
1881 {
1882 uint32_t accumulator = 0;
1883
1884 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1885 {
1886 accumulator += inLatencyBins[i];
1887 if (i < (int)countof(kResponseLatencyMsLimits))
1888 {
1889 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
1890 }
1891 else
1892 {
1893 snprintf(label, sizeof(label), "< ∞ ms");
1894 }
1895 LogStat(label, inLatencyBins[i], accumulator, total);
1896 if (accumulator == total) break;
1897 }
1898 }
1899 else
1900 {
1901 LogMsgNoIdent("No data.");
1902 }
1903 }
1904
1905 //===========================================================================================================================
1906 // ValidateDNSStatsDomains
1907 //===========================================================================================================================
1908
1909 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
1910 #warning "Do not include ValidateDNSStatsDomains() in customer release!"
1911 mDNSlocal void ValidateDNSStatsDomains(void)
1912 {
1913 int i;
1914 const Domain * domain;
1915 mDNSu8 * ptr;
1916 domainname domainNameExpected;
1917 int labelCountExpected;
1918 mDNSBool domainNamesEqual;
1919 mDNSBool failed = mDNSfalse;
1920
1921 for (i = 0; i < countof(kQueryStatsDomains); ++i)
1922 {
1923 domain = &kQueryStatsDomains[i];
1924
1925 if (strcmp(domain->cstr, ".") == 0)
1926 {
1927 domainNameExpected.c[0] = 0;
1928 }
1929 else
1930 {
1931 ptr = MakeDomainNameFromDNSNameString(&domainNameExpected, domain->cstr);
1932 if (!ptr)
1933 {
1934 LogMsg("ValidateDNSStatsDomains: Failed to make domain name for \"%s\".", domain->cstr);
1935 failed = mDNStrue;
1936 goto exit;
1937 }
1938 }
1939
1940 domainNamesEqual = SameDomainName(domain->name, &domainNameExpected);
1941 labelCountExpected = CountLabels(&domainNameExpected);
1942 if (domainNamesEqual && (domain->labelCount == labelCountExpected))
1943 {
1944 LogMsg("ValidateDNSStatsDomains: \"%s\" passed.", domain->cstr);
1945 }
1946 else
1947 {
1948 if (!domainNamesEqual)
1949 {
1950 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect domain name.", domain->cstr);
1951 }
1952 if (domain->labelCount != labelCountExpected)
1953 {
1954 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect label count. Actual %d, expected %d.",
1955 domain->cstr, domain->labelCount, labelCountExpected);
1956 }
1957 failed = mDNStrue;
1958 }
1959 }
1960
1961 exit:
1962 if (failed) abort();
1963 }
1964 #endif
1965 #endif // TARGET_OS_EMBEDDED