[rtems-libbsd commit] mDNSResponder: Update to v878.30.4

Sebastian Huber sebh at rtems.org
Thu Sep 20 09:29:04 UTC 2018


Module:    rtems-libbsd
Branch:    master
Commit:    272360946778648e9090941ad1aa43b60d5031a3
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=272360946778648e9090941ad1aa43b60d5031a3

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Sep 19 08:57:22 2018 +0200

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.

---

 mDNSResponder/Makefile                   |   2 +-
 mDNSResponder/mDNSCore/mDNS.c            |  15 +-
 mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h |   6 +-
 mDNSResponder/mDNSCore/uDNS.c            |  15 +-
 mDNSResponder/mDNSMacOSX/Metrics.h       |  18 +-
 mDNSResponder/mDNSMacOSX/Metrics.m       | 973 +++++++++++++++++++++----------
 mDNSResponder/mDNSMacOSX/daemon.c        |  33 +-
 mDNSResponder/mDNSMacOSX/helper.c        |  19 +-
 mDNSResponder/mDNSMacOSX/mDNSMacOSX.c    |  54 +-
 mDNSResponder/mDNSShared/dns_sd.h        |   2 +-
 10 files changed, 782 insertions(+), 355 deletions(-)

diff --git a/mDNSResponder/Makefile b/mDNSResponder/Makefile
index 1c7c63a..9d97533 100644
--- a/mDNSResponder/Makefile
+++ b/mDNSResponder/Makefile
@@ -16,7 +16,7 @@
 
 include $(MAKEFILEPATH)/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-878.20.3"
+MVERS = "mDNSResponder-878.30.4"
 
 VER =
 ifneq ($(strip $(GCC_VERSION)),)
diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c
index 0d4d8ae..72375d9 100755
--- a/mDNSResponder/mDNSCore/mDNS.c
+++ b/mDNSResponder/mDNSCore/mDNS.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2017 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -4170,12 +4170,12 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
                 responseLatencyMs = 0;
             }
 
-            MetricsUpdateUDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, responseLatencyMs, isForCellular);
+            MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, responseLatencyMs, isForCellular);
             q->metrics.answered = mDNStrue;
         }
         if (q->metrics.querySendCount > 0)
         {
-            MetricsUpdateUDNSResolveStats(queryName, &rr->resrec, isForCellular);
+            MetricsUpdateDNSResolveStats(queryName, &rr->resrec, isForCellular);
         }
     }
 #endif
@@ -8944,6 +8944,13 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
            response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
            response->h.numAdditionals, response->h.numAdditionals == 1 ? " "    : "s", end - response->data, LLQType);
 
+#if AWD_METRICS
+    if (mDNSSameIPPort(srcport, UnicastDNSPort))
+    {
+        MetricsUpdateDNSResponseSize((mDNSu32)(end - (mDNSu8 *)response));
+    }
+#endif
+
     // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
     //    When a DNS client receives a reply with TC
     //    set, it should ignore that response, and query again, using a
@@ -12127,7 +12134,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
         queryName  = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
         isForCell  = (question->qDNSServer && question->qDNSServer->cellIntf);
         durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
-        MetricsUpdateUDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell);
+        MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell);
     }
 #endif
     // Take care to cut question from list *before* calling UpdateQuestionDuplicates
diff --git a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
index 0e96058..72ff7ca 100755
--- a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2017 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1896,7 +1896,7 @@ typedef enum { DNSSECValNotRequired = 0, DNSSECValRequired, DNSSECValInProgress,
 // RFC 4122 defines it to be 16 bytes 
 #define UUID_SIZE       16
 
-#define AWD_METRICS (USE_AWD && TARGET_OS_EMBEDDED)
+#define AWD_METRICS (USE_AWD && TARGET_OS_IOS)
 
 #if AWD_METRICS
 typedef struct
@@ -2039,7 +2039,7 @@ struct DNSQuestion_struct
     domainname           *qnameOrig;        // Copy of the original question name if it is not fully qualified
     mDNSQuestionCallback *QuestionCallback;
     void                 *QuestionContext;
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
     uDNSMetrics metrics;                    // Data used for collecting unicast DNS query metrics.
 #endif
 #if USE_DNS64
diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c
index dc87724..4d01142 100755
--- a/mDNSResponder/mDNSCore/uDNS.c
+++ b/mDNSResponder/mDNSCore/uDNS.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2017 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,10 @@
 #endif
 #include "uDNS.h"
 
+#if AWD_METRICS
+#include "Metrics.h"
+#endif
+
 #if (defined(_MSC_VER))
 // Disable "assignment within conditional expression".
 // Other compilers understand the convention that if you place the assignment expression within an extra pair
@@ -1329,6 +1333,12 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
 
         err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo, mDNSfalse);
         if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
+#if AWD_METRICS
+        if (mDNSSameIPPort(tcpInfo->Port, UnicastDNSPort))
+        {
+            MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&tcpInfo->request));
+        }
+#endif
 
         // Record time we sent this question
         if (q)
@@ -4758,9 +4768,10 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                     else
                     {
                         err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass);
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
                         if (!err)
                         {
+                            MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
                             if (q->metrics.answered)
                             {
                                 q->metrics.querySendCount = 0;
diff --git a/mDNSResponder/mDNSMacOSX/Metrics.h b/mDNSResponder/mDNSMacOSX/Metrics.h
index dbe6196..ff419fd 100644
--- a/mDNSResponder/mDNSMacOSX/Metrics.h
+++ b/mDNSResponder/mDNSMacOSX/Metrics.h
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2016 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,19 +14,22 @@
  * limitations under the License.
  */
 
-#include "mDNSEmbeddedAPI.h"
-
 #ifndef __Metrics_h
 #define __Metrics_h
 
+#include "mDNSEmbeddedAPI.h"
+#include <TargetConditionals.h>
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IOS
 mStatus MetricsInit(void);
-void    MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
-void    MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell);
+void    MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
+void    MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell);
+void    MetricsUpdateDNSQuerySize(mDNSu32 inSize);
+void    MetricsUpdateDNSResponseSize(mDNSu32 inSize);
 void    LogMetrics(void);
 #endif
 
diff --git a/mDNSResponder/mDNSMacOSX/Metrics.m b/mDNSResponder/mDNSMacOSX/Metrics.m
index f8a3ae7..e540f3b 100644
--- a/mDNSResponder/mDNSMacOSX/Metrics.m
+++ b/mDNSResponder/mDNSMacOSX/Metrics.m
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2016 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,18 +16,19 @@
 
 #import "Metrics.h"
 
-#if (TARGET_OS_EMBEDDED)
+#if (TARGET_OS_IOS)
 #import <CoreUtils/SoftLinking.h>
 #import <WirelessDiagnostics/AWDDNSDomainStats.h>
+#import <WirelessDiagnostics/AWDMDNSResponderDNSMessageSizeStats.h>
 #import <WirelessDiagnostics/AWDMDNSResponderDNSStatistics.h>
 #import <WirelessDiagnostics/AWDMDNSResponderResolveStats.h>
 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDNSServer.h>
 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDomain.h>
 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsHostname.h>
 #import <WirelessDiagnostics/AWDMDNSResponderResolveStatsResult.h>
+#import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
 #import <WirelessDiagnostics/AWDMetricIds_MDNSResponder.h>
 #import <WirelessDiagnostics/WirelessDiagnostics.h>
-#import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
 
 #import "DNSCommon.h"
 #import "mDNSMacOSX.h"
@@ -40,25 +40,45 @@
 
 SOFT_LINK_FRAMEWORK(PrivateFrameworks, WirelessDiagnostics)
 
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
+// AWDServerConnection class
+
+SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection)
+
+#define AWDServerConnectionSoft     getAWDServerConnectionClass()
+
+// Classes for query stats
+
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSStatistics)
+SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
+
+#define AWDMDNSResponderDNSStatisticsSoft       getAWDMDNSResponderDNSStatisticsClass()
+#define AWDDNSDomainStatsSoft                   getAWDDNSDomainStatsClass()
+
+// Classes for resolve stats
+
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats)
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer)
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain)
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname)
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDServerConnection)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
 
-#define AWDDNSDomainStatsSoft                           getAWDDNSDomainStatsClass()
-#define AWDMDNSResponderDNSStatisticsSoft               getAWDMDNSResponderDNSStatisticsClass()
 #define AWDMDNSResponderResolveStatsSoft                getAWDMDNSResponderResolveStatsClass()
