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

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

mDNSResponder: Update to v765.1.2

The sources can be obtained via:

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

Move mDNS_StartResolveService() and mDNS_StopResolveService() to an
RTEMS-specific file (rtemsbsd/mdns/mDNSResolveService.c) using the
v576.30.4 implementation. Apple removed these functions without
explanation.

Update #3522.

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