source: rtems-libbsd/mDNSResponder/mDNSMacOSX/Metrics.m @ 4a5f546

55-freebsd-126-freebsd-12
Last change on this file since 4a5f546 was 2723609, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:57:22

mDNSResponder: Update to v878.30.4

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-878.30.4.tar.gz

Close #3522.

  • Property mode set to 100644
File size: 90.0 KB
Line 
1/*
2 * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#import "Metrics.h"
18
19#if (TARGET_OS_IOS)
20#import <CoreUtils/SoftLinking.h>
21#import <WirelessDiagnostics/AWDDNSDomainStats.h>
22#import <WirelessDiagnostics/AWDMDNSResponderDNSMessageSizeStats.h>
23#import <WirelessDiagnostics/AWDMDNSResponderDNSStatistics.h>
24#import <WirelessDiagnostics/AWDMDNSResponderResolveStats.h>
25#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDNSServer.h>
26#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDomain.h>
27#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsHostname.h>
28#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsResult.h>
29#import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
30#import <WirelessDiagnostics/AWDMetricIds_MDNSResponder.h>
31#import <WirelessDiagnostics/WirelessDiagnostics.h>
32
33#import "DNSCommon.h"
34#import "mDNSMacOSX.h"
35#import "DebugServices.h"
36
37//===========================================================================================================================
38//  External Frameworks
39//===========================================================================================================================
40
41SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics)
42
43// AWDServerConnection class
44
45SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection)
46
47#define AWDServerConnectionSoft     getAWDServerConnectionClass()
48
49// Classes for query stats
50
51SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics)
52SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
53
54#define AWDMDNSResponderDNSStatisticsSoft       getAWDMDNSResponderDNSStatisticsClass()
55#define AWDDNSDomainStatsSoft                   getAWDDNSDomainStatsClass()
56
57// Classes for resolve stats
58
59SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats)
60SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer)
61SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain)
62SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname)
63SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult)
64
65#define AWDMDNSResponderResolveStatsSoft                getAWDMDNSResponderResolveStatsClass()
66#define AWDMDNSResponderResolveStatsDNSServerSoft       getAWDMDNSResponderResolveStatsDNSServerClass()
67#define AWDMDNSResponderResolveStatsDomainSoft          getAWDMDNSResponderResolveStatsDomainClass()
68#define AWDMDNSResponderResolveStatsHostnameSoft        getAWDMDNSResponderResolveStatsHostnameClass()
69#define AWDMDNSResponderResolveStatsResultSoft          getAWDMDNSResponderResolveStatsResultClass()
70
71// Classes for services stats
72
73SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
74
75#define AWDMetricManagerSoft        getAWDMetricManagerClass()
76
77// Classes for DNS message size stats
78
79SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSMessageSizeStats)
80
81#define AWDMDNSResponderDNSMessageSizeStatsSoft     getAWDMDNSResponderDNSMessageSizeStatsClass()
82
83//===========================================================================================================================
84//  Macros
85//===========================================================================================================================
86
87#define countof(X)                      (sizeof(X) / sizeof(X[0]))
88#define countof_field(TYPE, FIELD)      countof(((TYPE *)0)->FIELD)
89#define increment_saturate(VAR, MAX)    do {if ((VAR) < (MAX)) {++(VAR);}} while (0)
90#define ForgetMem(X)                    do {if(*(X)) {free(*(X)); *(X) = NULL;}} while(0)
91
92//===========================================================================================================================
93//  Constants
94//===========================================================================================================================
95
96#define kQueryStatsMaxQuerySendCount    10
97#define kQueryStatsSendCountBinCount    (kQueryStatsMaxQuerySendCount + 1)
98#define kQueryStatsLatencyBinCount      55
99#define kResolveStatsMaxObjCount        2000
100
101//===========================================================================================================================
102//  Data structures
103//===========================================================================================================================
104
105// Data structures for query stats.
106
107typedef struct QueryStats       QueryStats;
108typedef struct DNSHistSet       DNSHistSet;
109typedef mDNSBool                (*QueryNameTest_f)(const QueryStats *inStats, const domainname *inQueryName);
110
111struct QueryStats
112{
113    QueryStats *        next;           // Pointer to next domain stats in list.
114    const char *        domainStr;      // Domain (see below) as a C string.
115    uint8_t *           domain;         // Domain for which these stats are collected.
116    const char *        altDomainStr;   // Alt domain string to use in the AWD version of the stats instead of domainStr.
117    DNSHistSet *        nonCellular;    // Query stats for queries sent over non-cellular interfaces.
118    DNSHistSet *        cellular;       // Query stats for queries sent over cellular interfaces.
119    QueryNameTest_f     test;           // Function that tests whether a given query's stats belong based on the query name.
120    int                 labelCount;     // Number of labels in domain name. Used for domain name comparisons.
121    mDNSBool            terminal;       // If true and test passes, then no other QueryStats on the list should be visited.
122};
123
124check_compile_time(sizeof(QueryStats) <= 64);
125
126// DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
127// <rdar://problem/23980546> MDNSResponder.proto update.
128//
129// answeredQuerySendCountBins
130//
131// 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
132// was sent i times. The value at index 10 is the number of times that an answered query was sent 10+ times.
133//
134// unansweredQuerySendCountBins
135//
136// 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
137// was sent i times. The value at index 10 is the number of times that an unanswered query was sent 10+ times.
138//
139// responseLatencyBins
140//
141// An array of 55 histogram bins. Each array value is the number of DNS queries that were answered in a paricular time
142// interval. The 55 consecutive non-overlapping time intervals have the following non-inclusive upper bounds (all values are
143// 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,
144// 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
145// 4500, 5000, 6000, 7000, 8000, 9000, 10000, ∞.
146
147typedef struct
148{
149    uint16_t    unansweredQuerySendCountBins[kQueryStatsSendCountBinCount];
150    uint16_t    unansweredQueryDurationBins[kQueryStatsLatencyBinCount];
151    uint16_t    answeredQuerySendCountBins[kQueryStatsSendCountBinCount];
152    uint16_t    responseLatencyBins[kQueryStatsLatencyBinCount];
153    uint16_t    negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
154    uint16_t    negResponseLatencyBins[kQueryStatsLatencyBinCount];
155
156}   DNSHist;
157
158check_compile_time(sizeof(DNSHist) <= 512);
159check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins)  == (kQueryStatsMaxQuerySendCount + 1));
160check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins)    == (kQueryStatsMaxQuerySendCount + 1));
161check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
162
163// Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
164// latency histogram bins to observe these time interval upper bounds.
165
166static const mDNSu32        kResponseLatencyMsLimits[] =
167{
168        1,     2,     3,     4,     5,
169       10,    20,    30,    40,    50,    60,    70,    80,    90,
170      100,   110,   120,   130,   140,   150,   160,   170,   180,   190,
171      200,   250,   300,   350,   400,   450,   500,   550,   600,   650,   700,   750,   800,   850,   900,   950,
172     1000,  1500,  2000,  2500,  3000,  3500,  4000,  4500,
173     5000,  6000,  7000,  8000,  9000,
174    10000
175};
176
177check_compile_time(countof(kResponseLatencyMsLimits) == 54);
178check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (countof(kResponseLatencyMsLimits) + 1));
179check_compile_time(countof_field(DNSHist, responseLatencyBins)         == (countof(kResponseLatencyMsLimits) + 1));
180check_compile_time(countof_field(DNSHist, negResponseLatencyBins)      == (countof(kResponseLatencyMsLimits) + 1));
181
182struct DNSHistSet
183{
184    DNSHist *       histA;      // Histogram data for queries for A resource records.
185    DNSHist *       histAAAA;   // Histogram data for queries for AAAA resource records.
186};
187
188typedef struct
189{
190    const char *        domainStr;
191    const char *        altDomainStr;
192    QueryNameTest_f     test;
193    mDNSBool            terminal;
194
195}   QueryStatsArgs;
196
197// Data structures for resolve stats.
198
199static const char * const       kResolveStatsDomains[] =
200{
201    "apple.com.",
202    "icloud.com.",
203    "mzstatic.com.",
204    "me.com."
205};
206
207check_compile_time(countof(kResolveStatsDomains) == 4);
208
209typedef struct ResolveStatsDomain           ResolveStatsDomain;
210typedef struct ResolveStatsHostname         ResolveStatsHostname;
211typedef struct ResolveStatsDNSServer        ResolveStatsDNSServer;
212typedef struct ResolveStatsIPv4AddrSet      ResolveStatsIPv4AddrSet;
213typedef struct ResolveStatsIPv6Addr         ResolveStatsIPv6Addr;
214typedef struct ResolveStatsNegAAAASet       ResolveStatsNegAAAASet;
215
216struct ResolveStatsDomain
217{
218    ResolveStatsDomain *        next;           // Next domain object in list.
219    const char *                domainStr;
220    uint8_t *                   domain;         // Domain for which these stats are collected.
221    int                         labelCount;     // Number of labels in domain name. Used for domain name comparisons.
222    ResolveStatsHostname *      hostnameList;   // List of hostname objects in this domain.
223};
224
225check_compile_time(sizeof(ResolveStatsDomain) <= 40);
226
227struct ResolveStatsHostname
228{
229    ResolveStatsHostname *          next;       // Next hostname object in list.
230    ResolveStatsIPv4AddrSet *       addrV4List; // List of IPv4 addresses to which this hostname resolved.
231    ResolveStatsIPv6Addr *          addrV6List; // List of IPv6 addresses to which this hostname resolved.
232    ResolveStatsNegAAAASet *        negV6List;  // List of negative AAAA response objects.
233    uint8_t                         name[1];    // Variable length storage for hostname as length-prefixed labels.
234};
235
236check_compile_time(sizeof(ResolveStatsHostname) <= 64);
237
238struct ResolveStatsDNSServer
239{
240    ResolveStatsDNSServer *     next;           // Next DNS server object in list.
241    uint8_t                     id;             // 8-bit ID assigned to this DNS server used by IP address objects.
242    mDNSBool                    isForCell;      // True if this DNS server belongs to a cellular interface.
243    mDNSBool                    isAddrV6;       // True if this DNS server has an IPv6 address instead of IPv4.
244    uint8_t                     addrBytes[1];   // Variable length storage for DNS server's IP address.
245};
246
247check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
248
249typedef struct
250{
251    uint16_t        count;          // Number of times this IPv4 address was provided as a resolution result.
252    uint8_t         serverID;       // 8-bit ID of the DNS server from which this IPv4 address came.
253    uint8_t         isNegative;
254    uint8_t         addrBytes[4];   // IPv4 address bytes.
255
256}   IPv4AddrCounter;
257
258check_compile_time(sizeof(IPv4AddrCounter) <= 8);
259
260struct ResolveStatsIPv4AddrSet
261{
262    ResolveStatsIPv4AddrSet *       next;           // Next set of IPv4 address counters in list.
263    IPv4AddrCounter                 counters[3];    // Array of IPv4 address counters.
264};
265
266check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
267
268struct ResolveStatsIPv6Addr
269{
270    ResolveStatsIPv6Addr *      next;           // Next IPv6 address object in list.
271    uint16_t                    count;          // Number of times this IPv6 address was provided as a resolution result.
272    uint8_t                     serverID;       // 8-bit ID of the DNS server from which this IPv6 address came.
273    uint8_t                     addrBytes[16];  // IPv6 address bytes.
274};
275
276check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
277
278typedef struct
279{
280    uint16_t        count;      // Number of times that a negative response was returned by a DNS server.
281    uint8_t         serverID;   // 8-bit ID of the DNS server that sent the negative responses.
282
283}   NegAAAACounter;
284
285check_compile_time(sizeof(NegAAAACounter) <= 4);
286
287struct ResolveStatsNegAAAASet
288{
289    ResolveStatsNegAAAASet *        next;           // Next set of negative AAAA response counters in list.
290    NegAAAACounter                  counters[6];    // Array of negative AAAA response counters.
291};
292
293check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
294
295typedef enum
296{
297    kResponseType_IPv4Addr  = 1,
298    kResponseType_IPv6Addr  = 2,
299    kResponseType_NegA      = 3,
300    kResponseType_NegAAAA   = 4
301
302}   ResponseType;
303
304typedef struct
305{
306    ResponseType        type;
307    const uint8_t *     data;
308
309}   Response;
310
311// Data structures for DNS message size stats.
312
313#define kQuerySizeBinWidth      16
314#define kQuerySizeBinMax        512
315#define kQuerySizeBinCount      ((kQuerySizeBinMax / kQuerySizeBinWidth) + 1)
316
317check_compile_time(kQuerySizeBinWidth > 0);
318check_compile_time(kQuerySizeBinCount > 0);
319check_compile_time((kQuerySizeBinMax % kQuerySizeBinWidth) == 0);
320
321#define kResponseSizeBinWidth       16
322#define kResponseSizeBinMax         512
323#define kResponseSizeBinCount       ((kResponseSizeBinMax / kResponseSizeBinWidth) + 1)
324
325check_compile_time(kResponseSizeBinWidth > 0);
326check_compile_time(kResponseSizeBinCount > 0);
327check_compile_time((kResponseSizeBinMax % kResponseSizeBinWidth) == 0);
328
329typedef struct
330{
331    uint16_t    querySizeBins[kQuerySizeBinCount];
332    uint16_t    responseSizeBins[kResponseSizeBinCount];
333
334}   DNSMessageSizeStats;
335
336check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
337
338//===========================================================================================================================
339//  Local Prototypes
340//===========================================================================================================================
341
342// Query stats
343
344mDNSlocal mStatus       QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats);
345mDNSlocal void          QueryStatsFree(QueryStats *inStats);
346mDNSlocal void          QueryStatsFreeList(QueryStats *inList);
347mDNSlocal mStatus       QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
348mDNSlocal const char *  QueryStatsGetDomainString(const QueryStats *inStats);
349mDNSlocal mDNSBool      QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName);
350mDNSlocal mDNSBool      QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName);
351mDNSlocal mDNSBool      QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName);
352mDNSlocal mDNSBool      QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName);
353
354// Resolve stats
355
356mDNSlocal mStatus   ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain);
357mDNSlocal void      ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
358mDNSlocal mStatus   ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
359mDNSlocal mStatus   ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
360
361mDNSlocal mStatus   ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
362mDNSlocal void      ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
363mDNSlocal mStatus   ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
364mDNSlocal mStatus   ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
365
366mDNSlocal mStatus   ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
367mDNSlocal void      ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
368mDNSlocal mStatus   ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
369
370mDNSlocal mStatus   ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
371mDNSlocal void      ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
372
373mDNSlocal mStatus   ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
374mDNSlocal void      ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
375
376mDNSlocal mStatus   ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
377mDNSlocal void      ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
378mDNSlocal mStatus   ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
379
380// DNS message size stats
381
382mDNSlocal mStatus   DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
383mDNSlocal void      DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
384
385mDNSlocal mStatus   CreateQueryStatsList(QueryStats **outList);
386mDNSlocal mStatus   CreateResolveStatsList(ResolveStatsDomain **outList);
387mDNSlocal void      FreeResolveStatsList(ResolveStatsDomain *inList);
388mDNSlocal void      FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
389mDNSlocal mStatus   SubmitAWDMetric(UInt32 inMetricID);
390mDNSlocal mStatus   SubmitAWDMetricQueryStats(void);
391mDNSlocal mStatus   SubmitAWDMetricResolveStats(void);
392mDNSlocal mStatus   SubmitAWDMetricDNSMessageSizeStats(void);
393mDNSlocal mStatus   CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
394mDNSlocal void      LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
395mDNSlocal void      LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
396mDNSlocal void      LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
397mDNSlocal void      LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
398mDNSlocal void      LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth);
399
400mDNSlocal size_t    CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
401
402//===========================================================================================================================
403//  Globals
404//===========================================================================================================================
405
406static AWDServerConnection *        gAWDServerConnection        = nil;
407static QueryStats *                 gQueryStatsList             = NULL;
408static ResolveStatsDomain *         gResolveStatsList           = NULL;
409static ResolveStatsDNSServer *      gResolveStatsServerList     = NULL;
410static unsigned int                 gResolveStatsNextServerID   = 0;
411static int                          gResolveStatsObjCount       = 0;
412static DNSMessageSizeStats *        gDNSMessageSizeStats        = NULL;
413
414// Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
415
416static const QueryStatsArgs     kQueryStatsArgs[] =
417{
418    { ".",                      NULL,                               QueryStatsDomainTest,           mDNSfalse },
419    { "",                       "alt:*-courier.push.apple.com.",    QueryStatsCourierPushTest,      mDNSfalse },
420    { "apple.com.",             NULL,                               QueryStatsDomainTest,           mDNStrue  },
421    { "gateway.icloud.com.",    "alt:gateway.icloud.com",           QueryStatsHostnameTest,         mDNSfalse },
422    { "",                       "alt:*-content.icloud.com.",        QueryStatsContentiCloudTest,    mDNSfalse },
423    { "icloud.com.",            NULL,                               QueryStatsDomainTest,           mDNStrue  },
424    { "mzstatic.com.",          NULL,                               QueryStatsDomainTest,           mDNStrue  },
425    { "google.com.",            NULL,                               QueryStatsDomainTest,           mDNStrue  },
426    { "baidu.com.",             NULL,                               QueryStatsDomainTest,           mDNStrue  },
427    { "yahoo.com.",             NULL,                               QueryStatsDomainTest,           mDNStrue  },
428    { "qq.com.",                NULL,                               QueryStatsDomainTest,           mDNStrue  }
429};
430
431check_compile_time(countof(kQueryStatsArgs) == 11);
432
433//===========================================================================================================================
434//  MetricsInit
435//===========================================================================================================================
436
437mStatus MetricsInit(void)
438{
439    @autoreleasepool
440    {
441        gAWDServerConnection = [[AWDServerConnectionSoft alloc]
442            initWithComponentId:     AWDComponentId_MDNSResponder
443            andBlockOnConfiguration: NO];
444
445        if (gAWDServerConnection)
446        {
447            [gAWDServerConnection
448                registerQueriableMetricCallback: ^(UInt32 inMetricID)
449                {
450                    SubmitAWDMetric(inMetricID);
451                }
452                forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
453
454            [gAWDServerConnection
455                registerQueriableMetricCallback: ^(UInt32 inMetricID)
456                {
457                    SubmitAWDMetric(inMetricID);
458                }
459                forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
460
461            [gAWDServerConnection
462                registerQueriableMetricCallback: ^(UInt32 inMetricID)
463                {
464                    SubmitAWDMetric(inMetricID);
465                }
466                forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
467
468            [gAWDServerConnection
469                registerQueriableMetricCallback: ^(UInt32 inMetricID)
470                {
471                    SubmitAWDMetric(inMetricID);
472                }
473                forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSMessageSizeStats];
474        }
475        else
476        {
477            LogMsg("MetricsInit: failed to create AWD server connection.");
478        }
479    }
480
481    if( gAWDServerConnection )
482    {
483        CreateQueryStatsList(&gQueryStatsList);
484        CreateResolveStatsList(&gResolveStatsList);
485        DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
486    }
487
488    return (mStatus_NoError);
489}
490
491//===========================================================================================================================
492//  MetricsUpdateDNSQueryStats
493//===========================================================================================================================
494
495mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
496{
497    QueryStats *        stats;
498    mDNSBool            match;
499
500    require_quiet(gAWDServerConnection, exit);
501    require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
502
503    for (stats = gQueryStatsList; stats; stats = stats->next)
504    {
505        match = stats->test(stats, inQueryName);
506        if (match)
507        {
508            QueryStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
509            if (stats->terminal) break;
510        }
511    }
512
513exit:
514    return;
515}
516
517//===========================================================================================================================
518//  MetricsUpdateDNSResolveStats
519//===========================================================================================================================
520
521mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
522{
523    ResolveStatsDomain *        domainStats;
524    domainname                  hostname;
525    size_t                      hostnameLen;
526    mDNSBool                    isQueryInDomain;
527    int                         skipCount;
528    int                         skipCountLast = -1;
529    int                         queryLabelCount;
530    const domainname *          queryParentDomain;
531    Response                    response;
532
533    require_quiet(gAWDServerConnection, exit);
534    require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
535    require_quiet(inRR->rDNSServer, exit);
536
537    queryLabelCount = CountLabels(inQueryName);
538
539    for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
540    {
541        isQueryInDomain = mDNSfalse;
542        skipCount = queryLabelCount - domainStats->labelCount;
543        if (skipCount >= 0)
544        {
545            if (skipCount != skipCountLast)
546            {
547                queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
548                skipCountLast = skipCount;
549            }
550            isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
551        }
552        if (!isQueryInDomain) continue;
553
554        hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
555        if (hostnameLen >= sizeof(hostname.c)) continue;
556
557        memcpy(hostname.c, inQueryName->c, hostnameLen);
558        hostname.c[hostnameLen] = 0;
559
560        if (inRR->RecordType == kDNSRecordTypePacketNegative)
561        {
562            response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
563            response.data = NULL;
564        }
565        else
566        {
567            response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
568            response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
569        }
570        ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
571    }
572
573exit:
574    return;
575}
576
577//===========================================================================================================================
578//  MetricsUpdateDNSQuerySize
579//===========================================================================================================================
580
581mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
582
583mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
584{
585    if (!gDNSMessageSizeStats) return;
586    UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
587}
588
589mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
590{
591    size_t      i;
592
593    if (inSize == 0) return;
594    i = (inSize - 1) / inBinWidth;
595    if (i >= inBinCount) i = inBinCount - 1;
596    increment_saturate(inBins[i], UINT16_MAX);
597}
598
599//===========================================================================================================================
600//  MetricsUpdateDNSResponseSize
601//===========================================================================================================================
602
603mDNSexport void MetricsUpdateDNSResponseSize(mDNSu32 inSize)
604{
605    if (!gDNSMessageSizeStats) return;
606    UpdateMessageSizeCounts(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth, inSize);
607}
608
609//===========================================================================================================================
610//  LogMetrics
611//===========================================================================================================================
612
613mDNSexport void LogMetrics(void)
614{
615    QueryStats *                        stats;
616    const ResolveStatsDomain *          domain;
617    const ResolveStatsHostname *        hostname;
618    const ResolveStatsDNSServer *       server;
619    const ResolveStatsIPv4AddrSet *     addrV4;
620    const ResolveStatsIPv6Addr *        addrV6;
621    const ResolveStatsNegAAAASet *      negV6;
622    int                                 hostnameCount;
623    int                                 i;
624    unsigned int                        serverID;
625    int                                 serverObjCount   = 0;
626    int                                 hostnameObjCount = 0;
627    int                                 addrObjCount     = 0;
628
629    LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
630    LogMsgNoIdent("---- DNS query stats by domain -----");
631
632    for (stats = gQueryStatsList; stats; stats = stats->next)
633    {
634        if (!stats->nonCellular && !stats->cellular)
635        {
636            LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
637            continue;
638        }
639        if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
640        if (stats->cellular)    LogDNSHistSet(stats->cellular,    QueryStatsGetDomainString(stats), mDNStrue);
641    }
642
643    LogMsgNoIdent("---- DNS resolve stats by domain -----");
644
645    LogMsgNoIdent("Servers:");
646    for (server = gResolveStatsServerList; server; server = server->next)
647    {
648        serverObjCount++;
649        LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
650            server->id, server->isForCell ? " C" : "NC", server->addrBytes);
651    }
652
653    for (domain = gResolveStatsList; domain; domain = domain->next)
654    {
655        hostnameCount = 0;
656        for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
657        hostnameObjCount += hostnameCount;
658
659        LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
660
661        for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
662        {
663            LogMsgNoIdent("    %##s", hostname->name);
664            for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
665            {
666                for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
667                {
668                    if (serverID == 0) addrObjCount++;
669                    for (i = 0; i < (int)countof(addrV4->counters); ++i)
670                    {
671                        const IPv4AddrCounter *      counter;
672
673                        counter = &addrV4->counters[i];
674                        if (counter->count == 0) break;
675                        if (counter->serverID == serverID)
676                        {
677                            if (counter->isNegative)
678                            {
679                                LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
680                            }
681                            else
682                            {
683                                LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
684                            }
685                        }
686                    }
687                }
688                for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
689                {
690                    if (serverID == 0) addrObjCount++;
691                    if (addrV6->serverID == serverID)
692                    {
693                        LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
694                    }
695                }
696                for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
697                {
698                    if (serverID == 0) addrObjCount++;
699                    for (i = 0; i < (int)countof(negV6->counters); ++i)
700                    {
701                        const NegAAAACounter *      counter;
702
703                        counter = &negV6->counters[i];
704                        if (counter->count == 0) break;
705                        if (counter->serverID == serverID)
706                        {
707                            LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
708                        }
709                    }
710                }
711            }
712        }
713    }
714    LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
715        serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
716
717    LogMsgNoIdent("---- Num of Services Registered -----");
718    LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
719                  curr_num_regservices, max_num_regservices);
720
721    if (gDNSMessageSizeStats)
722    {
723        LogMsgNoIdent("---- DNS query size stats ---");
724        LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
725
726        LogMsgNoIdent("-- DNS response size stats --");
727        LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
728    }
729    else
730    {
731        LogMsgNoIdent("No DNS message size stats.");
732    }
733}
734
735//===========================================================================================================================
736//  QueryStatsCreate
737//===========================================================================================================================
738
739mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName);
740
741mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats)
742{
743    mStatus             err;
744    QueryStats *        obj;
745
746    obj = (QueryStats *)calloc(1, sizeof(*obj));
747    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
748
749    obj->domainStr = inDomainStr;
750    err = StringToDomainName(obj->domainStr, &obj->domain);
751    require_noerr_quiet(err, exit);
752
753    obj->altDomainStr   = inAltDomainStr;
754    obj->test           = inTest;
755    obj->labelCount     = CountLabels((const domainname *)obj->domain);
756    obj->terminal       = inTerminal;
757
758    *outStats = obj;
759    obj = NULL;
760    err = mStatus_NoError;
761
762exit:
763    if (obj) QueryStatsFree(obj);
764    return (err);
765}
766
767mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName)
768{
769    mStatus             err;
770    uint8_t *           domainPtr = NULL;
771    size_t              domainLen;
772    const mDNSu8 *      ptr;
773    domainname          domain;
774
775    if (strcmp(inString, ".") == 0)
776    {
777        domain.c[0] = 0;
778    }
779    else
780    {
781        ptr = MakeDomainNameFromDNSNameString(&domain, inString);
782        require_action_quiet(ptr, exit, err = mStatus_BadParamErr);
783    }
784    domainLen = DomainNameLength(&domain);
785
786    domainPtr = (uint8_t *)malloc(domainLen);
787    require_action_quiet(domainPtr, exit, err = mStatus_NoMemoryErr);
788
789    memcpy(domainPtr, domain.c, domainLen);
790
791    *outDomainName = domainPtr;
792    domainPtr = NULL;
793    err = mStatus_NoError;
794
795exit:
796    return(err);
797}
798
799//===========================================================================================================================
800//  QueryStatsFree
801//===========================================================================================================================
802
803mDNSlocal void QueryStatsFree(QueryStats *inStats)
804{
805    ForgetMem(&inStats->domain);
806    if (inStats->nonCellular)
807    {
808        ForgetMem(&inStats->nonCellular->histA);
809        ForgetMem(&inStats->nonCellular->histAAAA);
810        free(inStats->nonCellular);
811        inStats->nonCellular = NULL;
812    }
813    if (inStats->cellular)
814    {
815        ForgetMem(&inStats->cellular->histA);
816        ForgetMem(&inStats->cellular->histAAAA);
817        free(inStats->cellular);
818        inStats->cellular = NULL;
819    }
820    free(inStats);
821}
822
823//===========================================================================================================================
824//  QueryStatsFreeList
825//===========================================================================================================================
826
827mDNSlocal void QueryStatsFreeList(QueryStats *inList)
828{
829    QueryStats *        stats;
830
831    while ((stats = inList) != NULL)
832    {
833        inList = stats->next;
834        QueryStatsFree(stats);
835    }
836}
837
838//===========================================================================================================================
839//  QueryStatsUpdate
840//===========================================================================================================================
841
842mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
843{
844    mStatus             err;
845    DNSHistSet *        set;
846    DNSHistSet **       pSet;
847    DNSHist *           hist;
848    DNSHist **          pHist;
849    int                 i;
850
851    require_action_quiet(inRR || (inQuerySendCount > 0), exit, err = mStatus_NoError);
852    require_action_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit, err = mStatus_NoError);
853
854    pSet = inForCell ? &inStats->cellular : &inStats->nonCellular;
855    if ((set = *pSet) == NULL)
856    {
857        set = (DNSHistSet *)calloc(1, sizeof(*set));
858        require_action_quiet(set, exit, err = mStatus_NoMemoryErr);
859        *pSet = set;
860    }
861    pHist = (inType == kDNSType_A) ? &set->histA : &set->histAAAA;
862    if ((hist = *pHist) == NULL)
863    {
864        hist = (DNSHist *)calloc(1, sizeof(*hist));
865        require_action_quiet(hist, exit, err = mStatus_NoMemoryErr);
866        *pHist = hist;
867    }
868
869    if (inRR)
870    {
871        uint16_t *          sendCountBins;
872        uint16_t *          latencyBins;
873        const mDNSBool      isNegative = (inRR->RecordType == kDNSRecordTypePacketNegative);
874
875        i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
876
877        sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
878        increment_saturate(sendCountBins[i], UINT16_MAX);
879
880        if (inQuerySendCount > 0)
881        {
882            for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
883            latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
884            increment_saturate(latencyBins[i], UINT16_MAX);
885        }
886    }
887    else
888    {
889        i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
890        increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
891
892        for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
893        increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
894    }
895    err = mStatus_NoError;
896
897exit:
898    return (err);
899}
900
901//===========================================================================================================================
902//  QueryStatsGetDomainString
903//===========================================================================================================================
904
905mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats)
906{
907    return (inStats->altDomainStr ? inStats->altDomainStr : inStats->domainStr);
908}
909
910//===========================================================================================================================
911//  QueryStatsDomainTest
912//===========================================================================================================================
913
914mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName)
915{
916    const domainname *      parentDomain;
917    int                     labelCount;
918
919    if (inStats->domain[0] == 0) return (mDNStrue);
920
921    labelCount = CountLabels(inQueryName);
922    if (labelCount < inStats->labelCount) return (mDNSfalse);
923
924    parentDomain = SkipLeadingLabels(inQueryName, labelCount - inStats->labelCount);
925    return (SameDomainName(parentDomain, (const domainname *)inStats->domain));
926}
927
928//===========================================================================================================================
929//  QueryStatsHostnameTest
930//===========================================================================================================================
931
932mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName)
933{
934    return (SameDomainName(inQueryName, (const domainname *)inStats->domain));
935}
936
937//===========================================================================================================================
938//  QueryStatsContentiCloudTest
939//===========================================================================================================================
940
941mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen);
942
943#define kContentSuffixStr       "-content"
944
945mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName)
946{
947    const mDNSu8 * const    firstLabel = inQueryName->c;
948    const uint8_t *         suffix;
949    const domainname *      parentDomain;
950    int                     labelCount;
951
952    (void) inStats; // Unused.
953
954    labelCount = CountLabels(inQueryName);
955    if (labelCount != 3) return (mDNSfalse);
956
957    suffix = LocateLabelSuffix(firstLabel, (const uint8_t *)kContentSuffixStr, sizeof_string(kContentSuffixStr));
958    if (suffix && (suffix > &firstLabel[1]))
959    {
960        parentDomain = SkipLeadingLabels(inQueryName, 1);
961        if (SameDomainName(parentDomain, (const domainname *)"\x6" "icloud" "\x3" "com"))
962        {
963            return (mDNStrue);
964        }
965    }
966
967    return (mDNSfalse);
968}
969
970mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen)
971{
972    const uint8_t *     ptr;
973    const uint8_t *     lp;
974    const uint8_t *     sp;
975    size_t              len;
976    const size_t        labelLen = inLabel[0];
977
978    if (labelLen < inSuffixLen) return (NULL);
979
980    ptr = &inLabel[1 + labelLen - inSuffixLen];
981    lp  = ptr;
982    sp  = inSuffixPtr;
983    for (len = inSuffixLen; len > 0; --len)
984    {
985        if (tolower(*lp) != tolower(*sp)) return (NULL);
986        ++lp;
987        ++sp;
988    }
989
990    return (ptr);
991}
992
993//===========================================================================================================================
994//  QueryStatsCourierPushTest
995//===========================================================================================================================
996
997#define kCourierSuffixStr       "-courier"
998
999mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName)
1000{
1001    const mDNSu8 * const    firstLabel = inQueryName->c;
1002    const uint8_t *         suffix;
1003    const uint8_t *         ptr;
1004    const domainname *      parentDomain;
1005    int                     labelCount;
1006
1007    (void) inStats; // Unused.
1008
1009    labelCount = CountLabels(inQueryName);
1010    if (labelCount != 4) return (mDNSfalse);
1011
1012    suffix = LocateLabelSuffix(firstLabel, (const mDNSu8 *)kCourierSuffixStr, sizeof_string(kCourierSuffixStr));
1013    if (suffix && (suffix > &firstLabel[1]))
1014    {
1015        for (ptr = &firstLabel[1]; ptr < suffix; ++ptr)
1016        {
1017            if (!isdigit(*ptr)) break;
1018        }
1019        if (ptr == suffix)
1020        {
1021            parentDomain = SkipLeadingLabels(inQueryName, 1);
1022            if (SameDomainName(parentDomain, (const domainname *)"\x4" "push" "\x5" "apple" "\x3" "com"))
1023            {
1024                return (mDNStrue);
1025            }
1026        }
1027    }
1028
1029    return (mDNSfalse);
1030}
1031
1032//===========================================================================================================================
1033//  ResolveStatsDomainCreate
1034//===========================================================================================================================
1035
1036mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
1037{
1038    mStatus                     err;
1039    ResolveStatsDomain *        obj;
1040
1041    obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
1042    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1043
1044    obj->domainStr = inDomainStr;
1045    err = StringToDomainName(obj->domainStr, &obj->domain);
1046    require_noerr_quiet(err, exit);
1047
1048    obj->labelCount = CountLabels((const domainname *)obj->domain);
1049
1050    *outDomain = obj;
1051    obj = NULL;
1052    err = mStatus_NoError;
1053
1054exit:
1055    if (obj) ResolveStatsDomainFree(obj);
1056    return (err);
1057}
1058
1059//===========================================================================================================================
1060//  ResolveStatsDomainFree
1061//===========================================================================================================================
1062
1063mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
1064{
1065    ResolveStatsHostname *      hostname;
1066
1067    ForgetMem(&inDomain->domain);
1068    while ((hostname = inDomain->hostnameList) != NULL)
1069    {
1070        inDomain->hostnameList = hostname->next;
1071        ResolveStatsHostnameFree(hostname);
1072    }
1073    free(inDomain);
1074}
1075
1076//===========================================================================================================================
1077//  ResolveStatsDomainUpdate
1078//===========================================================================================================================
1079
1080mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
1081{
1082    mStatus                     err;
1083    ResolveStatsHostname **     p;
1084    ResolveStatsHostname *      hostname;
1085    uint8_t                     serverID;
1086
1087    for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
1088    {
1089        if (SameDomainName((domainname *)hostname->name, inHostname)) break;
1090    }
1091
1092    if (!hostname)
1093    {
1094        require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1095        err = ResolveStatsHostnameCreate(inHostname, &hostname);
1096        require_noerr_quiet(err, exit);
1097        gResolveStatsObjCount++;
1098        *p = hostname;
1099    }
1100
1101    err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
1102    require_noerr_quiet(err, exit);
1103
1104    err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
1105    require_noerr_quiet(err, exit);
1106
1107exit:
1108    return (err);
1109}
1110
1111//===========================================================================================================================
1112//  ResolveStatsHostnameCreate
1113//===========================================================================================================================
1114
1115mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
1116{
1117    mStatus                     err;
1118    ResolveStatsHostname *      obj;
1119    size_t                      nameLen;
1120
1121    nameLen = DomainNameLength(inName);
1122    require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
1123
1124    obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
1125    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1126
1127    memcpy(obj->name, inName, nameLen);
1128
1129    *outHostname = obj;
1130    err = mStatus_NoError;
1131
1132exit:
1133    return (err);
1134}
1135
1136//===========================================================================================================================
1137//  ResolveStatsDomainCreateAWDVersion
1138//===========================================================================================================================
1139
1140mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
1141{
1142    mStatus                                     err;
1143    AWDMDNSResponderResolveStatsDomain *        domain;
1144    ResolveStatsHostname *                      hostname;
1145    AWDMDNSResponderResolveStatsHostname *      awdHostname;
1146    NSString *                                  name;
1147
1148    domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
1149    require_action_quiet(domain, exit, err = mStatus_UnknownErr);
1150
1151    name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
1152    require_action_quiet(name, exit, err = mStatus_UnknownErr);
1153
1154    domain.name = name;
1155    [name release];
1156    name = nil;
1157
1158    for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
1159    {
1160        err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
1161        require_noerr_quiet(err, exit);
1162
1163        [domain addHostname:awdHostname];
1164        [awdHostname release];
1165        awdHostname = nil;
1166    }
1167
1168    *outDomain = domain;
1169    domain = nil;
1170    err = mStatus_NoError;
1171
1172exit:
1173    [domain release];
1174    return (err);
1175}
1176
1177//===========================================================================================================================
1178//  ResolveStatsHostnameFree
1179//===========================================================================================================================
1180
1181mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
1182{
1183    ResolveStatsIPv4AddrSet *       addrV4;
1184    ResolveStatsIPv6Addr *          addrV6;
1185    ResolveStatsNegAAAASet *        negV6;
1186
1187    while ((addrV4 = inHostname->addrV4List) != NULL)
1188    {
1189        inHostname->addrV4List = addrV4->next;
1190        ResolveStatsIPv4AddrSetFree(addrV4);
1191    }
1192    while ((addrV6 = inHostname->addrV6List) != NULL)
1193    {
1194        inHostname->addrV6List = addrV6->next;
1195        ResolveStatsIPv6AddressFree(addrV6);
1196    }
1197    while ((negV6 = inHostname->negV6List) != NULL)
1198    {
1199        inHostname->negV6List = negV6->next;
1200        ResolveStatsNegAAAASetFree(negV6);
1201    }
1202    free(inHostname);
1203}
1204
1205//===========================================================================================================================
1206//  ResolveStatsHostnameUpdate
1207//===========================================================================================================================
1208
1209mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
1210{
1211    mStatus     err;
1212
1213    if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
1214    {
1215        ResolveStatsIPv4AddrSet **      p;
1216        ResolveStatsIPv4AddrSet *       addrV4;
1217        int                             i;
1218        IPv4AddrCounter *               counter;
1219
1220        for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
1221        {
1222            for (i = 0; i < (int)countof(addrV4->counters); ++i)
1223            {
1224                counter = &addrV4->counters[i];
1225                if (counter->count == 0) break;
1226                if (counter->serverID != inServerID) continue;
1227                if (inResp->type == kResponseType_NegA)
1228                {
1229                    if (counter->isNegative) break;
1230                }
1231                else
1232                {
1233                    if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
1234                }
1235            }
1236            if (i < (int)countof(addrV4->counters)) break;
1237        }
1238        if (!addrV4)
1239        {
1240            require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1241            err = ResolveStatsIPv4AddrSetCreate(&addrV4);
1242            require_noerr_quiet(err, exit);
1243            gResolveStatsObjCount++;
1244
1245            *p = addrV4;
1246            counter = &addrV4->counters[0];
1247        }
1248        if (counter->count == 0)
1249        {
1250            counter->serverID = inServerID;
1251            if (inResp->type == kResponseType_NegA)
1252            {
1253                counter->isNegative = 1;
1254            }
1255            else
1256            {
1257                counter->isNegative = 0;
1258                memcpy(counter->addrBytes, inResp->data, 4);
1259            }
1260        }
1261        increment_saturate(counter->count, UINT16_MAX);
1262        err = mStatus_NoError;
1263    }
1264    else if (inResp->type == kResponseType_IPv6Addr)
1265    {
1266        ResolveStatsIPv6Addr **     p;
1267        ResolveStatsIPv6Addr *      addrV6;
1268
1269        for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
1270        {
1271            if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
1272        }
1273        if (!addrV6)
1274        {
1275            require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1276            err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
1277            require_noerr_quiet(err, exit);
1278            gResolveStatsObjCount++;
1279
1280            *p = addrV6;
1281        }
1282        increment_saturate(addrV6->count, UINT16_MAX);
1283        err = mStatus_NoError;
1284    }
1285    else if (inResp->type == kResponseType_NegAAAA)
1286    {
1287        ResolveStatsNegAAAASet **       p;
1288        ResolveStatsNegAAAASet *        negV6;
1289        int                             i;
1290        NegAAAACounter *                counter;
1291
1292        for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
1293        {
1294            for (i = 0; i < (int)countof(negV6->counters); ++i)
1295            {
1296                counter = &negV6->counters[i];
1297                if ((counter->count == 0) || (counter->serverID == inServerID)) break;
1298            }
1299            if (i < (int)countof(negV6->counters)) break;
1300        }
1301        if (!negV6)
1302        {
1303            require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1304            err = ResolveStatsNegAAAASetCreate(&negV6);
1305            require_noerr_quiet(err, exit);
1306            gResolveStatsObjCount++;
1307
1308            *p = negV6;
1309            counter = &negV6->counters[0];
1310        }
1311        if (counter->count == 0) counter->serverID = inServerID;
1312        increment_saturate(counter->count, UINT16_MAX);
1313        err = mStatus_NoError;
1314    }
1315    else
1316    {
1317        err = mStatus_Invalid;
1318    }
1319
1320exit:
1321    return (err);
1322}
1323
1324//===========================================================================================================================
1325//  ResolveStatsHostnameCreateAWDVersion
1326//===========================================================================================================================
1327
1328mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
1329{
1330    mStatus                                     err;
1331    AWDMDNSResponderResolveStatsHostname *      hostname;
1332    NSString *                                  name;
1333    char                                        nameBuf[MAX_ESCAPED_DOMAIN_NAME];
1334    const char *                                ptr;
1335    ResolveStatsIPv4AddrSet *                   addrV4;
1336    ResolveStatsIPv6Addr *                      addrV6;
1337    ResolveStatsNegAAAASet *                    negV6;
1338    AWDMDNSResponderResolveStatsResult *        result = nil;
1339    int                                         i;
1340
1341    hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
1342    require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
1343
1344    ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
1345    require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
1346
1347    name = [[NSString alloc] initWithUTF8String:nameBuf];
1348    require_action_quiet(name, exit, err = mStatus_UnknownErr);
1349
1350    hostname.name = name;
1351    [name release];
1352    name = nil;
1353
1354    for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
1355    {
1356        for (i = 0; i < (int)countof(addrV4->counters); ++i)
1357        {
1358            const IPv4AddrCounter *     counter;
1359            NSData *                    addrBytes;
1360
1361            counter = &addrV4->counters[i];
1362            if (counter->count == 0) break;
1363
1364            result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1365            require_action_quiet(result, exit, err = mStatus_UnknownErr);
1366
1367            if (counter->isNegative)
1368            {
1369                result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
1370            }
1371            else
1372            {
1373                addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
1374                require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1375
1376                result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
1377                result.data = addrBytes;
1378                [addrBytes release];
1379            }
1380            result.count    = counter->count;
1381            result.serverID = counter->serverID;
1382
1383            [hostname addResult:result];
1384            [result release];
1385            result = nil;
1386        }
1387    }
1388
1389    for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
1390    {
1391        NSData *        addrBytes;
1392
1393        result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1394        require_action_quiet(result, exit, err = mStatus_UnknownErr);
1395
1396        addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
1397        require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1398
1399        result.type     = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
1400        result.count    = addrV6->count;
1401        result.serverID = addrV6->serverID;
1402        result.data     = addrBytes;
1403
1404        [addrBytes release];
1405
1406        [hostname addResult:result];
1407        [result release];
1408        result = nil;
1409    }
1410
1411    for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
1412    {
1413        for (i = 0; i < (int)countof(negV6->counters); ++i)
1414        {
1415            const NegAAAACounter *      counter;
1416
1417            counter = &negV6->counters[i];
1418            if (counter->count == 0) break;
1419
1420            result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
1421            require_action_quiet(result, exit, err = mStatus_UnknownErr);
1422
1423            result.type     = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
1424            result.count    = counter->count;
1425            result.serverID = counter->serverID;
1426
1427            [hostname addResult:result];
1428            [result release];
1429            result = nil;
1430        }
1431    }
1432
1433    *outHostname = hostname;
1434    hostname = nil;
1435    err = mStatus_NoError;
1436
1437exit:
1438    [result release];
1439    [hostname release];
1440    return (err);
1441}
1442
1443//===========================================================================================================================
1444//  ResolveStatsDNSServerCreate
1445//===========================================================================================================================
1446
1447mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
1448{
1449    mStatus                     err;
1450    ResolveStatsDNSServer *     obj;
1451    size_t                      addrLen;
1452
1453    require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1454
1455    addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
1456    obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
1457    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1458
1459    obj->isForCell = inForCell;
1460    if (inAddr->type == mDNSAddrType_IPv4)
1461    {
1462        obj->isAddrV6 = mDNSfalse;
1463        memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
1464    }
1465    else
1466    {
1467        obj->isAddrV6 = mDNStrue;
1468        memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
1469    }
1470
1471    *outServer = obj;
1472    err = mStatus_NoError;
1473
1474exit:
1475    return (err);
1476}
1477
1478//===========================================================================================================================
1479//  ResolveStatsDNSServerFree
1480//===========================================================================================================================
1481
1482mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
1483{
1484    free(inServer);
1485}
1486
1487//===========================================================================================================================
1488//  ResolveStatsDNSServerCreateAWDVersion
1489//===========================================================================================================================
1490
1491mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
1492{
1493    mStatus                                     err;
1494    AWDMDNSResponderResolveStatsDNSServer *     server;
1495    NSData *                                    addrBytes = nil;
1496
1497    server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
1498    require_action_quiet(server, exit, err = mStatus_UnknownErr);
1499
1500    addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
1501    require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
1502
1503    server.serverID = inServer->id;
1504    server.address  = addrBytes;
1505    if (inServer->isForCell)
1506    {
1507        server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
1508    }
1509    else
1510    {
1511        server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
1512    }
1513
1514    *outServer = server;
1515    server = nil;
1516    err = mStatus_NoError;
1517
1518exit:
1519    [addrBytes release];
1520    [server release];
1521    return (err);
1522}
1523
1524//===========================================================================================================================
1525//  ResolveStatsIPv4AddrSetCreate
1526//===========================================================================================================================
1527
1528mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
1529{
1530    mStatus                         err;
1531    ResolveStatsIPv4AddrSet *       obj;
1532
1533    obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
1534    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1535
1536    *outSet = obj;
1537    err = mStatus_NoError;
1538
1539exit:
1540    return (err);
1541}
1542
1543//===========================================================================================================================
1544//  ResolveStatsIPv4AddrSetFree
1545//===========================================================================================================================
1546
1547mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
1548{
1549    free(inSet);
1550}
1551
1552//===========================================================================================================================
1553//  ResolveStatsIPv6AddressCreate
1554//===========================================================================================================================
1555
1556mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
1557{
1558    mStatus                     err;
1559    ResolveStatsIPv6Addr *      obj;
1560
1561    obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
1562    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1563
1564    obj->serverID = inServerID;
1565    memcpy(obj->addrBytes, inAddrBytes, 16);
1566
1567    *outAddr = obj;
1568    err = mStatus_NoError;
1569
1570exit:
1571    return (err);
1572}
1573
1574//===========================================================================================================================
1575//  ResolveStatsIPv6AddressFree
1576//===========================================================================================================================
1577
1578mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
1579{
1580    free(inAddr);
1581}
1582
1583//===========================================================================================================================
1584//  ResolveStatsNegAAAASetCreate
1585//===========================================================================================================================
1586
1587mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
1588{
1589    mStatus                         err;
1590    ResolveStatsNegAAAASet *        obj;
1591
1592    obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
1593    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
1594
1595    *outSet = obj;
1596    err = mStatus_NoError;
1597
1598exit:
1599    return (err);
1600}
1601
1602//===========================================================================================================================
1603//  ResolveStatsNegAAAASetFree
1604//===========================================================================================================================
1605
1606mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
1607{
1608    free(inSet);
1609}
1610
1611//===========================================================================================================================
1612//  ResolveStatsGetServerID
1613//===========================================================================================================================
1614
1615mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
1616{
1617    mStatus                         err;
1618    ResolveStatsDNSServer **        p;
1619    ResolveStatsDNSServer *         server;
1620
1621    require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
1622
1623    for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
1624    {
1625        if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
1626        {
1627            if (inServerAddr->type == mDNSAddrType_IPv4)
1628            {
1629                if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
1630            }
1631            else
1632            {
1633                if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
1634            }
1635        }
1636    }
1637
1638    if (!server)
1639    {
1640        require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
1641        require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
1642        err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
1643        require_noerr_quiet(err, exit);
1644        gResolveStatsObjCount++;
1645
1646        server->id   = (uint8_t)gResolveStatsNextServerID++;
1647        server->next = gResolveStatsServerList;
1648        gResolveStatsServerList = server;
1649    }
1650    else if (gResolveStatsServerList != server)
1651    {
1652        *p = server->next;
1653        server->next = gResolveStatsServerList;
1654        gResolveStatsServerList = server;
1655    }
1656
1657    *outServerID = server->id;
1658    err = mStatus_NoError;
1659
1660exit:
1661    return (err);
1662}
1663
1664//===========================================================================================================================
1665//  DNSMessageSizeStatsCreate
1666//===========================================================================================================================
1667
1668mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
1669{
1670    mStatus                     err;
1671    DNSMessageSizeStats *       stats;
1672
1673    stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
1674    require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
1675
1676    *outStats = stats;
1677    err = mStatus_NoError;
1678
1679exit:
1680    return (err);
1681}
1682
1683//===========================================================================================================================
1684//  DNSMessageSizeStatsFree
1685//===========================================================================================================================
1686
1687mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
1688{
1689    free(inStats);
1690}
1691
1692//===========================================================================================================================
1693//  CreateQueryStatsList
1694//===========================================================================================================================
1695
1696mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
1697{
1698    mStatus                             err;
1699    QueryStats **                       p;
1700    QueryStats *                        stats;
1701    const QueryStatsArgs *              args;
1702    const QueryStatsArgs * const        end     = kQueryStatsArgs + countof(kQueryStatsArgs);
1703    QueryStats *                        list    = NULL;
1704
1705    p = &list;
1706    for (args = kQueryStatsArgs; args < end; ++args)
1707    {
1708        err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
1709        require_noerr_quiet(err, exit);
1710
1711        *p = stats;
1712        p = &stats->next;
1713    }
1714
1715    *outList = list;
1716    list = NULL;
1717    err = mStatus_NoError;
1718
1719exit:
1720    QueryStatsFreeList(list);
1721    return (err);
1722}
1723
1724//===========================================================================================================================
1725//  CreateResolveStatsList
1726//===========================================================================================================================
1727
1728mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
1729{
1730    mStatus                     err;
1731    unsigned int                i;
1732    ResolveStatsDomain *        domain;
1733    ResolveStatsDomain **       p;
1734    ResolveStatsDomain *        list = NULL;
1735
1736    p = &list;
1737    for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
1738    {
1739        err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
1740        require_noerr_quiet(err, exit);
1741
1742        *p = domain;
1743        p = &domain->next;
1744    }
1745
1746    *outList = list;
1747    list = NULL;
1748    err = mStatus_NoError;
1749
1750exit:
1751    FreeResolveStatsList(list);
1752    return (err);
1753}
1754
1755//===========================================================================================================================
1756//  FreeResolveStatsList
1757//===========================================================================================================================
1758
1759mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
1760{
1761    ResolveStatsDomain *        domain;
1762
1763    while ((domain = inList) != NULL)
1764    {
1765        inList = domain->next;
1766        ResolveStatsDomainFree(domain);
1767    }
1768}
1769
1770//===========================================================================================================================
1771//  FreeResolveStatsServerList
1772//===========================================================================================================================
1773
1774mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
1775{
1776    ResolveStatsDNSServer *     server;
1777
1778    while ((server = inList) != NULL)
1779    {
1780        inList = server->next;
1781        ResolveStatsDNSServerFree(server);
1782    }
1783}
1784
1785//===========================================================================================================================
1786//  SubmitAWDMetric
1787//===========================================================================================================================
1788
1789mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
1790{
1791    mStatus     err;
1792
1793    switch (inMetricID)
1794    {
1795        case AWDMetricId_MDNSResponder_DNSStatistics:
1796            err = SubmitAWDMetricQueryStats();
1797            break;
1798
1799        case AWDMetricId_MDNSResponder_ResolveStats:
1800            err = SubmitAWDMetricResolveStats();
1801            break;
1802
1803        case AWDMetricId_MDNSResponder_ServicesStats:
1804            [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
1805            KQueueLock();
1806            // reset the no of max services since we want to collect the max no of services registered per AWD submission period
1807            max_num_regservices = curr_num_regservices;
1808            KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
1809            err = mStatus_NoError;
1810            break;
1811
1812        case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
1813            err = SubmitAWDMetricDNSMessageSizeStats();
1814            break;
1815
1816        default:
1817            err = mStatus_UnsupportedErr;
1818            break;
1819    }
1820
1821    if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
1822    return (err);
1823}
1824
1825//===========================================================================================================================
1826//  SubmitAWDMetricQueryStats
1827//===========================================================================================================================
1828
1829mDNSlocal mStatus   AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
1830mDNSlocal mStatus   AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
1831
1832mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
1833{
1834    mStatus                             err;
1835    BOOL                                success;
1836    QueryStats *                        stats;
1837    QueryStats *                        statsList;
1838    QueryStats *                        newStatsList;
1839    AWDMetricContainer *                container   = nil;
1840    AWDMDNSResponderDNSStatistics *     metric      = nil;
1841
1842    newStatsList = NULL;
1843    CreateQueryStatsList(&newStatsList);
1844
1845    KQueueLock();
1846    statsList       = gQueryStatsList;
1847    gQueryStatsList = newStatsList;
1848    KQueueUnlock("SubmitAWDMetricQueryStats");
1849
1850    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
1851    require_action_quiet(container, exit, err = mStatus_UnknownErr);
1852
1853    metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
1854    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1855
1856    while ((stats = statsList) != NULL)
1857    {
1858        err = AddQueryStats(metric, stats);
1859        require_noerr_quiet(err, exit);
1860
1861        statsList = stats->next;
1862        QueryStatsFree(stats);
1863    }
1864
1865    container.metric = metric;
1866    success = [gAWDServerConnection submitMetric:container];
1867    LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
1868    err = success ? mStatus_NoError : mStatus_UnknownErr;
1869
1870exit:
1871    [metric release];
1872    [container release];
1873    QueryStatsFreeList(statsList);
1874    return (err);
1875}
1876
1877mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
1878{
1879    mStatus     err;
1880
1881    if (inStats->nonCellular)
1882    {
1883        err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
1884        require_noerr_quiet(err, exit);
1885    }
1886    if (inStats->cellular)
1887    {
1888        err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
1889        require_noerr_quiet(err, exit);
1890    }
1891    err = mStatus_NoError;
1892
1893exit:
1894    return (err);
1895}
1896
1897mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
1898{
1899    mStatus                 err;
1900    AWDDNSDomainStats *     awdStats;
1901
1902    if (inSet->histA)
1903    {
1904        err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
1905        require_noerr_quiet(err, exit);
1906
1907        [inMetric addStats:awdStats];
1908        [awdStats release];
1909    }
1910    if (inSet->histAAAA)
1911    {
1912        err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
1913        require_noerr_quiet(err, exit);
1914
1915        [inMetric addStats:awdStats];
1916        [awdStats release];
1917    }
1918    err = mStatus_NoError;
1919
1920exit:
1921    return (err);
1922}
1923
1924//===========================================================================================================================
1925//  SubmitAWDMetricResolveStats
1926//===========================================================================================================================
1927
1928mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
1929{
1930    mStatus                             err;
1931    ResolveStatsDomain *                newResolveStatsList;
1932    ResolveStatsDomain *                domainList  = NULL;
1933    ResolveStatsDNSServer *             serverList  = NULL;
1934    AWDMetricContainer *                container   = nil;
1935    AWDMDNSResponderResolveStats *      metric      = nil;
1936    ResolveStatsDNSServer *             server;
1937    ResolveStatsDomain *                domain;
1938    BOOL                                success;
1939
1940    err = CreateResolveStatsList(&newResolveStatsList);
1941    require_noerr_quiet(err, exit);
1942
1943    KQueueLock();
1944    domainList = gResolveStatsList;
1945    serverList = gResolveStatsServerList;
1946    gResolveStatsList           = newResolveStatsList;
1947    gResolveStatsServerList     = NULL;
1948    gResolveStatsNextServerID   = 0;
1949    gResolveStatsObjCount       = 0;
1950    KQueueUnlock("SubmitAWDMetricResolveStats");
1951
1952    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
1953    require_action_quiet(container, exit, err = mStatus_UnknownErr);
1954
1955    metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
1956    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
1957
1958    while ((server = serverList) != NULL)
1959    {
1960        AWDMDNSResponderResolveStatsDNSServer *     awdServer;
1961
1962        serverList = server->next;
1963        err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
1964        ResolveStatsDNSServerFree(server);
1965        require_noerr_quiet(err, exit);
1966
1967        [metric addServer:awdServer];
1968        [awdServer release];
1969    }
1970
1971    while ((domain = domainList) != NULL)
1972    {
1973        AWDMDNSResponderResolveStatsDomain *        awdDomain;
1974
1975        domainList = domain->next;
1976        err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
1977        ResolveStatsDomainFree(domain);
1978        require_noerr_quiet(err, exit);
1979
1980        [metric addDomain:awdDomain];
1981        [awdDomain release];
1982    }
1983
1984    container.metric = metric;
1985    success = [gAWDServerConnection submitMetric:container];
1986    LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed");
1987    err = success ? mStatus_NoError : mStatus_UnknownErr;
1988
1989exit:
1990    [metric release];
1991    [container release];
1992    FreeResolveStatsList(domainList);
1993    FreeResolveStatsServerList(serverList);
1994    return (err);
1995}
1996
1997//===========================================================================================================================
1998//  SubmitAWDMetricDNSMessageSizeStats
1999//===========================================================================================================================
2000
2001mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
2002{
2003    mStatus                                     err;
2004    DNSMessageSizeStats *                       stats;
2005    DNSMessageSizeStats *                       newStats;
2006    AWDMetricContainer *                        container;
2007    AWDMDNSResponderDNSMessageSizeStats *       metric = nil;
2008    BOOL                                        success;
2009
2010    newStats = NULL;
2011    DNSMessageSizeStatsCreate(&newStats);
2012
2013    KQueueLock();
2014    stats                   = gDNSMessageSizeStats;
2015    gDNSMessageSizeStats    = newStats;
2016    KQueueUnlock("SubmitAWDMetricDNSMessageSizeStats");
2017
2018    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSMessageSizeStats];
2019    require_action_quiet(container, exit, err = mStatus_UnknownErr);
2020
2021    metric = [[AWDMDNSResponderDNSMessageSizeStatsSoft alloc] init];
2022    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
2023
2024    if (stats)
2025    {
2026        size_t          binCount;
2027        uint32_t        bins[Max(kQuerySizeBinCount, kResponseSizeBinCount)];
2028
2029        // Set query size counts.
2030
2031        binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
2032        [metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
2033
2034        // Set response size counts.
2035
2036        binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
2037        [metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
2038    }
2039
2040    container.metric = metric;
2041    success = [gAWDServerConnection submitMetric:container];
2042    LogMsg("SubmitAWDMetricDNSMessageSizeStats: metric submission %s.", success ? "succeeded" : "failed");
2043    err = success ? mStatus_NoError : mStatus_UnknownErr;
2044
2045exit:
2046    [metric release];
2047    [container release];
2048    if (stats) DNSMessageSizeStatsFree(stats);
2049    return (err);
2050}
2051
2052//===========================================================================================================================
2053//  CreateAWDDNSDomainStats
2054//===========================================================================================================================
2055
2056mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats)
2057{
2058    mStatus                 err;
2059    AWDDNSDomainStats *     awdStats    = nil;
2060    NSString *              domain      = nil;
2061    size_t                  binCount;
2062    uint32_t                sendCountBins[kQueryStatsSendCountBinCount];
2063    uint32_t                latencyBins[kQueryStatsLatencyBinCount];
2064
2065    awdStats = [[AWDDNSDomainStatsSoft alloc] init];
2066    require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
2067
2068    domain = [[NSString alloc] initWithUTF8String:inDomain];
2069    require_action_quiet(domain, exit, err = mStatus_UnknownErr);
2070
2071    awdStats.domain      = domain;
2072    awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
2073    awdStats.recordType  = inType;
2074
2075    // Positively answered query send counts
2076
2077    binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
2078    [awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2079
2080    // binCount > 1 means that at least one of the non-zero send count bins had a non-zero count, i.e., at least one query
2081    // was sent out on the wire. In that case, include the associated latency bins as well.
2082
2083    if (binCount > 1)
2084    {
2085        binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
2086        [awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2087    }
2088
2089    // Negatively answered query send counts
2090
2091    binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2092    [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2093
2094    if (binCount > 1)
2095    {
2096        binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
2097        [awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
2098    }
2099
2100    // Unanswered query send counts
2101
2102    binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
2103    [awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
2104
2105    if (binCount > 1)
2106    {
2107        binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
2108        [awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
2109    }
2110
2111    *outStats = awdStats;
2112    awdStats = nil;
2113    err = mStatus_NoError;
2114
2115exit:
2116    [domain release];
2117    [awdStats release];
2118    return (err);
2119}
2120
2121//===========================================================================================================================
2122//  LogDNSHistSet
2123//===========================================================================================================================
2124
2125mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
2126{
2127    if (inSet->histA)       LogDNSHist(inSet->histA,    inDomain, inForCell, "A");
2128    if (inSet->histAAAA)    LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
2129}
2130
2131//===========================================================================================================================
2132//  LogDNSHist
2133//===========================================================================================================================
2134
2135#define Percent(N, D)       (((N) * 100) / (D)), ((((N) * 10000) / (D)) % 100)
2136#define PercentFmt          "%3u.%02u"
2137#define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
2138    LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
2139
2140mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
2141{
2142    unsigned int        totalAnswered;
2143    unsigned int        totalNegAnswered;
2144    unsigned int        totalUnanswered;
2145    int                 i;
2146
2147    totalAnswered = 0;
2148    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2149    {
2150        totalAnswered += inHist->answeredQuerySendCountBins[i];
2151    }
2152
2153    totalNegAnswered = 0;
2154    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2155    {
2156        totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
2157    }
2158
2159    totalUnanswered = 0;
2160    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2161    {
2162        totalUnanswered += inHist->unansweredQuerySendCountBins[i];
2163    }
2164
2165    LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
2166    LogMsgNoIdent("Answered questions            %4u", totalAnswered);
2167    LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
2168    LogMsgNoIdent("Unanswered questions          %4u", totalUnanswered);
2169    LogMsgNoIdent("-- Query send counts ---------");
2170    LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
2171    LogMsgNoIdent("-- Query send counts (NAQs) --");
2172    LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
2173
2174    if (totalAnswered > inHist->answeredQuerySendCountBins[0])
2175    {
2176        LogMsgNoIdent("--- Response times -----------");
2177        LogDNSHistLatencies(inHist->responseLatencyBins);
2178    }
2179
2180    if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
2181    {
2182        LogMsgNoIdent("--- Response times (NAQs) ----");
2183        LogDNSHistLatencies(inHist->negResponseLatencyBins);
2184    }
2185
2186    if (totalUnanswered > 0)
2187    {
2188        LogMsgNoIdent("--- Unanswered query times ---");
2189        LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
2190    }
2191}
2192
2193//===========================================================================================================================
2194//  LogDNSHistSendCounts
2195//===========================================================================================================================
2196
2197mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
2198{
2199    uint32_t        total;
2200    char            label[16];
2201    int             i;
2202
2203    total = 0;
2204    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2205    {
2206        total += inSendCountBins[i];
2207    }
2208
2209    if (total > 0)
2210    {
2211        uint32_t        accumulator = 0;
2212
2213        for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
2214        {
2215            accumulator += inSendCountBins[i];
2216            if (i < (kQueryStatsSendCountBinCount - 1))
2217            {
2218                snprintf(label, sizeof(label), "%2d ", i);
2219            }
2220            else
2221            {
2222                snprintf(label, sizeof(label), "%2d+", i);
2223            }
2224            LogStat(label, inSendCountBins[i], accumulator, total);
2225            if (accumulator == total) break;
2226        }
2227    }
2228    else
2229    {
2230        LogMsgNoIdent("No data.");
2231    }
2232}
2233
2234//===========================================================================================================================
2235//  LogDNSHistLatencies
2236//===========================================================================================================================
2237
2238mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
2239{
2240    uint32_t        total;
2241    int             i;
2242    char            label[16];
2243
2244    total = 0;
2245    for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2246    {
2247        total += inLatencyBins[i];
2248    }
2249
2250    if (total > 0)
2251    {
2252        uint32_t        accumulator = 0;
2253
2254        for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
2255        {
2256            accumulator += inLatencyBins[i];
2257            if (i < (int)countof(kResponseLatencyMsLimits))
2258            {
2259                snprintf(label, sizeof(label), "< %5u ms", kResponseLatencyMsLimits[i]);
2260            }
2261            else
2262            {
2263                snprintf(label, sizeof(label), "<     âˆž ms");
2264            }
2265            LogStat(label, inLatencyBins[i], accumulator, total);
2266            if (accumulator == total) break;
2267        }
2268    }
2269    else
2270    {
2271        LogMsgNoIdent("No data.");
2272    }
2273}
2274
2275//===========================================================================================================================
2276//  LogDNSMessageSizeStats
2277//===========================================================================================================================
2278
2279mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
2280{
2281    size_t          i;
2282    uint32_t        total;
2283
2284    total = 0;
2285    for (i = 0; i < inBinCount; ++i)
2286    {
2287        total += inBins[i];
2288    }
2289
2290    if (total > 0)
2291    {
2292        uint32_t            accumulator;
2293        unsigned int        lower, upper;
2294        char                label[16];
2295
2296        accumulator = 0;
2297        upper       = 0;
2298        for (i = 0; i < inBinCount; ++i)
2299        {
2300            accumulator += inBins[i];
2301            lower = upper + 1;
2302            if (i < (inBinCount - 1))
2303            {
2304                upper += inBinWidth;
2305                snprintf(label, sizeof(label), "%3u - %-3u", lower, upper);
2306            }
2307            else
2308            {
2309                snprintf(label, sizeof(label), "%3u+     ", lower);
2310            }
2311            LogStat(label, inBins[i], accumulator, total);
2312            if (accumulator == total) break;
2313        }
2314    }
2315    else
2316    {
2317        LogMsgNoIdent("No data.");
2318    }
2319}
2320
2321//===========================================================================================================================
2322//  CopyHistogramBins
2323//
2324//  Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
2325//  bin and all bins with non-zero values.
2326//===========================================================================================================================
2327
2328mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
2329{
2330    size_t      i;
2331    size_t      minCount;
2332
2333    if (inBinCount == 0) return (0);
2334
2335    minCount = 1;
2336    for (i = 0; i < inBinCount; ++i)
2337    {
2338        inDstBins[i] = inSrcBins[i];
2339        if (inDstBins[i] > 0) minCount = i + 1;
2340    }
2341
2342    return (minCount);
2343}
2344#endif // TARGET_OS_IOS
Note: See TracBrowser for help on using the repository browser.