-#define AWDMDNSResponderResolveStatsResultSoft          getAWDMDNSResponderResolveStatsResultClass()
 #define AWDMDNSResponderResolveStatsDNSServerSoft       getAWDMDNSResponderResolveStatsDNSServerClass()
 #define AWDMDNSResponderResolveStatsDomainSoft          getAWDMDNSResponderResolveStatsDomainClass()
 #define AWDMDNSResponderResolveStatsHostnameSoft        getAWDMDNSResponderResolveStatsHostnameClass()
-#define AWDServerConnectionSoft                         getAWDServerConnectionClass()
-#define AWDMetricManagerSoft                            getAWDMetricManagerClass()
+#define AWDMDNSResponderResolveStatsResultSoft          getAWDMDNSResponderResolveStatsResultClass()
+
+// Classes for services stats
+
+SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
+
+#define AWDMetricManagerSoft        getAWDMetricManagerClass()
+
+// Classes for DNS message size stats
+
+SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSMessageSizeStats)
+
+#define AWDMDNSResponderDNSMessageSizeStatsSoft     getAWDMDNSResponderDNSMessageSizeStatsClass()
 
 //===========================================================================================================================
 //  Macros
@@ -82,31 +102,26 @@ SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
 //  Data structures
 //===========================================================================================================================
 
-typedef struct
-{
-    const char *            cstr;       // Name of domain as a c-string.
-    const domainname *      name;       // Name of domain as length-prefixed labels.
-    int                     labelCount; // Number of labels in domain name. Used for domain name comparisons.
+// Data structures for query stats.
 
-}   Domain;
+typedef struct QueryStats       QueryStats;
+typedef struct DNSHistSet       DNSHistSet;
+typedef mDNSBool                (*QueryNameTest_f)(const QueryStats *inStats, const domainname *inQueryName);
 
-// Important: Do not add to this list without getting privacy approval beforehand. See <rdar://problem/24155761&26397203>.
-// If you get approval and do add a domain to this list, make sure it passes ValidateDNSStatsDomains() below.
-
-static const Domain     kQueryStatsDomains[] =
+struct QueryStats
 {
-    { ".",              (domainname *)"",                            0 },
-    { "apple.com.",     (domainname *)"\x5" "apple"     "\x3" "com", 2 },
-    { "icloud.com.",    (domainname *)"\x6" "icloud"    "\x3" "com", 2 },
-    { "mzstatic.com.",  (domainname *)"\x8" "mzstatic"  "\x3" "com", 2 },
-    { "google.com.",    (domainname *)"\x6" "google"    "\x3" "com", 2 },
-    { "facebook.com.",  (domainname *)"\x8" "facebook"  "\x3" "com", 2 },
-    { "baidu.com.",     (domainname *)"\x5" "baidu"     "\x3" "com", 2 },
-    { "yahoo.com.",     (domainname *)"\x5" "yahoo"     "\x3" "com", 2 },
-    { "qq.com.",        (domainname *)"\x2" "qq"        "\x3" "com", 2 },
+    QueryStats *        next;           // Pointer to next domain stats in list.
+    const char *        domainStr;      // Domain (see below) as a C string.
+    uint8_t *           domain;         // Domain for which these stats are collected.
+    const char *        altDomainStr;   // Alt domain string to use in the AWD version of the stats instead of domainStr.
+    DNSHistSet *        nonCellular;    // Query stats for queries sent over non-cellular interfaces.
+    DNSHistSet *        cellular;       // Query stats for queries sent over cellular interfaces.
+    QueryNameTest_f     test;           // Function that tests whether a given query's stats belong based on the query name.
+    int                 labelCount;     // Number of labels in domain name. Used for domain name comparisons.
+    mDNSBool            terminal;       // If true and test passes, then no other QueryStats on the list should be visited.
 };
 
-check_compile_time(countof(kQueryStatsDomains) == 9);
+check_compile_time(sizeof(QueryStats) <= 64);
 
 // DNSHist contains the per domain per network type histogram data that goes in a DNSDomainStats protobuf message. See
 // <rdar://problem/23980546> MDNSResponder.proto update.
@@ -164,30 +179,29 @@ check_compile_time(countof_field(DNSHist, unansweredQueryDurationBins) == (count
 check_compile_time(countof_field(DNSHist, responseLatencyBins)         == (countof(kResponseLatencyMsLimits) + 1));
 check_compile_time(countof_field(DNSHist, negResponseLatencyBins)      == (countof(kResponseLatencyMsLimits) + 1));
 
-typedef struct
+struct DNSHistSet
 {
     DNSHist *       histA;      // Histogram data for queries for A resource records.
     DNSHist *       histAAAA;   // Histogram data for queries for AAAA resource records.
+};
 
-}   DNSHistSet;
-
-typedef struct DNSDomainStats       DNSDomainStats;
-struct DNSDomainStats
+typedef struct
 {
-    DNSDomainStats *        next;           // Pointer to next domain stats in list.
-    const Domain *          domain;         // Domain for which these stats are collected.
-    DNSHistSet *            nonCellular;    // Query stats for queries sent over non-cellular interfaces.
-    DNSHistSet *            cellular;       // Query stats for queries sent over cellular interfaces.
-};
+    const char *        domainStr;
+    const char *        altDomainStr;
+    QueryNameTest_f     test;
+    mDNSBool            terminal;
+
+}   QueryStatsArgs;
 
-check_compile_time(sizeof(struct DNSDomainStats) <= 32);
+// Data structures for resolve stats.
 
-static const Domain     kResolveStatsDomains[] =
+static const char * const       kResolveStatsDomains[] =
 {
-    { "apple.com.",     (domainname *)"\x5" "apple"    "\x3" "com", 2 },
-    { "icloud.com.",    (domainname *)"\x6" "icloud"   "\x3" "com", 2 },
-    { "mzstatic.com.",  (domainname *)"\x8" "mzstatic" "\x3" "com", 2 },
-    { "me.com.",        (domainname *)"\x2" "me"       "\x3" "com", 2 },
+    "apple.com.",
+    "icloud.com.",
+    "mzstatic.com.",
+    "me.com."
 };
 
 check_compile_time(countof(kResolveStatsDomains) == 4);
@@ -202,10 +216,14 @@ typedef struct ResolveStatsNegAAAASet       ResolveStatsNegAAAASet;
 struct ResolveStatsDomain
 {
     ResolveStatsDomain *        next;           // Next domain object in list.
+    const char *                domainStr;
+    uint8_t *                   domain;         // Domain for which these stats are collected.
+    int                         labelCount;     // Number of labels in domain name. Used for domain name comparisons.
     ResolveStatsHostname *      hostnameList;   // List of hostname objects in this domain.
-    const Domain *              domainInfo;     // Pointer to domain info.
 };
 
+check_compile_time(sizeof(ResolveStatsDomain) <= 40);
+
 struct ResolveStatsHostname
 {
     ResolveStatsHostname *          next;       // Next hostname object in list.
@@ -290,27 +308,52 @@ typedef struct
 
 }   Response;
 
-//===========================================================================================================================
-//  Globals
-//===========================================================================================================================
+// Data structures for DNS message size stats.
 
-static DNSDomainStats *             gDomainStatsList            = NULL;
-static ResolveStatsDomain *         gResolveStatsList           = NULL;
-static ResolveStatsDNSServer *      gResolveStatsServerList     = NULL;
-static unsigned int                 gResolveStatsNextServerID   = 0;
-static int                          gResolveStatsObjCount       = 0;
-static AWDServerConnection *        gAWDServerConnection        = nil;
+#define kQuerySizeBinWidth      16
+#define kQuerySizeBinMax        512
+#define kQuerySizeBinCount      ((kQuerySizeBinMax / kQuerySizeBinWidth) + 1)
+
+check_compile_time(kQuerySizeBinWidth > 0);
+check_compile_time(kQuerySizeBinCount > 0);
+check_compile_time((kQuerySizeBinMax % kQuerySizeBinWidth) == 0);
+
+#define kResponseSizeBinWidth       16
+#define kResponseSizeBinMax         512
+#define kResponseSizeBinCount       ((kResponseSizeBinMax / kResponseSizeBinWidth) + 1)
+
+check_compile_time(kResponseSizeBinWidth > 0);
+check_compile_time(kResponseSizeBinCount > 0);
+check_compile_time((kResponseSizeBinMax % kResponseSizeBinWidth) == 0);
+
+typedef struct
+{
+    uint16_t    querySizeBins[kQuerySizeBinCount];
+    uint16_t    responseSizeBins[kResponseSizeBinCount];
+
+}   DNSMessageSizeStats;
+
+check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
 
 //===========================================================================================================================
 //  Local Prototypes
 //===========================================================================================================================
 
