]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Metrics.m
mDNSResponder-765.1.2.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 { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 },
103 { "google.com.", (domainname *)"\x6" "google" "\x3" "com", 2 },
104 { "youtube.com.", (domainname *)"\x7" "youtube" "\x3" "com", 2 },
105 { "facebook.com.", (domainname *)"\x8" "facebook" "\x3" "com", 2 },
106 { "baidu.com.", (domainname *)"\x5" "baidu" "\x3" "com", 2 },
107 { "yahoo.com.", (domainname *)"\x5" "yahoo" "\x3" "com", 2 },
108 { "qq.com.", (domainname *)"\x2" "qq" "\x3" "com", 2 },
109 };
110
111 check_compile_time(countof(kQueryStatsDomains) == 11);
112
113 // DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
114 // <rdar://problem/23980546> MDNSResponder.proto update.
115 //
116 // answeredQuerySendCountBins
117 //
118 // An array of 11 histogram bins. The value at index i, for 0 <= i <= 9, is the number of times that an answered DNS query
119 // was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times.
120 //
121 // unansweredQuerySendCountBins
122 //
123 // An array of 11 histogram bins. The value at index i, for 0 <= i <= 9, is the number of times that an unanswered DNS query
124 // was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times.
125 //
126 // responseLatencyBins
127 //
128 // An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time
129 // interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are
130 // in milliseconds): 1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
131 // 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
132 // 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞.
133
134 typedef struct
135 {
136 uint16_t unansweredQuerySendCountBins[kQueryStatsSendCountBinCount];
137 uint16_t unansweredQueryDurationBins[kQueryStatsLatencyBinCount];
138 uint16_t answeredQuerySendCountBins[kQueryStatsSendCountBinCount];
139 uint16_t responseLatencyBins[kQueryStatsLatencyBinCount];
140 uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
141 uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount];
142
143 } DNSHist;
144
145 check_compile_time(sizeof(DNSHist) <= 512);
146 check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
147 check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
148 check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
149
150 // Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
151 // latency histogram bins to observe these time interval upper bounds.
152
153 static const mDNSu32 kResponseLatencyMsLimits[] =
154 {
155 1, 2, 3, 4, 5,
156 10, 20, 30, 40, 50, 60, 70, 80, 90,
157 100, 110, 120, 130, 140, 150, 160, 170, 180, 190,
158 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950,
159 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
160 5000, 6000, 7000, 8000, 9000,
161 10000
162 };
163
164 check_compile_time(countof(kResponseLatencyMsLimits) == 54);
165 check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1));
166 check_compile_time(countof_field(DNSHist, responseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
167 check_compile_time(countof_field(DNSHist, negResponseLatencyBins) == (countof(kResponseLatencyMsLimits) + 1));
168
169 typedef struct
170 {
171 DNSHist * histAny; // Histogram data for queries of any resource record type.
172 DNSHist * histA; // Histogram data for queries for A resource records.
173 DNSHist * histAAAA; // Histogram data for queries for AAAA resource records.
174
175 } DNSHistSet;
176
177 typedef struct DNSDomainStats DNSDomainStats;
178 struct DNSDomainStats
179 {
180 DNSDomainStats * next; // Pointer to next domain stats in list.
181 const Domain * domain; // Domain for which these stats are collected.
182 DNSHistSet * nonCellular; // Query stats for queries sent over non-cellular interfaces.
183 DNSHistSet * cellular; // Query stats for queries sent over cellular interfaces.
184 };
185
186 check_compile_time(sizeof(struct DNSDomainStats) <= 32);
187
188 static const Domain kResolveStatsDomains[] =
189 {
190 { "apple.com.", (domainname *)"\x5" "apple" "\x3" "com", 2 },
191 { "icloud.com.", (domainname *)"\x6" "icloud" "\x3" "com", 2 },
192 { "mzstatic.com.", (domainname *)"\x8" "mzstatic" "\x3" "com", 2 },
193 { "me.com.", (domainname *)"\x2" "me" "\x3" "com", 2 },
194 };
195
196 check_compile_time(countof(kResolveStatsDomains) == 4);
197
198 typedef struct ResolveStatsDomain ResolveStatsDomain;
199 typedef struct ResolveStatsHostname ResolveStatsHostname;
200 typedef struct ResolveStatsDNSServer ResolveStatsDNSServer;
201 typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet;
202 typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr;
203 typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet;
204
205 struct ResolveStatsDomain
206 {
207 ResolveStatsDomain * next; // Next domain object in list.
208 ResolveStatsHostname * hostnameList; // List of hostname objects in this domain.
209 const Domain * domainInfo; // Pointer to domain info.
210 };
211
212 struct ResolveStatsHostname
213 {
214 ResolveStatsHostname * next; // Next hostname object in list.
215 ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved.
216 ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved.
217 ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects.
218 uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels.
219 };
220
221 check_compile_time(sizeof(ResolveStatsHostname) <= 64);
222
223 struct ResolveStatsDNSServer
224 {
225 ResolveStatsDNSServer * next; // Next DNS server object in list.
226 uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects.
227 mDNSBool isForCell; // True if this DNS server belongs to a cellular interface.
228 mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4.
229 uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address.
230 };
231
232 check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
233
234 typedef struct
235 {
236 uint16_t count; // Number of times this IPv4 address was provided as a resolution result.
237 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came.
238 uint8_t isNegative;
239 uint8_t addrBytes[4]; // IPv4 address bytes.
240
241 } IPv4AddrCounter;
242
243 check_compile_time(sizeof(IPv4AddrCounter) <= 8);
244
245 struct ResolveStatsIPv4AddrSet
246 {
247 ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
248 IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
249 };
250
251 check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
252
253 struct ResolveStatsIPv6Addr
254 {
255 ResolveStatsIPv6Addr * next; // Next IPv6 address object in list.
256 uint16_t count; // Number of times this IPv6 address was provided as a resolution result.
257 uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came.
258 uint8_t addrBytes[16]; // IPv6 address bytes.
259 };
260
261 check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
262
263 typedef struct
264 {
265 uint16_t count; // Number of times that a negative response was returned by a DNS server.
266 uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses.
267
268 } NegAAAACounter;
269
270 check_compile_time(sizeof(NegAAAACounter) <= 4);
271
272 struct ResolveStatsNegAAAASet
273 {
274 ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
275 NegAAAACounter counters[6]; // Array of negative AAAA response counters.
276 };
277
278 check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
279
280 typedef enum
281 {
282 kResponseType_IPv4Addr = 1,
283 kResponseType_IPv6Addr = 2,
284 kResponseType_NegA = 3,
285 kResponseType_NegAAAA = 4
286
287 } ResponseType;
288
289 typedef struct
290 {
291 ResponseType type;
292 const uint8_t * data;
293
294 } Response;
295
296 //===========================================================================================================================
297 // Globals
298 //===========================================================================================================================
299
300 extern mDNS mDNSStorage;
301
302 static DNSDomainStats * gDomainStatsList = NULL;
303 static ResolveStatsDomain * gResolveStatsList = NULL;
304 static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
305 static unsigned int gResolveStatsNextServerID = 0;
306 static int gResolveStatsObjCount = 0;
307 static AWDServerConnection * gAWDServerConnection = nil;
308
309 //===========================================================================================================================
310 // Local Prototypes
311 //===========================================================================================================================
312
313 mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats);
314 mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats);
315 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList);
316 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, uint16_t inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
317
318 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain);
319 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
320 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
321 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
322
323 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
324 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
325 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
326 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
327
328 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
329 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
330 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
331
332 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
333 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
334
335 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
336 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
337
338 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
339 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
340 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
341
342 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList);
343 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList);
344 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList);
345 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
346 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID);
347 mDNSlocal mStatus SubmitAWDMetricQueryStats(void);
348 mDNSlocal mStatus SubmitAWDMetricResolveStats(void);
349 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
350 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
351 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
352 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
353 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
354 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
355 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
356 mDNSlocal void ValidateDNSStatsDomains(void);
357 #endif
358
359 //===========================================================================================================================
360 // MetricsInit
361 //===========================================================================================================================
362
363 mStatus MetricsInit(void)
364 {
365 mStatus err;
366
367 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
368 ValidateDNSStatsDomains();
369 #endif
370
371 err = CreateDomainStatsList(&gDomainStatsList);
372 require_noerr_quiet(err, exit);
373
374 err = CreateResolveStatsList(&gResolveStatsList);
375 require_noerr_quiet(err, exit);
376
377 @autoreleasepool
378 {
379 gAWDServerConnection = [[AWDServerConnectionSoft alloc]
380 initWithComponentId: AWDComponentId_MDNSResponder
381 andBlockOnConfiguration: NO];
382
383 if (gAWDServerConnection)
384 {
385 [gAWDServerConnection
386 registerQueriableMetricCallback: ^(UInt32 inMetricID)
387 {
388 SubmitAWDMetric(inMetricID);
389 }
390 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
391
392 [gAWDServerConnection
393 registerQueriableMetricCallback: ^(UInt32 inMetricID)
394 {
395 SubmitAWDMetric(inMetricID);
396 }
397 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
398
399 [gAWDServerConnection
400 registerQueriableMetricCallback: ^(UInt32 inMetricID)
401 {
402 SubmitAWDMetric(inMetricID);
403 }
404 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
405 }
406 else
407 {
408 LogMsg("MetricsInit: failed to create AWD server connection.");
409 }
410 }
411 exit:
412 return (err);
413 }
414
415 //===========================================================================================================================
416 // MetricsUpdateUDNSQueryStats
417 //===========================================================================================================================
418
419 mDNSexport void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
420 {
421 DNSDomainStats * stats;
422 int queryLabelCount;
423 const domainname * queryParentDomain;
424 mDNSBool isQueryInDomain;
425 int skipCount;
426 int skipCountLast = -1;
427
428 queryLabelCount = CountLabels(inQueryName);
429
430 for (stats = gDomainStatsList; stats; stats = stats->next)
431 {
432 isQueryInDomain = mDNSfalse;
433 if (strcmp(stats->domain->cstr, ".") == 0)
434 {
435 // All queries are in the root domain.
436 isQueryInDomain = mDNStrue;
437 }
438 else
439 {
440 skipCount = queryLabelCount - stats->domain->labelCount;
441 if (skipCount >= 0)
442 {
443 if (skipCount != skipCountLast)
444 {
445 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
446 skipCountLast = skipCount;
447 }
448 isQueryInDomain = SameDomainName(queryParentDomain, stats->domain->name);
449 }
450 }
451
452 if (isQueryInDomain)
453 {
454 DNSDomainStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
455 }
456 }
457
458 }
459
460 //===========================================================================================================================
461 // MetricsUpdateUDNSResolveStats
462 //===========================================================================================================================
463
464 mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
465 {
466 ResolveStatsDomain * domain;
467 domainname hostname;
468 size_t hostnameLen;
469 mDNSBool isQueryInDomain;
470 int skipCount;
471 int skipCountLast = -1;
472 int queryLabelCount;
473 const domainname * queryParentDomain;
474 Response response;
475
476 require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
477 require_quiet(inRR->rDNSServer, exit);
478
479 queryLabelCount = CountLabels(inQueryName);
480
481 for (domain = gResolveStatsList; domain; domain = domain->next)
482 {
483 isQueryInDomain = mDNSfalse;
484 skipCount = queryLabelCount - domain->domainInfo->labelCount;
485 if (skipCount >= 0)
486 {
487 if (skipCount != skipCountLast)
488 {
489 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
490 skipCountLast = skipCount;
491 }
492 isQueryInDomain = SameDomainName(queryParentDomain, domain->domainInfo->name);
493 }
494 if (!isQueryInDomain) continue;
495
496 hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
497 if (hostnameLen >= sizeof(hostname.c)) continue;
498
499 memcpy(hostname.c, inQueryName->c, hostnameLen);
500 hostname.c[hostnameLen] = 0;
501
502 if (inRR->RecordType == kDNSRecordTypePacketNegative)
503 {
504 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
505 response.data = NULL;
506 }
507 else
508 {
509 response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
510 response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
511 }
512 ResolveStatsDomainUpdate(domain, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
513 }
514
515 exit:
516 return;
517 }
518
519 //===========================================================================================================================
520 // LogMetrics
521 //===========================================================================================================================
522
523 mDNSexport void LogMetrics(void)
524 {
525 DNSDomainStats * stats;
526 const ResolveStatsDomain * domain;
527 const ResolveStatsHostname * hostname;
528 const ResolveStatsDNSServer * server;
529 const ResolveStatsIPv4AddrSet * addrV4;
530 const ResolveStatsIPv6Addr * addrV6;
531 const ResolveStatsNegAAAASet * negV6;
532 int hostnameCount;
533 int i;
534 unsigned int serverID;
535 int serverObjCount = 0;
536 int hostnameObjCount = 0;
537 int addrObjCount = 0;
538
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->histAny);
661 ForgetMem(&inStats->nonCellular->histA);
662 ForgetMem(&inStats->nonCellular->histAAAA);
663 free(inStats->nonCellular);
664 inStats->nonCellular = NULL;
665 }
666 if (inStats->cellular)
667 {
668 ForgetMem(&inStats->cellular->histAny);
669 ForgetMem(&inStats->cellular->histA);
670 ForgetMem(&inStats->cellular->histAAAA);
671 free(inStats->cellular);
672 inStats->cellular = NULL;
673 }
674 free(inStats);
675 }
676
677 //===========================================================================================================================
678 // DNSDomainStatsFreeList
679 //===========================================================================================================================
680
681 mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList)
682 {
683 DNSDomainStats * stats;
684
685 while ((stats = inList) != NULL)
686 {
687 inList = stats->next;
688 DNSDomainStatsFree(stats);
689 }
690 }
691
692 //===========================================================================================================================
693 // DNSDomainStatsUpdate
694 //===========================================================================================================================
695
696 mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, uint16_t inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
697 {
698 mStatus err;
699 DNSHistSet ** p;
700 DNSHistSet * set;
701 DNSHist * histAny;
702 DNSHist * hist;
703 int i;
704
705 require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError);
706
707 p = inForCell ? &inStats->cellular : &inStats->nonCellular;
708 if ((set = *p) == NULL)
709 {
710 set = (DNSHistSet *)calloc(1, sizeof(*set));
711 require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
712 *p = set;
713 }
714 if ((histAny = set->histAny) == NULL)
715 {
716 histAny = (DNSHist *)calloc(1, sizeof(*histAny));
717 require_action_quiet(histAny, exit, err = mStatus_NoMemoryErr);
718 set->histAny = histAny;
719 }
720 if (inType == kDNSType_A)
721 {
722 if ((hist = set->histA) == NULL)
723 {
724 hist = (DNSHist *)calloc(1, sizeof(*hist));
725 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
726 set->histA = hist;
727 }
728 }
729 else if (inType == kDNSType_AAAA)
730 {
731 if ((hist = set->histAAAA) == NULL)
732 {
733 hist = (DNSHist *)calloc(1, sizeof(*hist));
734 require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
735 set->histAAAA = hist;
736 }
737 }
738 else
739 {
740 hist = NULL;
741 }
742
743 if (inRR)
744 {
745 uint16_t * sendCountBins;
746 uint16_t * latencyBins;
747 const mDNSBool isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
748
749 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
750
751 sendCountBins = isNegative ? histAny->negAnsweredQuerySendCountBins : histAny->answeredQuerySendCountBins;
752 increment_saturate(sendCountBins[i], UINT16_MAX);
753 if (hist)
754 {
755 sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
756 increment_saturate(sendCountBins[i], UINT16_MAX);
757 }
758
759 if (inQuerySendCount > 0)
760 {
761 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
762 latencyBins = isNegative ? histAny->negResponseLatencyBins : histAny->responseLatencyBins;
763 increment_saturate(latencyBins[i], UINT16_MAX);
764 if (hist)
765 {
766 latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
767 increment_saturate(latencyBins[i], UINT16_MAX);
768 }
769 }
770 }
771 else
772 {
773 i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
774 increment_saturate(histAny->unansweredQuerySendCountBins[i], UINT16_MAX);
775 if (hist) increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
776
777 for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
778 increment_saturate(histAny->unansweredQueryDurationBins[i], UINT16_MAX);
779 if (hist) increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
780 }
781 err = mStatus_NoError;
782
783 exit:
784 return (err);
785 }
786
787 //===========================================================================================================================
788 // ResolveStatsDomainCreate
789 //===========================================================================================================================
790
791 mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain)
792 {
793 mStatus err;
794 ResolveStatsDomain * obj;
795
796 obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
797 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
798
799 obj->domainInfo = inDomain;
800
801 *outDomain = obj;
802 err = mStatus_NoError;
803
804 exit:
805 return (err);
806 }
807
808 //===========================================================================================================================
809 // ResolveStatsDomainFree
810 //===========================================================================================================================
811
812 mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
813 {
814 ResolveStatsHostname * hostname;
815
816 while ((hostname = inDomain->hostnameList) != NULL)
817 {
818 inDomain->hostnameList = hostname->next;
819 ResolveStatsHostnameFree(hostname);
820 }
821 free(inDomain);
822 }
823
824 //===========================================================================================================================
825 // ResolveStatsDomainUpdate
826 //===========================================================================================================================
827
828 mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
829 {
830 mStatus err;
831 ResolveStatsHostname ** p;
832 ResolveStatsHostname * hostname;
833 uint8_t serverID;
834
835 for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
836 {
837 if (SameDomainName((domainname *)hostname->name, inHostname)) break;
838 }
839
840 if (!hostname)
841 {
842 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
843 err = ResolveStatsHostnameCreate(inHostname, &hostname);
844 require_noerr_quiet(err, exit);
845 gResolveStatsObjCount++;
846 *p = hostname;
847 }
848
849 err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
850 require_noerr_quiet(err, exit);
851
852 err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
853 require_noerr_quiet(err, exit);
854
855 exit:
856 return (err);
857 }
858
859 //===========================================================================================================================
860 // ResolveStatsHostnameCreate
861 //===========================================================================================================================
862
863 mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
864 {
865 mStatus err;
866 ResolveStatsHostname * obj;
867 size_t nameLen;
868
869 nameLen = DomainNameLength(inName);
870 require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
871
872 obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
873 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
874
875 memcpy(obj->name, inName, nameLen);
876
877 *outHostname = obj;
878 err = mStatus_NoError;
879
880 exit:
881 return (err);
882 }
883
884 //===========================================================================================================================
885 // ResolveStatsDomainCreateAWDVersion
886 //===========================================================================================================================
887
888 mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
889 {
890 mStatus err;
891 AWDMDNSResponderResolveStatsDomain * domain;
892 ResolveStatsHostname * hostname;
893 AWDMDNSResponderResolveStatsHostname * awdHostname;
894 NSString * name;
895
896 domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
897 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
898
899 name = [[NSString alloc] initWithUTF8String:inDomain->domainInfo->cstr];
900 require_action_quiet(name, exit, err = mStatus_UnknownErr);
901
902 domain.name = name;
903 [name release];
904 name = nil;
905
906 for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
907 {
908 err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
909 require_noerr_quiet(err, exit);
910
911 [domain addHostname:awdHostname];
912 [awdHostname release];
913 awdHostname = nil;
914 }
915
916 *outDomain = domain;
917 domain = nil;
918 err = mStatus_NoError;
919
920 exit:
921 [domain release];
922 return (err);
923 }
924
925 //===========================================================================================================================
926 // ResolveStatsHostnameFree
927 //===========================================================================================================================
928
929 mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
930 {
931 ResolveStatsIPv4AddrSet * addrV4;
932 ResolveStatsIPv6Addr * addrV6;
933 ResolveStatsNegAAAASet * negV6;
934
935 while ((addrV4 = inHostname->addrV4List) != NULL)
936 {
937 inHostname->addrV4List = addrV4->next;
938 ResolveStatsIPv4AddrSetFree(addrV4);
939 }
940 while ((addrV6 = inHostname->addrV6List) != NULL)
941 {
942 inHostname->addrV6List = addrV6->next;
943 ResolveStatsIPv6AddressFree(addrV6);
944 }
945 while ((negV6 = inHostname->negV6List) != NULL)
946 {
947 inHostname->negV6List = negV6->next;
948 ResolveStatsNegAAAASetFree(negV6);
949 }
950 free(inHostname);
951 }
952
953 //===========================================================================================================================
954 // ResolveStatsHostnameUpdate
955 //===========================================================================================================================
956
957 mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
958 {
959 mStatus err;
960
961 if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
962 {
963 ResolveStatsIPv4AddrSet ** p;
964 ResolveStatsIPv4AddrSet * addrV4;
965 int i;
966 IPv4AddrCounter * counter;
967
968 for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
969 {
970 for (i = 0; i < (int)countof(addrV4->counters); ++i)
971 {
972 counter = &addrV4->counters[i];
973 if (counter->count == 0) break;
974 if (counter->serverID != inServerID) continue;
975 if (inResp->type == kResponseType_NegA)
976 {
977 if (counter->isNegative) break;
978 }
979 else
980 {
981 if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
982 }
983 }
984 if (i < (int)countof(addrV4->counters)) break;
985 }
986 if (!addrV4)
987 {
988 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
989 err = ResolveStatsIPv4AddrSetCreate(&addrV4);
990 require_noerr_quiet(err, exit);
991 gResolveStatsObjCount++;
992
993 *p = addrV4;
994 counter = &addrV4->counters[0];
995 }
996 if (counter->count == 0)
997 {
998 counter->serverID = inServerID;
999 if (inResp->type == kResponseType_NegA)
1000 {
1001 counter->isNegative = 1;
1002 }
1003 else
1004 {
1005 counter->isNegative = 0;
1006 memcpy(counter->addrBytes, inResp->data, 4);
1007 }
1008 }
1009 increment_saturate(counter->count, UINT16_MAX);
1010 err = mStatus_NoError;
1011 }
1012 else if (inResp->type == kResponseType_IPv6Addr)
1013 {
1014 ResolveStatsIPv6Addr ** p;
1015 ResolveStatsIPv6Addr * addrV6;
1016
1017 for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
1018 {
1019 if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
1020 }
1021 if (!addrV6)
1022 {
1023 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1024 err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
1025 require_noerr_quiet(err, exit);
1026 gResolveStatsObjCount++;
1027
1028 *p = addrV6;
1029 }
1030 increment_saturate(addrV6->count, UINT16_MAX);
1031 err = mStatus_NoError;
1032 }
1033 else if (inResp->type == kResponseType_NegAAAA)
1034 {
1035 ResolveStatsNegAAAASet ** p;
1036 ResolveStatsNegAAAASet * negV6;
1037 int i;
1038 NegAAAACounter * counter;
1039
1040 for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1041 {
1042 for (i = 0; i < (int)countof(negV6->counters); ++i)
1043 {
1044 counter = &negV6->counters[i];
1045 if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1046 }
1047 if (i < (int)countof(negV6->counters)) break;
1048 }
1049 if (!negV6)
1050 {
1051 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1052 err = ResolveStatsNegAAAASetCreate(&negV6);
1053 require_noerr_quiet(err, exit);
1054 gResolveStatsObjCount++;
1055
1056 *p = negV6;
1057 counter = &negV6->counters[0];
1058 }
1059 if (counter->count == 0) counter->serverID = inServerID;
1060 increment_saturate(counter->count, UINT16_MAX);
1061 err = mStatus_NoError;
1062 }
1063 else
1064 {
1065 err = mStatus_Invalid;
1066 }
1067
1068 exit:
1069 return (err);
1070 }
1071
1072 //===========================================================================================================================
1073 // ResolveStatsHostnameCreateAWDVersion
1074 //===========================================================================================================================
1075
1076 mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1077 {
1078 mStatus err;
1079 AWDMDNSResponderResolveStatsHostname * hostname;
1080 NSString * name;
1081 char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1082 const char * ptr;
1083 ResolveStatsIPv4AddrSet * addrV4;
1084 ResolveStatsIPv6Addr * addrV6;
1085 ResolveStatsNegAAAASet * negV6;
1086 AWDMDNSResponderResolveStatsResult * result = nil;
1087 int i;
1088
1089 hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1090 require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1091
1092 ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1093 require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1094
1095 name = [[NSString alloc] initWithUTF8String:nameBuf];
1096 require_action_quiet(name, exit, err = mStatus_UnknownErr);
1097
1098 hostname.name = name;
1099 [name release];
1100 name = nil;
1101
1102 for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1103 {
1104 for (i = 0; i < (int)countof(addrV4->counters); ++i)
1105 {
1106 const IPv4AddrCounter * counter;
1107 NSData * addrBytes;
1108
1109 counter = &addrV4->counters[i];
1110 if (counter->count == 0) break;
1111
1112 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1113 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1114
1115 if (counter->isNegative)
1116 {
1117 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1118 }
1119 else
1120 {
1121 addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1122 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1123
1124 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1125 result.data = addrBytes;
1126 [addrBytes release];
1127 }
1128 result.count = counter->count;
1129 result.serverID = counter->serverID;
1130
1131 [hostname addResult:result];
1132 [result release];
1133 result = nil;
1134 }
1135 }
1136
1137 for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1138 {
1139 NSData * addrBytes;
1140
1141 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1142 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1143
1144 addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1145 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1146
1147 result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1148 result.count = addrV6->count;
1149 result.serverID = addrV6->serverID;
1150 result.data = addrBytes;
1151
1152 [addrBytes release];
1153
1154 [hostname addResult:result];
1155 [result release];
1156 result = nil;
1157 }
1158
1159 for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1160 {
1161 for (i = 0; i < (int)countof(negV6->counters); ++i)
1162 {
1163 const NegAAAACounter * counter;
1164
1165 counter = &negV6->counters[i];
1166 if (counter->count == 0) break;
1167
1168 result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1169 require_action_quiet(result, exit, err = mStatus_UnknownErr);
1170
1171 result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1172 result.count = counter->count;
1173 result.serverID = counter->serverID;
1174
1175 [hostname addResult:result];
1176 [result release];
1177 result = nil;
1178 }
1179 }
1180
1181 *outHostname = hostname;
1182 hostname = nil;
1183 err = mStatus_NoError;
1184
1185 exit:
1186 [result release];
1187 [hostname release];
1188 return (err);
1189 }
1190
1191 //===========================================================================================================================
1192 // ResolveStatsDNSServerCreate
1193 //===========================================================================================================================
1194
1195 mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1196 {
1197 mStatus err;
1198 ResolveStatsDNSServer * obj;
1199 size_t addrLen;
1200
1201 require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1202
1203 addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
1204 obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
1205 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1206
1207 obj->isForCell = inForCell;
1208 if (inAddr->type == mDNSAddrType_IPv4)
1209 {
1210 obj->isAddrV6 = mDNSfalse;
1211 memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1212 }
1213 else
1214 {
1215 obj->isAddrV6 = mDNStrue;
1216 memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1217 }
1218
1219 *outServer = obj;
1220 err = mStatus_NoError;
1221
1222 exit:
1223 return (err);
1224 }
1225
1226 //===========================================================================================================================
1227 // ResolveStatsDNSServerFree
1228 //===========================================================================================================================
1229
1230 mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1231 {
1232 free(inServer);
1233 }
1234
1235 //===========================================================================================================================
1236 // ResolveStatsDNSServerCreateAWDVersion
1237 //===========================================================================================================================
1238
1239 mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1240 {
1241 mStatus err;
1242 AWDMDNSResponderResolveStatsDNSServer * server;
1243 NSData * addrBytes = nil;
1244
1245 server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1246 require_action_quiet(server, exit, err = mStatus_UnknownErr);
1247
1248 addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1249 require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1250
1251 server.serverID = inServer->id;
1252 server.address = addrBytes;
1253 if (inServer->isForCell)
1254 {
1255 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1256 }
1257 else
1258 {
1259 server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1260 }
1261
1262 *outServer = server;
1263 server = nil;
1264 err = mStatus_NoError;
1265
1266 exit:
1267 [addrBytes release];
1268 [server release];
1269 return (err);
1270 }
1271
1272 //===========================================================================================================================
1273 // ResolveStatsIPv4AddrSetCreate
1274 //===========================================================================================================================
1275
1276 mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1277 {
1278 mStatus err;
1279 ResolveStatsIPv4AddrSet * obj;
1280
1281 obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1282 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1283
1284 *outSet = obj;
1285 err = mStatus_NoError;
1286
1287 exit:
1288 return (err);
1289 }
1290
1291 //===========================================================================================================================
1292 // ResolveStatsIPv4AddrSetFree
1293 //===========================================================================================================================
1294
1295 mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1296 {
1297 free(inSet);
1298 }
1299
1300 //===========================================================================================================================
1301 // ResolveStatsIPv6AddressCreate
1302 //===========================================================================================================================
1303
1304 mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1305 {
1306 mStatus err;
1307 ResolveStatsIPv6Addr * obj;
1308
1309 obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1310 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1311
1312 obj->serverID = inServerID;
1313 memcpy(obj->addrBytes, inAddrBytes, 16);
1314
1315 *outAddr = obj;
1316 err = mStatus_NoError;
1317
1318 exit:
1319 return (err);
1320 }
1321
1322 //===========================================================================================================================
1323 // ResolveStatsIPv6AddressFree
1324 //===========================================================================================================================
1325
1326 mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1327 {
1328 free(inAddr);
1329 }
1330
1331 //===========================================================================================================================
1332 // ResolveStatsNegAAAASetCreate
1333 //===========================================================================================================================
1334
1335 mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1336 {
1337 mStatus err;
1338 ResolveStatsNegAAAASet * obj;
1339
1340 obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1341 require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1342
1343 *outSet = obj;
1344 err = mStatus_NoError;
1345
1346 exit:
1347 return (err);
1348 }
1349
1350 //===========================================================================================================================
1351 // ResolveStatsNegAAAASetFree
1352 //===========================================================================================================================
1353
1354 mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1355 {
1356 free(inSet);
1357 }
1358
1359 //===========================================================================================================================
1360 // ResolveStatsGetServerID
1361 //===========================================================================================================================
1362
1363 mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1364 {
1365 mStatus err;
1366 ResolveStatsDNSServer ** p;
1367 ResolveStatsDNSServer * server;
1368
1369 require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1370
1371 for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1372 {
1373 if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1374 {
1375 if (inServerAddr->type == mDNSAddrType_IPv4)
1376 {
1377 if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1378 }
1379 else
1380 {
1381 if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1382 }
1383 }
1384 }
1385
1386 if (!server)
1387 {
1388 require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
1389 require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1390 err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
1391 require_noerr_quiet(err, exit);
1392 gResolveStatsObjCount++;
1393
1394 server->id = gResolveStatsNextServerID++;
1395 server->next = gResolveStatsServerList;
1396 gResolveStatsServerList = server;
1397 }
1398 else if (gResolveStatsServerList != server)
1399 {
1400 *p = server->next;
1401 server->next = gResolveStatsServerList;
1402 gResolveStatsServerList = server;
1403 }
1404
1405 *outServerID = server->id;
1406 err = mStatus_NoError;
1407
1408 exit:
1409 return (err);
1410 }
1411
1412 //===========================================================================================================================
1413 // CreateDomainStatsList
1414 //===========================================================================================================================
1415
1416 mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList)
1417 {
1418 mStatus err;
1419 int i;
1420 DNSDomainStats * stats;
1421 DNSDomainStats ** p;
1422 DNSDomainStats * list = NULL;
1423
1424 p = &list;
1425 for (i = 0; i < (int)countof(kQueryStatsDomains); ++i)
1426 {
1427 err = DNSDomainStatsCreate(&kQueryStatsDomains[i], &stats);
1428 require_noerr_quiet(err, exit);
1429
1430 *p = stats;
1431 p = &stats->next;
1432 }
1433
1434 *outList = list;
1435 list = NULL;
1436
1437 exit:
1438 DNSDomainStatsFreeList(list);
1439 return (err);
1440 }
1441
1442 //===========================================================================================================================
1443 // CreateResolveStatsList
1444 //===========================================================================================================================
1445
1446 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1447 {
1448 mStatus err;
1449 int i;
1450 ResolveStatsDomain * domain;
1451 ResolveStatsDomain ** p;
1452 ResolveStatsDomain * list = NULL;
1453
1454 p = &list;
1455 for (i = 0; i < (int)countof(kResolveStatsDomains); ++i)
1456 {
1457 err = ResolveStatsDomainCreate(&kResolveStatsDomains[i], &domain);
1458 require_noerr_quiet(err, exit);
1459
1460 *p = domain;
1461 p = &domain->next;
1462 }
1463
1464 *outList = list;
1465 list = NULL;
1466
1467 exit:
1468 FreeResolveStatsList(list);
1469 return (err);
1470 }
1471
1472 //===========================================================================================================================
1473 // FreeResolveStatsList
1474 //===========================================================================================================================
1475
1476 mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1477 {
1478 ResolveStatsDomain * domain;
1479
1480 while ((domain = inList) != NULL)
1481 {
1482 inList = domain->next;
1483 ResolveStatsDomainFree(domain);
1484 }
1485 }
1486
1487 //===========================================================================================================================
1488 // FreeResolveStatsServerList
1489 //===========================================================================================================================
1490
1491 mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1492 {
1493 ResolveStatsDNSServer * server;
1494
1495 while ((server = inList) != NULL)
1496 {
1497 inList = server->next;
1498 ResolveStatsDNSServerFree(server);
1499 }
1500 }
1501
1502 //===========================================================================================================================
1503 // SubmitAWDMetric
1504 //===========================================================================================================================
1505
1506 mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1507 {
1508 mStatus err = mStatus_NoError;
1509
1510 switch (inMetricID)
1511 {
1512 case AWDMetricId_MDNSResponder_DNSStatistics:
1513 err = SubmitAWDMetricQueryStats();
1514 break;
1515
1516 case AWDMetricId_MDNSResponder_ResolveStats:
1517 err = SubmitAWDMetricResolveStats();
1518 break;
1519
1520 case AWDMetricId_MDNSResponder_ServicesStats:
1521 [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats integerValue:max_num_regservices];
1522 KQueueLock(&mDNSStorage);
1523 // reset the no of max services since we want to collect the max no of services registered per AWD submission period
1524 max_num_regservices = curr_num_regservices;
1525 KQueueUnlock(&mDNSStorage, "SubmitAWDSimpleMetricServiceStats");
1526 break;
1527
1528 default:
1529 err = mStatus_UnsupportedErr;
1530 break;
1531 }
1532
1533 if (err)
1534 LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1535 return (err);
1536 }
1537
1538 //===========================================================================================================================
1539 // SubmitAWDMetricQueryStats
1540 //===========================================================================================================================
1541
1542 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1543 {
1544 mStatus err;
1545 BOOL success;
1546 DNSDomainStats * stats;
1547 DNSDomainStats * newDomainStatsList;
1548 DNSDomainStats * domainStatsList = NULL;
1549 AWDMetricContainer * container = nil;
1550 AWDMDNSResponderDNSStatistics * metric = nil;
1551
1552 err = CreateDomainStatsList(&newDomainStatsList);
1553 require_noerr_quiet(err, exit);
1554
1555 domainStatsList = gDomainStatsList;
1556
1557 KQueueLock(&mDNSStorage);
1558 gDomainStatsList = newDomainStatsList;
1559 KQueueUnlock(&mDNSStorage, "SubmitAWDMetricQueryStats");
1560
1561 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1562 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1563
1564 metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1565 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1566
1567 while ((stats = domainStatsList) != NULL)
1568 {
1569 if (stats->nonCellular)
1570 {
1571 err = AddAWDDNSDomainStats(metric, stats->nonCellular, stats->domain->cstr, mDNSfalse);
1572 require_noerr_quiet(err, exit);
1573 }
1574 if (stats->cellular)
1575 {
1576 err = AddAWDDNSDomainStats(metric, stats->cellular, stats->domain->cstr, mDNStrue);
1577 require_noerr_quiet(err, exit);
1578 }
1579 domainStatsList = stats->next;
1580 DNSDomainStatsFree(stats);
1581 }
1582
1583 container.metric = metric;
1584 success = [gAWDServerConnection submitMetric:container];
1585 LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed" );
1586 err = success ? mStatus_NoError : mStatus_UnknownErr;
1587
1588 exit:
1589 [metric release];
1590 [container release];
1591 DNSDomainStatsFreeList(domainStatsList);
1592 return (err);
1593 }
1594
1595 //===========================================================================================================================
1596 // SubmitAWDMetricResolveStats
1597 //===========================================================================================================================
1598
1599 mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1600 {
1601 mStatus err;
1602 ResolveStatsDomain * newResolveStatsList;
1603 ResolveStatsDomain * domainList = NULL;
1604 ResolveStatsDNSServer * serverList = NULL;
1605 AWDMetricContainer * container = nil;
1606 AWDMDNSResponderResolveStats * metric = nil;
1607 ResolveStatsDNSServer * server;
1608 ResolveStatsDomain * domain;
1609 BOOL success;
1610
1611 err = CreateResolveStatsList(&newResolveStatsList);
1612 require_noerr_quiet(err, exit);
1613
1614 domainList = gResolveStatsList;
1615 serverList = gResolveStatsServerList;
1616
1617 KQueueLock(&mDNSStorage);
1618 gResolveStatsList = newResolveStatsList;
1619 gResolveStatsServerList = NULL;
1620 gResolveStatsNextServerID = 0;
1621 gResolveStatsObjCount = 0;
1622 KQueueUnlock(&mDNSStorage, "SubmitAWDMetricResolveStats");
1623
1624 container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1625 require_action_quiet(container, exit, err = mStatus_UnknownErr);
1626
1627 metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1628 require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1629
1630 while ((server = serverList) != NULL)
1631 {
1632 AWDMDNSResponderResolveStatsDNSServer * awdServer;
1633
1634 serverList = server->next;
1635 err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1636 ResolveStatsDNSServerFree(server);
1637 require_noerr_quiet(err, exit);
1638
1639 [metric addServer:awdServer];
1640 [awdServer release];
1641 }
1642
1643 while ((domain = domainList) != NULL)
1644 {
1645 AWDMDNSResponderResolveStatsDomain * awdDomain;
1646
1647 domainList = domain->next;
1648 err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1649 ResolveStatsDomainFree(domain);
1650 require_noerr_quiet(err, exit);
1651
1652 [metric addDomain:awdDomain];
1653 [awdDomain release];
1654 }
1655
1656 container.metric = metric;
1657 success = [gAWDServerConnection submitMetric:container];
1658 LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed" );
1659 err = success ? mStatus_NoError : mStatus_UnknownErr;
1660
1661 exit:
1662 [metric release];
1663 [container release];
1664 FreeResolveStatsList(domainList);
1665 FreeResolveStatsServerList(serverList);
1666 return (err);
1667 }
1668
1669 //===========================================================================================================================
1670 // CreateAWDDNSDomainStats
1671 //===========================================================================================================================
1672
1673 mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
1674 {
1675 mStatus err;
1676 AWDDNSDomainStats * awdStats = nil;
1677 NSString * domain = nil;
1678 uint32_t sendCountBins[kQueryStatsSendCountBinCount];
1679 uint32_t latencyBins[kQueryStatsLatencyBinCount];
1680 int i;
1681 unsigned int totalAnswered;
1682 unsigned int totalNegAnswered;
1683 unsigned int totalUnanswered;
1684
1685 awdStats = [[AWDDNSDomainStatsSoft alloc] init];
1686 require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
1687
1688 domain = [[NSString alloc] initWithUTF8String:inDomain];
1689 require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1690
1691 awdStats.domain = domain;
1692 awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
1693 awdStats.recordType = inType;
1694
1695 totalAnswered = 0;
1696 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1697 {
1698 sendCountBins[i] = inHist->answeredQuerySendCountBins[i];
1699 totalAnswered += inHist->answeredQuerySendCountBins[i];
1700 }
1701 [awdStats setAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1702
1703 totalNegAnswered = 0;
1704 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1705 {
1706 sendCountBins[i] = inHist->negAnsweredQuerySendCountBins[i];
1707 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1708 }
1709 [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1710
1711 totalUnanswered = 0;
1712 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1713 {
1714 sendCountBins[i] = inHist->unansweredQuerySendCountBins[i];
1715 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1716 }
1717 [awdStats setUnansweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
1718
1719 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1720 {
1721 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1722 {
1723 latencyBins[i] = inHist->responseLatencyBins[i];
1724 }
1725 [awdStats setResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1726 }
1727
1728 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1729 {
1730 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1731 {
1732 latencyBins[i] = inHist->negResponseLatencyBins[i];
1733 }
1734 [awdStats setNegResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
1735 }
1736
1737 if (totalUnanswered > 0)
1738 {
1739 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1740 {
1741 latencyBins[i] = inHist->unansweredQueryDurationBins[i];
1742 }
1743 [awdStats setUnansweredQueryDurationMs:latencyBins count:kQueryStatsLatencyBinCount];
1744 }
1745
1746 *outStats = awdStats;
1747 awdStats = nil;
1748 err = mStatus_NoError;
1749
1750 exit:
1751 [domain release];
1752 [awdStats release];
1753 return (err);
1754 }
1755
1756 //===========================================================================================================================
1757 // AddAWDDNSDomainStats
1758 //===========================================================================================================================
1759
1760 mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1761 {
1762 mStatus err;
1763 AWDDNSDomainStats * awdStats;
1764
1765 if (inSet->histAny)
1766 {
1767 err = CreateAWDDNSDomainStats(inSet->histAny, inDomain, inForCell, AWDDNSDomainStats_RecordType_Any, &awdStats);
1768 require_noerr_quiet(err, exit);
1769
1770 [inMetric addStats:awdStats];
1771 [awdStats release];
1772 }
1773 if (inSet->histA)
1774 {
1775 err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1776 require_noerr_quiet(err, exit);
1777
1778 [inMetric addStats:awdStats];
1779 [awdStats release];
1780 }
1781 if (inSet->histAAAA)
1782 {
1783 err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1784 require_noerr_quiet(err, exit);
1785
1786 [inMetric addStats:awdStats];
1787 [awdStats release];
1788 }
1789 err = mStatus_NoError;
1790
1791 exit:
1792 return (err);
1793 }
1794
1795 //===========================================================================================================================
1796 // LogDNSHistSet
1797 //===========================================================================================================================
1798
1799 mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1800 {
1801 if (inSet->histAny) LogDNSHist(inSet->histAny, inDomain, inForCell, "Any");
1802 if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
1803 if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
1804 }
1805
1806 //===========================================================================================================================
1807 // LogDNSHist
1808 //===========================================================================================================================
1809
1810 #define Percent(N, D) ((N) * 100) / (D), (((N) * 10000) / (D)) % 100
1811 #define PercentFmt "%3u.%02u"
1812 #define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
1813 LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
1814
1815 mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
1816 {
1817 unsigned int totalAnswered;
1818 unsigned int totalNegAnswered;
1819 unsigned int totalUnanswered;
1820 int i;
1821
1822 totalAnswered = 0;
1823 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1824 {
1825 totalAnswered += inHist->answeredQuerySendCountBins[i];
1826 }
1827
1828 totalNegAnswered = 0;
1829 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1830 {
1831 totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
1832 }
1833
1834 totalUnanswered = 0;
1835 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1836 {
1837 totalUnanswered += inHist->unansweredQuerySendCountBins[i];
1838 }
1839
1840 LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
1841 LogMsgNoIdent("Answered questions %4u", totalAnswered);
1842 LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
1843 LogMsgNoIdent("Unanswered questions %4u", totalUnanswered);
1844 LogMsgNoIdent("-- Query send counts ---------");
1845 LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
1846 LogMsgNoIdent("-- Query send counts (NAQs) --");
1847 LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
1848
1849 if (totalAnswered > inHist->answeredQuerySendCountBins[0])
1850 {
1851 LogMsgNoIdent("--- Response times -----------");
1852 LogDNSHistLatencies(inHist->responseLatencyBins);
1853 }
1854
1855 if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
1856 {
1857 LogMsgNoIdent("--- Response times (NAQs) ----");
1858 LogDNSHistLatencies(inHist->negResponseLatencyBins);
1859 }
1860
1861 if (totalUnanswered > 0)
1862 {
1863 LogMsgNoIdent("--- Unanswered query times ---");
1864 LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
1865 }
1866 }
1867
1868 //===========================================================================================================================
1869 // LogDNSHistSendCounts
1870 //===========================================================================================================================
1871
1872 mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
1873 {
1874 uint32_t total;
1875 char label[16];
1876 int i;
1877
1878 total = 0;
1879 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1880 {
1881 total += inSendCountBins[i];
1882 }
1883
1884 if (total > 0)
1885 {
1886 uint32_t accumulator = 0;
1887
1888 for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
1889 {
1890 accumulator += inSendCountBins[i];
1891 if (i < (kQueryStatsSendCountBinCount - 1))
1892 {
1893 snprintf(label, sizeof(label), "%2d ", i);
1894 }
1895 else
1896 {
1897 snprintf(label, sizeof(label), "%2d+", i);
1898 }
1899 LogStat(label, inSendCountBins[i], accumulator, total);
1900 if (accumulator == total) break;
1901 }
1902 }
1903 else
1904 {
1905 LogMsgNoIdent("No data.");
1906 }
1907 }
1908
1909 //===========================================================================================================================
1910 // LogDNSHistLatencies
1911 //===========================================================================================================================
1912
1913 mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
1914 {
1915 uint32_t total;
1916 int i;
1917 char label[16];
1918
1919 total = 0;
1920 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1921 {
1922 total += inLatencyBins[i];
1923 }
1924
1925 if (total > 0)
1926 {
1927 uint32_t accumulator = 0;
1928
1929 for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
1930 {
1931 accumulator += inLatencyBins[i];
1932 if (i < (int)countof(kResponseLatencyMsLimits))
1933 {
1934 snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
1935 }
1936 else
1937 {
1938 snprintf(label, sizeof(label), "< ∞ ms");
1939 }
1940 LogStat(label, inLatencyBins[i], accumulator, total);
1941 if (accumulator == total) break;
1942 }
1943 }
1944 else
1945 {
1946 LogMsgNoIdent("No data.");
1947 }
1948 }
1949
1950 //===========================================================================================================================
1951 // ValidateDNSStatsDomains
1952 //===========================================================================================================================
1953
1954 #if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
1955 #warning "Do not include ValidateDNSStatsDomains() in customer release!"
1956 mDNSlocal void ValidateDNSStatsDomains(void)
1957 {
1958 int i;
1959 const Domain * domain;
1960 mDNSu8 * ptr;
1961 domainname domainNameExpected;
1962 int labelCountExpected;
1963 mDNSBool domainNamesEqual;
1964 mDNSBool failed = mDNSfalse;
1965
1966 for (i = 0; i < countof(kQueryStatsDomains); ++i)
1967 {
1968 domain = &kQueryStatsDomains[i];
1969
1970 if (strcmp(domain->cstr, ".") == 0)
1971 {
1972 domainNameExpected.c[0] = 0;
1973 }
1974 else
1975 {
1976 ptr = MakeDomainNameFromDNSNameString(&domainNameExpected, domain->cstr);
1977 if (!ptr)
1978 {
1979 LogMsg("ValidateDNSStatsDomains: Failed to make domain name for \"%s\".", domain->cstr);
1980 failed = mDNStrue;
1981 goto exit;
1982 }
1983 }
1984
1985 domainNamesEqual = SameDomainName(domain->name, &domainNameExpected);
1986 labelCountExpected = CountLabels(&domainNameExpected);
1987 if (domainNamesEqual && (domain->labelCount == labelCountExpected))
1988 {
1989 LogMsg("ValidateDNSStatsDomains: \"%s\" passed.", domain->cstr);
1990 }
1991 else
1992 {
1993 if (!domainNamesEqual)
1994 {
1995 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect domain name.", domain->cstr);
1996 }
1997 if (domain->labelCount != labelCountExpected)
1998 {
1999 LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect label count. Actual %d, expected %d.",
2000 domain->cstr, domain->labelCount, labelCountExpected);
2001 }
2002 failed = mDNStrue;
2003 }
2004 }
2005
2006 exit:
2007 if (failed) abort();
2008 }
2009 #endif
2010 #endif // TARGET_OS_EMBEDDED