-mDNSlocal mStatus   DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats);
-mDNSlocal void      DNSDomainStatsFree(DNSDomainStats *inStats);
-mDNSlocal void      DNSDomainStatsFreeList(DNSDomainStats *inList);
-mDNSlocal mStatus   DNSDomainStatsUpdate(DNSDomainStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
+// Query stats
+
+mDNSlocal mStatus       QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats);
+mDNSlocal void          QueryStatsFree(QueryStats *inStats);
+mDNSlocal void          QueryStatsFreeList(QueryStats *inList);
+mDNSlocal mStatus       QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell);
+mDNSlocal const char *  QueryStatsGetDomainString(const QueryStats *inStats);
+mDNSlocal mDNSBool      QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName);
+mDNSlocal mDNSBool      QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName);
+mDNSlocal mDNSBool      QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName);
+mDNSlocal mDNSBool      QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName);
 
-mDNSlocal mStatus   ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain);
+// Resolve stats
+
+mDNSlocal mStatus   ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain);
 mDNSlocal void      ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
 mDNSlocal mStatus   ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
 mDNSlocal mStatus   ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
@@ -334,22 +377,58 @@ mDNSlocal mStatus   ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet
 mDNSlocal void      ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
 mDNSlocal mStatus   ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
 
-mDNSlocal mStatus   CreateDomainStatsList(DNSDomainStats **outList);
+// DNS message size stats
+
+mDNSlocal mStatus   DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
+mDNSlocal void      DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
+
+mDNSlocal mStatus   CreateQueryStatsList(QueryStats **outList);
 mDNSlocal mStatus   CreateResolveStatsList(ResolveStatsDomain **outList);
 mDNSlocal void      FreeResolveStatsList(ResolveStatsDomain *inList);
 mDNSlocal void      FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
 mDNSlocal mStatus   SubmitAWDMetric(UInt32 inMetricID);
 mDNSlocal mStatus   SubmitAWDMetricQueryStats(void);
 mDNSlocal mStatus   SubmitAWDMetricResolveStats(void);
+mDNSlocal mStatus   SubmitAWDMetricDNSMessageSizeStats(void);
 mDNSlocal mStatus   CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
-mDNSlocal mStatus   AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
 mDNSlocal void      LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
 mDNSlocal void      LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
 mDNSlocal void      LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
 mDNSlocal void      LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
-#if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
-mDNSlocal void      ValidateDNSStatsDomains(void);
-#endif
+mDNSlocal void      LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth);
+
+mDNSlocal size_t    CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
+
+//===========================================================================================================================
+//  Globals
+//===========================================================================================================================
+
+static AWDServerConnection *        gAWDServerConnection        = nil;
+static QueryStats *                 gQueryStatsList             = NULL;
+static ResolveStatsDomain *         gResolveStatsList           = NULL;
+static ResolveStatsDNSServer *      gResolveStatsServerList     = NULL;
+static unsigned int                 gResolveStatsNextServerID   = 0;
+static int                          gResolveStatsObjCount       = 0;
+static DNSMessageSizeStats *        gDNSMessageSizeStats        = NULL;
+
+// Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
+
+static const QueryStatsArgs     kQueryStatsArgs[] =
+{
+    { ".",                      NULL,                               QueryStatsDomainTest,           mDNSfalse },
+    { "",                       "alt:*-courier.push.apple.com.",    QueryStatsCourierPushTest,      mDNSfalse },
+    { "apple.com.",             NULL,                               QueryStatsDomainTest,           mDNStrue  },
+    { "gateway.icloud.com.",    "alt:gateway.icloud.com",           QueryStatsHostnameTest,         mDNSfalse },
+    { "",                       "alt:*-content.icloud.com.",        QueryStatsContentiCloudTest,    mDNSfalse },
+    { "icloud.com.",            NULL,                               QueryStatsDomainTest,           mDNStrue  },
+    { "mzstatic.com.",          NULL,                               QueryStatsDomainTest,           mDNStrue  },
+    { "google.com.",            NULL,                               QueryStatsDomainTest,           mDNStrue  },
+    { "baidu.com.",             NULL,                               QueryStatsDomainTest,           mDNStrue  },
+    { "yahoo.com.",             NULL,                               QueryStatsDomainTest,           mDNStrue  },
+    { "qq.com.",                NULL,                               QueryStatsDomainTest,           mDNStrue  }
+};
+
+check_compile_time(countof(kQueryStatsArgs) == 11);
 
 //===========================================================================================================================
 //  MetricsInit
@@ -357,10 +436,6 @@ mDNSlocal void      ValidateDNSStatsDomains(void);
 
 mStatus MetricsInit(void)
 {
-#if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
-    ValidateDNSStatsDomains();
-#endif
-
     @autoreleasepool
     {
         gAWDServerConnection = [[AWDServerConnectionSoft alloc]
@@ -389,6 +464,13 @@ mStatus MetricsInit(void)
                     SubmitAWDMetric(inMetricID);
                 }
                 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ServicesStats];
+
+            [gAWDServerConnection
+                registerQueriableMetricCallback: ^(UInt32 inMetricID)
+                {
+                    SubmitAWDMetric(inMetricID);
+                }
+                forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSMessageSizeStats];
         }
         else
         {
@@ -398,56 +480,33 @@ mStatus MetricsInit(void)
 
     if( gAWDServerConnection )
     {
-        CreateDomainStatsList(&gDomainStatsList);
+        CreateQueryStatsList(&gQueryStatsList);
         CreateResolveStatsList(&gResolveStatsList);
+        DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
     }
 
     return (mStatus_NoError);
 }
 
 //===========================================================================================================================
-//  MetricsUpdateUDNSQueryStats
+//  MetricsUpdateDNSQueryStats
 //===========================================================================================================================
 
-mDNSexport void MetricsUpdateUDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
+mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
 {
-    DNSDomainStats *        stats;
-    int                     queryLabelCount;
-    const domainname *      queryParentDomain;
-    mDNSBool                isQueryInDomain;
-    int                     skipCount;
-    int                     skipCountLast = -1;
+    QueryStats *        stats;
+    mDNSBool            match;
 
     require_quiet(gAWDServerConnection, exit);
     require_quiet((inType == kDNSType_A) || (inType == kDNSType_AAAA), exit);
 
-    queryLabelCount = CountLabels(inQueryName);
-
-    for (stats = gDomainStatsList; stats; stats = stats->next)
+    for (stats = gQueryStatsList; stats; stats = stats->next)
     {
-        isQueryInDomain = mDNSfalse;
-        if (strcmp(stats->domain->cstr, ".") == 0)
-        {
-            // All queries are in the root domain.
-            isQueryInDomain = mDNStrue;
-        }
-        else
-        {
-            skipCount = queryLabelCount - stats->domain->labelCount;
-            if (skipCount >= 0)
-            {
-                if (skipCount != skipCountLast)
-                {
-                    queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
-                    skipCountLast = skipCount;
-                }
-                isQueryInDomain = SameDomainName(queryParentDomain, stats->domain->name);
-            }
-        }
-
-        if (isQueryInDomain)
+        match = stats->test(stats, inQueryName);
+        if (match)
         {
-            DNSDomainStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
+            QueryStatsUpdate(stats, inType, inRR, inSendCount, inLatencyMs, inForCell);
+            if (stats->terminal) break;
         }
     }
 
@@ -456,12 +515,12 @@ exit:
 }
 
 //===========================================================================================================================
-//  MetricsUpdateUDNSResolveStats
+//  MetricsUpdateDNSResolveStats
 //===========================================================================================================================
 
-mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
+mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
 {
-    ResolveStatsDomain *        domain;
+    ResolveStatsDomain *        domainStats;
     domainname                  hostname;
     size_t                      hostnameLen;
     mDNSBool                    isQueryInDomain;
@@ -477,10 +536,10 @@ mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, con
 
     queryLabelCount = CountLabels(inQueryName);
 
-    for (domain = gResolveStatsList; domain; domain = domain->next)
+    for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
     {
         isQueryInDomain = mDNSfalse;
-        skipCount = queryLabelCount - domain->domainInfo->labelCount;
+        skipCount = queryLabelCount - domainStats->labelCount;
         if (skipCount >= 0)
         {
             if (skipCount != skipCountLast)
@@ -488,7 +547,7 @@ mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, con
                 queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
                 skipCountLast = skipCount;
             }
-            isQueryInDomain = SameDomainName(queryParentDomain, domain->domainInfo->name);
+            isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
         }
         if (!isQueryInDomain) continue;
 
@@ -508,7 +567,7 @@ mDNSexport void MetricsUpdateUDNSResolveStats(const domainname *inQueryName, con
             response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
             response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
         }
-        ResolveStatsDomainUpdate(domain, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
+        ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
     }
 
 exit:
@@ -516,12 +575,44 @@ exit:
 }
 
 //===========================================================================================================================
+//  MetricsUpdateDNSQuerySize
+//===========================================================================================================================
+
+mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
+
+mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
+{
+    if (!gDNSMessageSizeStats) return;
+    UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
+}
+
+mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
+{
+    size_t      i;
+
+    if (inSize == 0) return;
+    i = (inSize - 1) / inBinWidth;
+    if (i >= inBinCount) i = inBinCount - 1;
+    increment_saturate(inBins[i], UINT16_MAX);
+}
+
+//===========================================================================================================================
+//  MetricsUpdateDNSResponseSize
+//===========================================================================================================================
+
+mDNSexport void MetricsUpdateDNSResponseSize(mDNSu32 inSize)
+{
+    if (!gDNSMessageSizeStats) return;
+    UpdateMessageSizeCounts(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth, inSize);
+}
+
+//===========================================================================================================================
 //  LogMetrics
 //===========================================================================================================================
 
 mDNSexport void LogMetrics(void)
 {
-    DNSDomainStats *                    stats;
+    QueryStats *                        stats;
     const ResolveStatsDomain *          domain;
     const ResolveStatsHostname *        hostname;
     const ResolveStatsDNSServer *       server;
@@ -538,15 +629,15 @@ mDNSexport void LogMetrics(void)
     LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
     LogMsgNoIdent("---- DNS query stats by domain -----");
 
-    for (stats = gDomainStatsList; stats; stats = stats->next)
+    for (stats = gQueryStatsList; stats; stats = stats->next)
     {
         if (!stats->nonCellular && !stats->cellular)
         {
-            LogMsgNoIdent("No data for %s", stats->domain->cstr);
+            LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
             continue;
         }
-        if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, stats->domain->cstr, mDNSfalse);
-        if (stats->cellular)    LogDNSHistSet(stats->cellular,    stats->domain->cstr, mDNStrue);
+        if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
+        if (stats->cellular)    LogDNSHistSet(stats->cellular,    QueryStatsGetDomainString(stats), mDNStrue);
     }
 
     LogMsgNoIdent("---- DNS resolve stats by domain -----");
@@ -565,7 +656,7 @@ mDNSexport void LogMetrics(void)
         for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
         hostnameObjCount += hostnameCount;
 
-        LogMsgNoIdent("%##s (%d hostname%s)", domain->domainInfo->name, hostnameCount, (hostnameCount == 1) ? "" : "s");
+        LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
 
         for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
         {
@@ -622,39 +713,96 @@ mDNSexport void LogMetrics(void)
     }
     LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
         serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
-    
+
     LogMsgNoIdent("---- Num of Services Registered -----");
     LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
                   curr_num_regservices, max_num_regservices);
+
+    if (gDNSMessageSizeStats)
+    {
+        LogMsgNoIdent("---- DNS query size stats ---");
+        LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
+
+        LogMsgNoIdent("-- DNS response size stats --");
+        LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
+    }
+    else
+    {
+        LogMsgNoIdent("No DNS message size stats.");
+    }
 }
 
 //===========================================================================================================================
-//  DNSDomainStatsCreate
+//  QueryStatsCreate
 //===========================================================================================================================
 
-mDNSlocal mStatus DNSDomainStatsCreate(const Domain *inDomain, DNSDomainStats **outStats)
+mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName);
+
+mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats)
 {
-    mStatus                 err;
-    DNSDomainStats *        obj;
+    mStatus             err;
+    QueryStats *        obj;
 
-    obj = (DNSDomainStats *)calloc(1, sizeof(*obj));
+    obj = (QueryStats *)calloc(1, sizeof(*obj));
     require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
 
-    obj->domain = inDomain;
+    obj->domainStr = inDomainStr;
+    err = StringToDomainName(obj->domainStr, &obj->domain);
+    require_noerr_quiet(err, exit);
+
+    obj->altDomainStr   = inAltDomainStr;
+    obj->test           = inTest;
+    obj->labelCount     = CountLabels((const domainname *)obj->domain);
+    obj->terminal       = inTerminal;
 
     *outStats = obj;
+    obj = NULL;
     err = mStatus_NoError;
 
 exit:
+    if (obj) QueryStatsFree(obj);
     return (err);
 }
 
+mDNSlocal mStatus StringToDomainName(const char *inString, uint8_t **outDomainName)
+{
+    mStatus             err;
+    uint8_t *           domainPtr = NULL;
+    size_t              domainLen;
+    const mDNSu8 *      ptr;
+    domainname          domain;
+
+    if (strcmp(inString, ".") == 0)
+    {
+        domain.c[0] = 0;
+    }
+    else
+    {
+        ptr = MakeDomainNameFromDNSNameString(&domain, inString);
+        require_action_quiet(ptr, exit, err = mStatus_BadParamErr);
+    }
+    domainLen = DomainNameLength(&domain);
+
+    domainPtr = (uint8_t *)malloc(domainLen);
+    require_action_quiet(domainPtr, exit, err = mStatus_NoMemoryErr);
+
+    memcpy(domainPtr, domain.c, domainLen);
+
+    *outDomainName = domainPtr;
+    domainPtr = NULL;
+    err = mStatus_NoError;
+
+exit:
+    return(err);
+}
+
 //===========================================================================================================================
-//  DNSDomainStatsFree
+//  QueryStatsFree
 //===========================================================================================================================
 
-mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats)
+mDNSlocal void QueryStatsFree(QueryStats *inStats)
 {
+    ForgetMem(&inStats->domain);
     if (inStats->nonCellular)
     {
         ForgetMem(&inStats->nonCellular->histA);
@@ -673,25 +821,25 @@ mDNSlocal void DNSDomainStatsFree(DNSDomainStats *inStats)
 }
 
 //===========================================================================================================================
-//  DNSDomainStatsFreeList
+//  QueryStatsFreeList
 //===========================================================================================================================
 
-mDNSlocal void DNSDomainStatsFreeList(DNSDomainStats *inList)
+mDNSlocal void QueryStatsFreeList(QueryStats *inList)
 {
-    DNSDomainStats *        stats;
+    QueryStats *        stats;
 
     while ((stats = inList) != NULL)
     {
         inList = stats->next;
-        DNSDomainStatsFree(stats);
+        QueryStatsFree(stats);
     }
 }
 
 //===========================================================================================================================
-//  DNSDomainStatsUpdate
+//  QueryStatsUpdate
 //===========================================================================================================================
 
-mDNSlocal mStatus DNSDomainStatsUpdate(DNSDomainStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
+mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, mDNSu32 inLatencyMs, mDNSBool inForCell)
 {
     mStatus             err;
     DNSHistSet *        set;
@@ -751,10 +899,141 @@ exit:
 }
 
 //===========================================================================================================================
+//  QueryStatsGetDomainString
+//===========================================================================================================================
+
+mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats)
+{
+    return (inStats->altDomainStr ? inStats->altDomainStr : inStats->domainStr);
+}
+
+//===========================================================================================================================
+//  QueryStatsDomainTest
+//===========================================================================================================================
+
+mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName)
+{
+    const domainname *      parentDomain;
+    int                     labelCount;
+
+    if (inStats->domain[0] == 0) return (mDNStrue);
+
+    labelCount = CountLabels(inQueryName);
+    if (labelCount < inStats->labelCount) return (mDNSfalse);
+
+    parentDomain = SkipLeadingLabels(inQueryName, labelCount - inStats->labelCount);
+    return (SameDomainName(parentDomain, (const domainname *)inStats->domain));
+}
+
+//===========================================================================================================================
+//  QueryStatsHostnameTest
+//===========================================================================================================================
+
+mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName)
+{
+    return (SameDomainName(inQueryName, (const domainname *)inStats->domain));
+}
+
+//===========================================================================================================================
+//  QueryStatsContentiCloudTest
+//===========================================================================================================================
+
+mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen);
+
+#define kContentSuffixStr       "-content"
+
+mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName)
+{
+    const mDNSu8 * const    firstLabel = inQueryName->c;
+    const uint8_t *         suffix;
+    const domainname *      parentDomain;
+    int                     labelCount;
+
+    (void) inStats; // Unused.
+
+    labelCount = CountLabels(inQueryName);
+    if (labelCount != 3) return (mDNSfalse);
+
+    suffix = LocateLabelSuffix(firstLabel, (const uint8_t *)kContentSuffixStr, sizeof_string(kContentSuffixStr));
+    if (suffix && (suffix > &firstLabel[1]))
+    {
+        parentDomain = SkipLeadingLabels(inQueryName, 1);
+        if (SameDomainName(parentDomain, (const domainname *)"\x6" "icloud" "\x3" "com"))
+        {
+            return (mDNStrue);
+        }
+    }
+
+    return (mDNSfalse);
+}
+
+mDNSlocal const uint8_t *LocateLabelSuffix(const uint8_t *inLabel, const uint8_t *inSuffixPtr, size_t inSuffixLen)
+{
+    const uint8_t *     ptr;
+    const uint8_t *     lp;
+    const uint8_t *     sp;
+    size_t              len;
+    const size_t        labelLen = inLabel[0];
+
+    if (labelLen < inSuffixLen) return (NULL);
+
+    ptr = &inLabel[1 + labelLen - inSuffixLen];
+    lp  = ptr;
+    sp  = inSuffixPtr;
+    for (len = inSuffixLen; len > 0; --len)
+    {
+        if (tolower(*lp) != tolower(*sp)) return (NULL);
+        ++lp;
+        ++sp;
+    }
+
+    return (ptr);
+}
+
+//===========================================================================================================================
+//  QueryStatsCourierPushTest
+//===========================================================================================================================
+
+#define kCourierSuffixStr       "-courier"
+
+mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName)
+{
+    const mDNSu8 * const    firstLabel = inQueryName->c;
+    const uint8_t *         suffix;
+    const uint8_t *         ptr;
+    const domainname *      parentDomain;
+    int                     labelCount;
+
+    (void) inStats; // Unused.
+
+    labelCount = CountLabels(inQueryName);
+    if (labelCount != 4) return (mDNSfalse);
+
+    suffix = LocateLabelSuffix(firstLabel, (const mDNSu8 *)kCourierSuffixStr, sizeof_string(kCourierSuffixStr));
+    if (suffix && (suffix > &firstLabel[1]))
+    {
+        for (ptr = &firstLabel[1]; ptr < suffix; ++ptr)
+        {
+            if (!isdigit(*ptr)) break;
+        }
+        if (ptr == suffix)
+        {
+            parentDomain = SkipLeadingLabels(inQueryName, 1);
+            if (SameDomainName(parentDomain, (const domainname *)"\x4" "push" "\x5" "apple" "\x3" "com"))
+            {
+                return (mDNStrue);
+            }
+        }
+    }
+
+    return (mDNSfalse);
+}
+
+//===========================================================================================================================
 //  ResolveStatsDomainCreate
 //===========================================================================================================================
 
-mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsDomain **outDomain)
+mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
 {
     mStatus                     err;
     ResolveStatsDomain *        obj;
@@ -762,12 +1041,18 @@ mDNSlocal mStatus ResolveStatsDomainCreate(const Domain *inDomain, ResolveStatsD
     obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
     require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
 
-    obj->domainInfo = inDomain;
+    obj->domainStr = inDomainStr;
+    err = StringToDomainName(obj->domainStr, &obj->domain);
+    require_noerr_quiet(err, exit);
+
+    obj->labelCount = CountLabels((const domainname *)obj->domain);
 
     *outDomain = obj;
+    obj = NULL;
     err = mStatus_NoError;
 
 exit:
+    if (obj) ResolveStatsDomainFree(obj);
     return (err);
 }
 
@@ -779,6 +1064,7 @@ mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
 {
     ResolveStatsHostname *      hostname;
 
+    ForgetMem(&inDomain->domain);
     while ((hostname = inDomain->hostnameList) != NULL)
     {
         inDomain->hostnameList = hostname->next;
@@ -862,7 +1148,7 @@ mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *i
     domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
     require_action_quiet(domain, exit, err = mStatus_UnknownErr);
 
-    name = [[NSString alloc] initWithUTF8String:inDomain->domainInfo->cstr];
+    name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
     require_action_quiet(name, exit, err = mStatus_UnknownErr);
 
     domain.name = name;
@@ -1357,7 +1643,7 @@ mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool
         require_noerr_quiet(err, exit);
         gResolveStatsObjCount++;
 
-        server->id   = gResolveStatsNextServerID++;
+        server->id   = (uint8_t)gResolveStatsNextServerID++;
         server->next = gResolveStatsServerList;
         gResolveStatsServerList = server;
     }
@@ -1376,21 +1662,50 @@ exit:
 }
 
 //===========================================================================================================================
-//  CreateDomainStatsList
+//  DNSMessageSizeStatsCreate
 //===========================================================================================================================
 
-mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList)
+mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
 {
-    mStatus                 err;
-    int                     i;
-    DNSDomainStats *        stats;
-    DNSDomainStats **       p;
-    DNSDomainStats *        list = NULL;
+    mStatus                     err;
+    DNSMessageSizeStats *       stats;
+
+    stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
+    require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
+
+    *outStats = stats;
+    err = mStatus_NoError;
+
+exit:
+    return (err);
+}
+
+//===========================================================================================================================
+//  DNSMessageSizeStatsFree
+//===========================================================================================================================
+
+mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
+{
+    free(inStats);
+}
+
+//===========================================================================================================================
+//  CreateQueryStatsList
+//===========================================================================================================================
+
+mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
+{
+    mStatus                             err;
+    QueryStats **                       p;
+    QueryStats *                        stats;
+    const QueryStatsArgs *              args;
+    const QueryStatsArgs * const        end     = kQueryStatsArgs + countof(kQueryStatsArgs);
+    QueryStats *                        list    = NULL;
 
     p = &list;
-    for (i = 0; i < (int)countof(kQueryStatsDomains); ++i)
+    for (args = kQueryStatsArgs; args < end; ++args)
     {
-        err = DNSDomainStatsCreate(&kQueryStatsDomains[i], &stats);
+        err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
         require_noerr_quiet(err, exit);
 
         *p = stats;
@@ -1399,9 +1714,10 @@ mDNSlocal mStatus CreateDomainStatsList(DNSDomainStats **outList)
 
     *outList = list;
     list = NULL;
+    err = mStatus_NoError;
 
 exit:
-    DNSDomainStatsFreeList(list);
+    QueryStatsFreeList(list);
     return (err);
 }
 
@@ -1412,15 +1728,15 @@ exit:
 mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
 {
     mStatus                     err;
-    int                         i;
+    unsigned int                i;
     ResolveStatsDomain *        domain;
     ResolveStatsDomain **       p;
     ResolveStatsDomain *        list = NULL;
 
     p = &list;
-    for (i = 0; i < (int)countof(kResolveStatsDomains); ++i)
+    for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
     {
-        err = ResolveStatsDomainCreate(&kResolveStatsDomains[i], &domain);
+        err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
         require_noerr_quiet(err, exit);
 
         *p = domain;
@@ -1429,6 +1745,7 @@ mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
 
     *outList = list;
     list = NULL;
+    err = mStatus_NoError;
 
 exit:
     FreeResolveStatsList(list);
@@ -1491,7 +1808,11 @@ mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
             KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
             err = mStatus_NoError;
             break;
-            
+
+        case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
+            err = SubmitAWDMetricDNSMessageSizeStats();
+            break;
+
         default:
             err = mStatus_UnsupportedErr;
             break;
@@ -1505,22 +1826,25 @@ mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
 //  SubmitAWDMetricQueryStats
 //===========================================================================================================================
 
+mDNSlocal mStatus   AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
+mDNSlocal mStatus   AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
+
 mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
 {
     mStatus                             err;
     BOOL                                success;
-    DNSDomainStats *                    stats;
-    DNSDomainStats *                    newDomainStatsList;
-    DNSDomainStats *                    domainStatsList = NULL;
-    AWDMetricContainer *                container       = nil;
-    AWDMDNSResponderDNSStatistics *     metric          = nil;
+    QueryStats *                        stats;
+    QueryStats *                        statsList;
+    QueryStats *                        newStatsList;
+    AWDMetricContainer *                container   = nil;
+    AWDMDNSResponderDNSStatistics *     metric      = nil;
 
-    err = CreateDomainStatsList(&newDomainStatsList);
-    require_noerr_quiet(err, exit);
+    newStatsList = NULL;
+    CreateQueryStatsList(&newStatsList);
 
     KQueueLock();
-    domainStatsList = gDomainStatsList;
-    gDomainStatsList = newDomainStatsList;
+    statsList       = gQueryStatsList;
+    gQueryStatsList = newStatsList;
     KQueueUnlock("SubmitAWDMetricQueryStats");
 
     container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
@@ -1529,31 +1853,71 @@ mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
     metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
     require_action_quiet(metric, exit, err = mStatus_UnknownErr);
 
-    while ((stats = domainStatsList) != NULL)
+    while ((stats = statsList) != NULL)
     {
-        if (stats->nonCellular)
-        {
-            err = AddAWDDNSDomainStats(metric, stats->nonCellular, stats->domain->cstr, mDNSfalse);
-            require_noerr_quiet(err, exit);
-        }
-        if (stats->cellular)
-        {
-            err = AddAWDDNSDomainStats(metric, stats->cellular, stats->domain->cstr, mDNStrue);
-            require_noerr_quiet(err, exit);
-        }
-        domainStatsList = stats->next;
-        DNSDomainStatsFree(stats);
+        err = AddQueryStats(metric, stats);
+        require_noerr_quiet(err, exit);
+
+        statsList = stats->next;
+        QueryStatsFree(stats);
     }
 
     container.metric = metric;
     success = [gAWDServerConnection submitMetric:container];
-    LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed" );
+    LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
     err = success ? mStatus_NoError : mStatus_UnknownErr;
 
 exit:
     [metric release];
     [container release];
-    DNSDomainStatsFreeList(domainStatsList);
+    QueryStatsFreeList(statsList);
+    return (err);
+}
+
+mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
+{
+    mStatus     err;
+
+    if (inStats->nonCellular)
+    {
+        err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
+        require_noerr_quiet(err, exit);
+    }
+    if (inStats->cellular)
+    {
+        err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
+        require_noerr_quiet(err, exit);
+    }
+    err = mStatus_NoError;
+
+exit:
+    return (err);
+}
+
+mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
+{
+    mStatus                 err;
+    AWDDNSDomainStats *     awdStats;
+
+    if (inSet->histA)
+    {
+        err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
+        require_noerr_quiet(err, exit);
+
+        [inMetric addStats:awdStats];
+        [awdStats release];
+    }
+    if (inSet->histAAAA)
+    {
+        err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
+        require_noerr_quiet(err, exit);
+
+        [inMetric addStats:awdStats];
+        [awdStats release];
+    }
+    err = mStatus_NoError;
+
+exit:
     return (err);
 }
 
@@ -1619,7 +1983,7 @@ mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
 
     container.metric = metric;
     success = [gAWDServerConnection submitMetric:container];
-    LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed" );
+    LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed");
     err = success ? mStatus_NoError : mStatus_UnknownErr;
 
 exit:
@@ -1631,6 +1995,61 @@ exit:
 }
 
 //===========================================================================================================================
+//  SubmitAWDMetricDNSMessageSizeStats
+//===========================================================================================================================
+
+mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
+{
+    mStatus                                     err;
+    DNSMessageSizeStats *                       stats;
+    DNSMessageSizeStats *                       newStats;
+    AWDMetricContainer *                        container;
+    AWDMDNSResponderDNSMessageSizeStats *       metric = nil;
+    BOOL                                        success;
+
+    newStats = NULL;
+    DNSMessageSizeStatsCreate(&newStats);
+
+    KQueueLock();
+    stats                   = gDNSMessageSizeStats;
+    gDNSMessageSizeStats    = newStats;
+    KQueueUnlock("SubmitAWDMetricDNSMessageSizeStats");
+
+    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSMessageSizeStats];
+    require_action_quiet(container, exit, err = mStatus_UnknownErr);
+
+    metric = [[AWDMDNSResponderDNSMessageSizeStatsSoft alloc] init];
+    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
+
+    if (stats)
+    {
+        size_t          binCount;
+        uint32_t        bins[Max(kQuerySizeBinCount, kResponseSizeBinCount)];
+
+        // Set query size counts.
+
+        binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
+        [metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
+
+        // Set response size counts.
+
+        binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
+        [metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
+    }
+
+    container.metric = metric;
+    success = [gAWDServerConnection submitMetric:container];
+    LogMsg("SubmitAWDMetricDNSMessageSizeStats: metric submission %s.", success ? "succeeded" : "failed");
+    err = success ? mStatus_NoError : mStatus_UnknownErr;
+
+exit:
+    [metric release];
+    [container release];
+    if (stats) DNSMessageSizeStatsFree(stats);
+    return (err);
+}
+
+//===========================================================================================================================
 //  CreateAWDDNSDomainStats
 //===========================================================================================================================
 
@@ -1639,12 +2058,9 @@ mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain,
     mStatus                 err;
     AWDDNSDomainStats *     awdStats    = nil;
     NSString *              domain      = nil;
+    size_t                  binCount;
     uint32_t                sendCountBins[kQueryStatsSendCountBinCount];
     uint32_t                latencyBins[kQueryStatsLatencyBinCount];
-    int                     i;
-    unsigned int            totalAnswered;
-    unsigned int            totalNegAnswered;
-    unsigned int            totalUnanswered;
 
     awdStats = [[AWDDNSDomainStatsSoft alloc] init];
     require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
@@ -1656,55 +2072,40 @@ mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain,
     awdStats.networkType = inForCell ? AWDDNSDomainStats_NetworkType_Cellular : AWDDNSDomainStats_NetworkType_NonCellular;
     awdStats.recordType  = inType;
 
-    totalAnswered = 0;
-    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
-    {
-        sendCountBins[i] = inHist->answeredQuerySendCountBins[i];
-        totalAnswered   += inHist->answeredQuerySendCountBins[i];
-    }
-    [awdStats setAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
+    // Positively answered query send counts
 
-    totalNegAnswered = 0;
-    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
-    {
-        sendCountBins[i]  = inHist->negAnsweredQuerySendCountBins[i];
-        totalNegAnswered += inHist->negAnsweredQuerySendCountBins[i];
-    }
-    [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
+    binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
+    [awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
 
-    totalUnanswered = 0;
-    for (i = 0; i < kQueryStatsSendCountBinCount; ++i)
-    {
-        sendCountBins[i] = inHist->unansweredQuerySendCountBins[i];
-        totalUnanswered += inHist->unansweredQuerySendCountBins[i];
-    }
-    [awdStats setUnansweredQuerySendCounts:sendCountBins count:kQueryStatsSendCountBinCount];
+    // 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
+    // was sent out on the wire. In that case, include the associated latency bins as well.
 
-    if (totalAnswered > inHist->answeredQuerySendCountBins[0])
+    if (binCount > 1)
     {
-        for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
-        {
-            latencyBins[i] = inHist->responseLatencyBins[i];
-        }
-        [awdStats setResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
+        binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
+        [awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
     }
 
-    if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
+    // Negatively answered query send counts
+
+    binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
+    [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
+
+    if (binCount > 1)
     {
-        for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
-        {
-            latencyBins[i] = inHist->negResponseLatencyBins[i];
-        }
-        [awdStats setNegResponseLatencyMs:latencyBins count:kQueryStatsLatencyBinCount];
+        binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
+        [awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
     }
 
-    if (totalUnanswered > 0)
+    // Unanswered query send counts
+
+    binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
+    [awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
+
+    if (binCount > 1)
     {
-        for (i = 0; i < kQueryStatsLatencyBinCount; ++i)
-        {
-            latencyBins[i] = inHist->unansweredQueryDurationBins[i];
-        }
-        [awdStats setUnansweredQueryDurationMs:latencyBins count:kQueryStatsLatencyBinCount];
+        binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
+        [awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
     }
 
     *outStats = awdStats;
@@ -1718,37 +2119,6 @@ exit:
 }
 
 //===========================================================================================================================
-//  AddAWDDNSDomainStats
-//===========================================================================================================================
-
-mDNSlocal mStatus AddAWDDNSDomainStats(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
-{
-    mStatus                 err;
-    AWDDNSDomainStats *     awdStats;
-
-    if (inSet->histA)
-    {
-        err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
-        require_noerr_quiet(err, exit);
-
-        [inMetric addStats:awdStats];
-        [awdStats release];
-    }
-    if (inSet->histAAAA)
-    {
-        err = CreateAWDDNSDomainStats(inSet->histAAAA, inDomain, inForCell, AWDDNSDomainStats_RecordType_AAAA, &awdStats);
-        require_noerr_quiet(err, exit);
-
-        [inMetric addStats:awdStats];
-        [awdStats release];
-    }
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
 //  LogDNSHistSet
 //===========================================================================================================================
 
@@ -1762,7 +2132,7 @@ mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNS
 //  LogDNSHist
 //===========================================================================================================================
 
-#define Percent(N, D)       ((N) * 100) / (D), (((N) * 10000) / (D)) % 100
+#define Percent(N, D)       (((N) * 100) / (D)), ((((N) * 10000) / (D)) % 100)
 #define PercentFmt          "%3u.%02u"
 #define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
     LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
@@ -1903,63 +2273,72 @@ mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLaten
 }
 
 //===========================================================================================================================
-//  ValidateDNSStatsDomains
+//  LogDNSMessageSizeStats
 //===========================================================================================================================
 
-#if (METRICS_VALIDATE_DNS_STATS_DOMAINS)
-#warning "Do not include ValidateDNSStatsDomains() in customer release!"
-mDNSlocal void ValidateDNSStatsDomains(void)
+mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
 {
-    int                 i;
-    const Domain *      domain;
-    mDNSu8 *            ptr;
-    domainname          domainNameExpected;
-    int                 labelCountExpected;
-    mDNSBool            domainNamesEqual;
-    mDNSBool            failed = mDNSfalse;
+    size_t          i;
+    uint32_t        total;
 
-    for (i = 0; i < countof(kQueryStatsDomains); ++i)
+    total = 0;
+    for (i = 0; i < inBinCount; ++i)
     {
-        domain = &kQueryStatsDomains[i];
+        total += inBins[i];
+    }
 
-        if (strcmp(domain->cstr, ".") == 0)
-        {
-            domainNameExpected.c[0] = 0;
-        }
-        else
-        {
-            ptr = MakeDomainNameFromDNSNameString(&domainNameExpected, domain->cstr);
-            if (!ptr)
-            {
-                LogMsg("ValidateDNSStatsDomains: Failed to make domain name for \"%s\".", domain->cstr);
-                failed = mDNStrue;
-                goto exit;
-            }
-        }
+    if (total > 0)
+    {
+        uint32_t            accumulator;
+        unsigned int        lower, upper;
+        char                label[16];
 
-        domainNamesEqual = SameDomainName(domain->name, &domainNameExpected);
-        labelCountExpected = CountLabels(&domainNameExpected);
-        if (domainNamesEqual && (domain->labelCount == labelCountExpected))
-        {
-            LogMsg("ValidateDNSStatsDomains: \"%s\" passed.", domain->cstr);
-        }
-        else
+        accumulator = 0;
+        upper       = 0;
+        for (i = 0; i < inBinCount; ++i)
         {
-            if (!domainNamesEqual)
+            accumulator += inBins[i];
+            lower = upper + 1;
+            if (i < (inBinCount - 1))
             {
-                LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect domain name.", domain->cstr);
+                upper += inBinWidth;
+                snprintf(label, sizeof(label), "%3u - %-3u", lower, upper);
             }
-            if (domain->labelCount != labelCountExpected)
+            else
             {
-                LogMsg("ValidateDNSStatsDomains: \"%s\" failed: incorrect label count. Actual %d, expected %d.",
-                    domain->cstr, domain->labelCount, labelCountExpected);
+                snprintf(label, sizeof(label), "%3u+     ", lower);
             }
-            failed = mDNStrue;
+            LogStat(label, inBins[i], accumulator, total);
+            if (accumulator == total) break;
         }
     }
+    else
+    {
+        LogMsgNoIdent("No data.");
+    }
+}
 
-exit:
-    if (failed) abort();
+//===========================================================================================================================
+//  CopyHistogramBins
+//
+//  Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
+//  bin and all bins with non-zero values.
+//===========================================================================================================================
+
+mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
+{
+    size_t      i;
+    size_t      minCount;
+
+    if (inBinCount == 0) return (0);
+
+    minCount = 1;
+    for (i = 0; i < inBinCount; ++i)
+    {
+        inDstBins[i] = inSrcBins[i];
+        if (inDstBins[i] > 0) minCount = i + 1;
+    }
+
+    return (minCount);
 }
-#endif
-#endif // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_IOS
diff --git a/mDNSResponder/mDNSMacOSX/daemon.c b/mDNSResponder/mDNSMacOSX/daemon.c
index 5dece76..fa192b6 100644
--- a/mDNSResponder/mDNSMacOSX/daemon.c
+++ b/mDNSResponder/mDNSMacOSX/daemon.c
@@ -45,7 +45,7 @@
 #include "xpc_services.h"           // Interface to XPC services
 #include "helper.h"
 
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
 #include "Metrics.h"
 #endif
 
@@ -558,7 +558,7 @@ mDNSexport void INFOCallback(void)
         LogMsgNoIdent("%##s", mDNSStorage.FQDN.c);
     }
 
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
     LogMetrics();
 #endif
     LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
@@ -1360,9 +1360,10 @@ mDNSlocal void * KQueueLoop(void *m_param)
         {
             if (events_found > kEventsToReadAtOnce || (events_found < 0 && errno != EINTR))
             {
+                const int kevent_errno = errno;
                 // Not sure what to do here, our kqueue has failed us - this isn't ideal
-                LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno, strerror(errno));
-                exit(errno);
+                LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", kevent_errno, strerror(kevent_errno));
+                exit(kevent_errno);
             }
 
             numevents += events_found;
@@ -1390,7 +1391,7 @@ mDNSlocal size_t LaunchdCheckin(void)
 {
     // Ask launchd for our socket
     int result = launch_activate_socket("Listeners", &launchd_fds, &launchd_fds_count);
-    if (result != 0) { LogMsg("launch_activate_socket() failed errno %d (%s)", errno, strerror(errno)); }
+    if (result != 0) { LogMsg("launch_activate_socket() failed error %d (%s)", result, strerror(result)); }
     return launchd_fds_count;
 }
 
@@ -1620,14 +1621,26 @@ mDNSexport int main(int argc, char **argv)
 
     // Create the kqueue, mutex and thread to support KQSockets
     KQueueFD = kqueue();
-    if (KQueueFD == -1) { LogMsg("kqueue() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+    if (KQueueFD == -1)
+    {
+        const int kqueue_errno = errno;
+        LogMsg("kqueue() failed errno %d (%s)", kqueue_errno, strerror(kqueue_errno));
+        status = kqueue_errno;
+        goto exit;
+    }
 
     i = pthread_mutex_init(&PlatformStorage.BigMutex, NULL);
-    if (i == -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+    if (i != 0) { LogMsg("pthread_mutex_init() failed error %d (%s)", i, strerror(i)); status = i; goto exit; }
 
     int fdpair[2] = {0, 0};
     i = socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair);
-    if (i == -1) { LogMsg("socketpair() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+    if (i == -1)
+    {
+        const int socketpair_errno = errno;
+        LogMsg("socketpair() failed errno %d (%s)", socketpair_errno, strerror(socketpair_errno));
+        status = socketpair_errno;
+        goto exit;
+    }
 
     // Socket pair returned us two identical sockets connected to each other
     // We will use the first socket to send the second socket. The second socket
@@ -1644,7 +1657,7 @@ mDNSexport int main(int argc, char **argv)
 #endif
     SandboxProcess();
 
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
     status = MetricsInit();
     if (status) { LogMsg("Daemon start: MetricsInit failed (%d)", status); }
 #endif
@@ -1666,7 +1679,7 @@ mDNSexport int main(int argc, char **argv)
       // Start the kqueue thread
     pthread_t KQueueThread;
     i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage);
-    if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+    if (i != 0) { LogMsg("pthread_create() failed error %d (%s)", i, strerror(i)); status = i; goto exit; }
     if (status == 0)
     {
         CFRunLoopRun();
diff --git a/mDNSResponder/mDNSMacOSX/helper.c b/mDNSResponder/mDNSMacOSX/helper.c
index f5b4f3b..dc90b35 100644
--- a/mDNSResponder/mDNSMacOSX/helper.c
+++ b/mDNSResponder/mDNSMacOSX/helper.c
@@ -1456,15 +1456,17 @@ void RetrieveTCPInfo(int family, const v6addr_t laddr, uint16_t lport, const v6a
     sz = sizeof(mib)/sizeof(mib[0]);
     if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
     {
-        os_log(log_handle, "RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno, strerror(errno));
-        *err = errno;
+        const int sysctl_errno = errno;
+        os_log(log_handle, "RetrieveTCPInfo: sysctlnametomib failed %d, %s", sysctl_errno, strerror(sysctl_errno));
+        *err = sysctl_errno;
     }
     miblen = (unsigned int)sz;
     len    = sizeof(struct tcp_info);
     if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
     {
-        os_log(log_handle, "RetrieveTCPInfo: sysctl failed %d, %s", errno, strerror(errno));
-        *err = errno;
+        const int sysctl_errno = errno;
+        os_log(log_handle, "RetrieveTCPInfo: sysctl failed %d, %s", sysctl_errno, strerror(sysctl_errno));
+        *err = sysctl_errno;
     }
     
     *seq    = ti.tcpi_snd_nxt - 1;
@@ -1745,8 +1747,9 @@ static int startRacoon(void)
         }
         else if (result < 0)
         {
-            os_log_debug(log_handle, "select returned %d errno %d %s", result, errno, strerror(errno));
-            if (errno != EINTR) break;
+            const int select_errno = errno;
+            os_log_debug(log_handle, "select returned %d errno %d %s", result, select_errno, strerror(select_errno));
+            if (select_errno != EINTR) break;
         }
     }
     
@@ -1827,7 +1830,7 @@ static int setupTunnelRoute(const v6addr_t local, const v6addr_t remote)
     /* send message, ignore error when route already exists */
     if (0 > write(s, &msg, msg.hdr.rtm_msglen))
     {
-        int errno_ = errno;
+        const int errno_ = errno;
         
         os_log_info(log_handle,"write to routing socket failed: %s", strerror(errno_));
         if (EEXIST != errno_)
@@ -1872,7 +1875,7 @@ static int teardownTunnelRoute(const v6addr_t remote)
     memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
     if (0 > write(s, &msg, msg.hdr.rtm_msglen))
     {
-        int errno_ = errno;
+        const int errno_ = errno;
         
         os_log_debug(log_handle,"write to routing socket failed: %s", strerror(errno_));
         
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
index ced72a6..3bb4ec6 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
@@ -661,6 +661,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
     struct sockaddr_storage to;
     int s = -1, err;
     mStatus result = mStatus_NoError;
+    int sendto_errno;
 
     if (InterfaceID)
     {
@@ -736,9 +737,10 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
             err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
             if (err < 0)
             {
+                const int setsockopt_errno = errno;
                 char name[IFNAMSIZ];
                 if (if_indextoname(info->scope_id, name) != NULL)
-                    LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
+                    LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, setsockopt_errno, strerror(setsockopt_errno));
                 else
                     LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
             }
@@ -779,6 +781,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
         setTrafficClass(s, useBackgroundTrafficClass);
 
     err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
+    sendto_errno = (err < 0) ? errno : 0;
 
     // set traffic class back to default value
     if (useBackgroundTrafficClass)
@@ -788,30 +791,30 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
     {
         static int MessageCount = 0;
         LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
-                s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+                s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
         if (!mDNSAddressIsAllDNSLinkGroup(dst))
         {
-            if (errno == EHOSTUNREACH) return(mStatus_HostUnreachErr);
-            if (errno == EHOSTDOWN || errno == ENETDOWN || errno == ENETUNREACH) return(mStatus_TransientErr);
+            if (sendto_errno == EHOSTUNREACH) return(mStatus_HostUnreachErr);
+            if (sendto_errno == EHOSTDOWN || sendto_errno == ENETDOWN || sendto_errno == ENETUNREACH) return(mStatus_TransientErr);
         }
         // Don't report EHOSTUNREACH in the first three minutes after boot
         // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
         // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
-        if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
+        if (sendto_errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
         // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
-        if (errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
-        if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+        if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
+        if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_errno == ENETDOWN)
             LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
-                    s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+                    s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
         else
         {
             MessageCount++;
             if (MessageCount < 50)  // Cap and ensure NO spamming of LogMsgs
                 LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
-                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
+                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
             else  // If logging is enabled, remove the cap and log aggressively
                 LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
-                        s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
+                        s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
         }
 
         result = mStatus_UnknownErr;
@@ -1071,7 +1074,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
         // Find out about other socket parameter that can help understand why select() says the socket is ready for read
         // All of this is racy, as data may have arrived after the call to select()
         static unsigned int numLogMessages = 0;
-        int save_errno = errno;
+        const int save_errno = errno;
         int so_error = -1;
         int so_nread = -1;
         int fionread = -1;
@@ -1912,6 +1915,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
     mStatus err = mStatus_NoError;
     char *errstr = mDNSNULL;
     const int mtu = 0;
+    int saved_errno;
 
     cp->closeFlag = mDNSNULL;
 
@@ -2044,12 +2048,13 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa
     return(mStatus_NoError);
 
 fail:
+    saved_errno = errno;
     // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
     if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
-        LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
+        LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, saved_errno, strerror(saved_errno));
 
     // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
-    if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
+    if (!strcmp(errstr, "bind") && saved_errno == EADDRINUSE)
     {
         err = EADDRINUSE;
         if (mDNSSameIPPort(port, MulticastDNSPort))
@@ -2325,8 +2330,9 @@ cp += len;                  \
     sock = socket(PF_ROUTE, SOCK_RAW, 0);
     if (sock < 0)
     {
-        LogMsg("getMACAddress: Can not open the socket - %s", strerror(errno));
-        return errno;
+        const int socket_errno = errno;
+        LogMsg("getMACAddress: Can not open the socket - %s", strerror(socket_errno));
+        return socket_errno;
     }
     
     rtm->rtm_addrs   |= RTA_DST | RTA_GATEWAY;
@@ -2358,9 +2364,10 @@ cp += len;                  \
     
     if (write(sock, (char *)&m_rtmsg, rlen) < 0)
     {
-        LogMsg("getMACAddress: writing to routing socket: %s", strerror(errno));
+        const int write_errno = errno;
+        LogMsg("getMACAddress: writing to routing socket: %s", strerror(write_errno));
         close(sock);
-        return errno;
+        return write_errno;
     }
     
     do
@@ -3235,7 +3242,11 @@ mDNSlocal  mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
 {
     // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
-    if (!SPSInterface(i)) return(mDNSfalse);
+    if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
+    {
+        LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
+        return(mDNSfalse);
+    }
 
     // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
     // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
@@ -3253,15 +3264,16 @@ mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
     strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
     if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
     {
+        const int ioctl_errno = errno;
         // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
         // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
         // error code is being returned from the kernel, we need to use the kernel version.
         #define KERNEL_EOPNOTSUPP 102
-        if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
-            LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
+        if (ioctl_errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
+            LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, ioctl_errno, strerror(ioctl_errno));
         // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
         // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
-        ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
+        ifr.ifr_wake_flags = (ioctl_errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
     }
 
     close(s);
diff --git a/mDNSResponder/mDNSShared/dns_sd.h b/mDNSResponder/mDNSShared/dns_sd.h
index 41a2bc3..0b47c39 100644
--- a/mDNSResponder/mDNSShared/dns_sd.h
+++ b/mDNSResponder/mDNSShared/dns_sd.h
@@ -66,7 +66,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 8782003
+#define _DNS_SD_H 8783004
 
 #ifdef  __cplusplus
 extern "C" {




More information about the vc mailing list