Bonjour Conformance Test WARNING in Multicast DNS SHARED REPLY TIMING resolution

Hello and Good day!

We are conducting Bonjour Conformance Test (BCT) for Printer device.

BCT result is PASSED but with warning in Multicast DNS, specifically,

WARNING: SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION

Other Shared Reply Timing is passed:

PASSED: MULTIPLE QUESTIONS - SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION

Environment:

  • BCT Tool Version: 1.5.4 (15400)
  • MacOS Sequioa 15.5
  • DUT Firmware : Linux Debian 9
  • Apple mDNSResponder 1790.80.10
  • Service types: _ipps._tcp, _uscans._tcp, _ipp._tcp, _uscan._tcp
  • Router : NEC AtermWR8370N
  • Setup: 1-to-1 [Mac->Router<-DUT connection]

Based on debug.log, this is where WARNING occurs:

NOTICE 2026-03-04 10:51:06.870187+0900 _shared_reply_timing 04103: Shared reply response times: min = 26ms, max = 114ms, avg = 65.50ms WARNING 2026-03-04 10:51:06.870361+0900 _shared_reply_timing 04136: 50 percent of the replies within the correct range fell in the interval 20ms and 46ms (should be close to 25%). PASSED (SHARED REPLY TIMING)

In the same debug.log for MULTIPLE QUESTIONS - SHARED REPLY TIMING is PASSED:

NOTICE 2026-03-04 10:52:29.912334+0900 _shared_reply_timing 04103: Shared reply response times: min = 22ms, max = 112ms, avg = 78.00ms DEBUG_2 2026-03-04 10:52:29.912849+0900 recv_packet 01997: received packet (558 bytes) PASSED (MULTIPLE QUESTIONS - SHARED REPLY TIMING)

[Details] Looking at Bonjour_Conformance_Guideline.pdf https://download.developer.apple.com/Documentation/Bonjour_Conformance_Test_Guideline/Bonjour_Conformance_Guideline.pdf

there were some differences:

  1. In 1.6.2 Expected Result: Test Result File of Test that All Tests Passed, this is not displayed:

PASSED: SHARED REPLY TIMING - UNIFORM RANDOM REPLY TIME DISTRIBUTION

  1. And in II.8 Shared Reply Timing:

(Ideally, 25% of the answers should fall in each 21ms quadrant of the range 20ms - 125ms.) and comparing to the debug.log, there was a discrepancy of the interval, because 20ms and 46ms is 26ms interval.

  1. From RFC6762 6. Responding, Ideal range is from 20ms-120ms

Because of this, please advise on the questions below:

  • I would like to know on the possible cause and resolution for these WARNINGS.
  • And since in current BCT result, (Test result integrity signature is generated), I would like to know if this is acceptable for BCT certification.

Thank you.

Answered by DTS Engineer in 880360022

Thank you for providing the code. I modify a bit to be able to build in our DUT

FYI, my original code has some logic flaws that I eventually sorted out with a bit more testing and experimentation. The underlying math here is that the BCT binning test is equivalent to the combined probability of rolling 10 3-sided dice and having either or both of these occur:

  1. The same number appear on 4 or more dice -> ~31%

  2. At least one number not appearing at all ->21%

...and the combined probability of those two events works out to about ~40%. I suspect/assume that you're having test runs that OCCASIONALLY succeed, but the inherent failure rate might also be being skewed by other details of your implementation.

I've filed a bug on this already (r.172771068), but I'd appreciate your filing your own bug and posting the bug number back here.

I would like to confirm if the result of SHARED REPLY TIMING with Warning is not an issue and can still result to BCT certification to Pass.

This warning is not an issue and should not prevent certification.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

[Details] Looking at Bonjour_Conformance_Guideline.pdf ... there were some differences:

So, for future reference, the Bonjour Conformance Guideline document is primarily focused on details of how the test needs to be run, NOT what the test actual "does" or how to interpret it's results.

The details of the test process itself are found in:

Documentation/Conformance Test Outline.txt

...inside the disk image of the conformance test itself. For the share reply timing test, that document says:

II.8 Shared Reply Timing

The test tool issues a query for a shared (service PTR) record, and records how quickly the device answers. This test is repeated 10 times. The response times must form a uniform random distribution in the range 20ms - 125ms. Any results in the range 10ms - 20ms, or 125ms - 750ms are warnings. Any results less than 10ms or more than 750ms are failures. For purposes of determining a uniform random distribution, only the answers that fall into the correct time range (20ms - 125ms) are considered. It is a warning if less than 5% or more than 45% of these answers fall in any one quadrant of the range. (Ideally, 25% of the answers should fall in each 21ms quadrant of the range 20ms - 125ms.) If all 100 replies lie within one tenth of the correct range, this is a failure. (To accommodate low-cost devices with low clock precision, warning-generating replies outside of the 20ms - 125ms range automatically prevent random distribution failures).

...

For the details, please refer to "RFC6762 6. Responding".

Note the RFC reference at the end. All of the test in the BCT correspond to requirements defined by the underlying RFC specs, so the test outline also refers back to the controlling RFC.

In term of this particular test section 6 of RFC6762 has the full rational, but the short summary is that spec expects a small random delay between response to reduce the probability of ethernet collision. Your particular failure was caused by exactly what the warning described:

"50 percent of the replies within the correct range fell in the interval 20ms and 46ms"

That leads to here:

(Ideally, 25% of the answers should fall in each 21ms quadrant of the range 20ms - 125ms.) and comparing to the debug.log, there was a discrepancy of the interval, because 20ms and 46ms is 26ms interval.

The "21ms quadrant" is a typo (r.172415434), as the correct interval for "20ms - 125ms" is "26ms":

(125ms - 20ms) -> 105ms

105/4 -> 26.25 -> 26ms

In terms of the RFC:

From RFC6762 6. Responding, Ideal range is from 20ms-120ms

I believe the BCT is intentionally setting it's ideal range slightly above the RFC ideal so that issues like network latency and other "noise" don't generate invalid failures. Putting that in more concrete terms, it's very difficult (basically impossible) for a device to delay for 119ms (a valid delay) while GUARANTEEING that the reply will be received by 120ms. A packet received at 123ms has no meaningful impact on the large bonjour protocol (since the valid range is obviously MUCH larger) so adding a small "pad" to the range reduce testing issues without creating any other impact.

I would like to know on the possible cause

See above.

and resolution for these WARNINGS.

I'd start by looking at the actual reply times, as the real concern here is fixed or consistent delays, not the distribution, as fixed or consistently repeating intervals could actually INCREASE the collision rate. At that point, it's then a matter of investigating and correcting whatever is causing your replay delay to be so short.

And since in current BCT result, (Test result integrity signature is generated), I would like to know if this is acceptable for BCT certification.

That's not a decision I'm directly involved with but, no, I wouldn't expect this to be an issue, assuming there isn't any obvious issue (like repeating patterns) in your reply delay.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi and thank you for response. For

I'd start by looking at the actual reply times, as the real concern here is fixed or consistent delays, not the distribution, as fixed or consistently repeating intervals could actually INCREASE the collision rate. At that point, it's then a matter of investigating and correcting whatever is causing your replay delay to be so short.

We have another test and the debug.log interval result is in 46ms to 72ms

NOTICE 2026-03-06 14:46:29.580419+0900 _shared_reply_timing 04103: Shared reply response times: min = 36ms, max = 120ms, avg = 68.90ms WARNING 2026-03-06 14:46:29.580541+0900 _shared_reply_timing 04136: 50 percent of the replies within the correct range fell in the interval 46ms and 72ms (should be close to 25%). PASSED (SHARED REPLY TIMING)

What we have understood so far is that the randomness is in mdnsresponder, called by the arc4random(), mDNSPlatformRandomNumber in mDNSPosix\mDNSPosix.c

#if !defined(_PLATFORM_HAS_STRONG_PRNG_) && (_BUILDING_XCODE_PROJECT_ || defined(_WIN32) || TARGET_OS_LINUX) #define _PLATFORM_HAS_STRONG_PRNG_ 1 #endif `#if PLATFORM_HAS_STRONG_PRNG extern mDNSu32 mDNSPlatformRandomNumber(void);

WARNING still occurs and we need advise if there is a more direct setting in mdnsResponder.

Thank you.

We have another test and the debug.log interval result is in 46ms to 72ms

OK. The question here is still what the actual intervals being generate were. Again, the concern here is that you're actually using a consistent sequence of delay, not something "random".

What we have understood so far is that the randomness is in mdnsresponder, called by the arc4random(), mDNSPlatformRandomNumber in mDNSPosix\mDNSPosix.c

That's the base source of random values, but the delay calculation is actually done here in mDNSCore/mDNS.c. The details of that calculation will vary depending on your platform configuration, so you might want to validate that mDNSPlatformOneSecond is being defined in a way that matches your hardware's capability.

WARNING still occurs and we need advise if there is a more direct setting in mdnsResponder.

Again, the next step here is to take a look at the actual values you're generating for the delay.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi and thank you very much for checking and advice. We checked the actual values of mdnsresponder by modifiying and adding log to mDNSCore/mDNS.c:ProcessQuery() after m->SuppressResponses (ln8822)

There is a definition MDNS_LOG_ANSWER_SUPPRESSION_TIMES that we set to 1, then rebuild to our DUT.

Below is the actual value result after restarting DUT:

2026-03-16T12:02:43.383297+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 64
2026-03-16T12:02:43.444028+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay     2; require    21
2026-03-16T12:02:43.444028+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 46
2026-03-16T12:02:44.781498+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    15; require    21
2026-03-16T12:02:44.781498+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 109
2026-03-16T12:02:45.567413+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay     0; require    21
2026-03-16T12:02:45.567413+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 33
2026-03-16T12:04:06.449555+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    20; require    21
2026-03-16T12:04:06.449555+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 93
2026-03-16T12:04:06.520841+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    20; require    21
2026-03-16T12:04:06.520841+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 62
2026-03-16T12:04:06.577234+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay     4; require    21
2026-03-16T12:04:06.577234+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 118
2026-03-16T12:04:06.876284+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    18; require    21
2026-03-16T12:04:06.876284+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 60
2026-03-16T12:04:07.468765+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    13; require    21
2026-03-16T12:04:07.468765+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 39
2026-03-16T12:04:07.688407+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    20; require    21
2026-03-16T12:04:07.688407+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 67
2026-03-16T12:04:07.736154+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay    19; require    21
2026-03-16T12:04:07.736154+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 45
2026-03-16T12:04:07.878733+09:00 	[mDNSResponder]	Default: Current SuppressResponses delay     2; require    21
2026-03-16T12:04:07.878733+09:00 	[mDNSResponder]	Default: MDNSPlatformOneSecond check:  1024. Set SuppressResponses to 95

Checking above result:

  • mDNSPlatformOneSecond is 1024 as we use Linux OS
  • First 10 results range is as follows:
  • 20–45 - 20% (33,39)
  • 46–71 - 50% (64,46,62,60,67)
  • 72–97 - 10% (93)
  • 98–125 - 20% (109,118)

=== Results are random but due to the range of one quadrant exceeding 45% threshold, I think this results to the WARNING SHARED REPLY TIMING

The computation of random delay in mdnsResponder is not modified however, so I would like to seek advice further.

Thank you.

First 10 results range is as follows:

This may or may not be an issue, as a small enough sample set will basically "always" have skewed binning. It's possible that the same issue is going on here; however, it's also possible that something about your platform configuration is calling mDNSRandom to skew.

Attached below is a small test I threw together by pulling the response delay code out of mDNSResponder and then hard coding values to replicate your configuration. I'd suggest running it on your hardware and see what distribution it finds. If the test below who's uniform distribution, then I'd ignore the warning as irrelevant. If it doesn't, then that's worth a deeper investigation.

//
//  main.m
//  bonjour_ranTest
//
//  Created by Kevin Elliott on 3/16/26.
//

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

uint32_t mDNSPlatformRandomNumber(void)
{
    return(arc4random());
}

uint32_t mDNSRandom(uint32_t max)      // Returns pseudo-random result from zero to max inclusive
{
#if 1
    uint32_t ret = 0;
    uint32_t mask = 1;
    
    while (mask < max) mask = (mask << 1) | 1;
    
    do ret = mDNSPlatformRandomNumber() & mask;
    while (ret > max);
  
    return ret;
#else
    return arc4random_uniform(max+1);
#endif
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        const int count = 100000;
        uint32_t mDNSPlatformOneSecond = 1024;
        uint32_t delayresponse = mDNSPlatformOneSecond;
        uint32_t ranArray[count + 10];
        uint32_t count20_45 = 0;
        uint32_t count46_71 = 0;
        uint32_t count72_97 = 0;
        uint32_t count98_125 = 0;
        uint32_t minVal = 1000;
        uint32_t maxVal = 0;
        for (int i = 0; i<=count; i++) {
            uint32_t ranVal = (uint32_t)mDNSRandom((uint32_t)mDNSPlatformOneSecond * 5) + 49;
            uint32_t val = ((delayresponse + ranVal) / 50);
            ranArray[i] = val;
            //printf("Num: %d\n", ranArray[i]);
            
            if(val < minVal) minVal = val;
            if(val > maxVal) maxVal = val;

            if(val >=20 && val<=45){
                count20_45++;
            }
            else if(val >=45 && val<=71){
                count46_71++;
            }
            else if(val >=72 && val<=97){
                count72_97++;
            }
            else if(val >=98 && val<=125){
                count98_125++;
            }
            else {
                printf("BIN FAIL!!! %d\n", val);
                assert(0);
            }

        }
        printf("max: %d min: %d\n", maxVal, minVal);
        float perc = count20_45 * 1.0;
        perc = (perc/count) * 100.0;
        printf("count20_45: %d, %f\n", count46_71, perc);
        
        perc = count46_71 * 1.0;
        perc = (perc/count) * 100.0;
        printf("count46_71: %d, %f\n", count46_71, perc);
        
        perc = count72_97 * 1.0;
        perc = (perc/count) * 100.0;
        printf("count72_97: %d, %f\n", count46_71, perc);
        
        perc = count98_125 * 1.0;
        perc = (perc/count) * 100.0;
        printf("count98_125: %d, %f\n", count46_71, perc);

    }
    return EXIT_SUCCESS;
}

Finally, you'll note that the function also includes an ifdef that replaces mDNSRandom() implementation with a direct call to arc4random_uniform(). I don't know the underlying history, but I suspect much of the current implementation basically exists because arc4random_uniform wasn't widely available. It's possible I've overlooked something, but I can't think of any reason why arc4random_uniform wouldn't be better than the current implementation of mDNSRandom.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi and thanks again for detailed response,

First 10 was due to the information from Documentation/Conformance Test Outline.txt

II.8 Shared Reply Timing The test tool issues a query for a shared (service PTR) record, and records how quickly the device answers. This test is repeated 10 times.

So the assumption of this is understood and I agree to "always" have skewed binning.

Attached below is a small test I threw together by pulling the response delay code out of mDNSResponder and then hard coding values

Thank you for providing the code. I modify a bit to be able to build in our DUT

	//  main.m
	//  bonjour_ranTest
	//
	//  Created by Kevin Elliott on 3/16/26.
	//
	 
	#include <stdio.h>
	#include <stdlib.h>
	#include <assert.h>
	#include <stdint.h> // Added 
	 
	uint32_t mDNSPlatformRandomNumber(void)
	{
	    return(arc4random());
	}
	 
	uint32_t mDNSRandom(uint32_t max)      // Returns pseudo-random result from zero to max inclusive
	{
	#if 1
	    uint32_t ret = 0;
	    uint32_t mask = 1;
	    
	    while (mask < max) mask = (mask << 1) | 1;
	    
	    do ret = mDNSPlatformRandomNumber() & mask;
	    while (ret > max);
	  
	    return ret;
	#else
	    return arc4random_uniform(max+1);
	#endif
	}
	 
	int main(int argc, const char * argv[]) {
		// Removed autoreleasepool
	        const int count = 100000; // Modified to other sample size
	        uint32_t mDNSPlatformOneSecond = 1024;
	        uint32_t delayresponse = mDNSPlatformOneSecond;
	        uint32_t ranArray[count + 10];
	        uint32_t count20_45 = 0;
	        uint32_t count46_71 = 0;
	        uint32_t count72_97 = 0;
	        uint32_t count98_125 = 0;
	        uint32_t minVal = 1000;
	        uint32_t maxVal = 0;
	        for (int i = 0; i<count; i++) { // Modified
	            uint32_t ranVal = (uint32_t)mDNSRandom((uint32_t)mDNSPlatformOneSecond * 5) + 49;
	            uint32_t val = ((delayresponse + ranVal) / 50);
	            ranArray[i] = val;
	            //printf("Num: %d\n", ranArray[i]);
	            
	            if(val < minVal) minVal = val;
	            if(val > maxVal) maxVal = val;
	 
	            if(val >=20 && val<=45){
	                count20_45++;
	            }
	            else if(val >=45 && val<=71){
	                count46_71++;
	            }
	            else if(val >=72 && val<=97){
	                count72_97++;
	            }
	            else if(val >=98 && val<=125){
	                count98_125++;
	            }
	            else {
	                printf("BIN FAIL!!! %d\n", val);
	                assert(0);
	            }
	 
			printf("max: %d min: %d\n", maxVal, minVal);
	        float perc = count20_45 * 1.0;
	        perc = (perc/count) * 100.0;
	        printf("count20_45: %d, %f\n", count20_45, perc); // Modified
	        
	        perc = count46_71 * 1.0;
	        perc = (perc/count) * 100.0;
	        printf("count46_71: %d, %f\n", count46_71, perc);
	        
	        perc = count72_97 * 1.0;
	        perc = (perc/count) * 100.0;
	        printf("count72_97: %d, %f\n", count72_97, perc); // Modified
	        
	        perc = count98_125 * 1.0;
	        perc = (perc/count) * 100.0;
	        printf("count98_125: %d, %f\n", count98_125, perc); // Modified
	 
	    }
	    return EXIT_SUCCESS;
	}

Below is the result after running: COUNT: 100000 max: 123 min: 21 count20_45: 23933, 23.932999 count46_71: 25400, 25.400002 count72_97: 25303, 25.302999 count98_125: 25364, 25.364000 Result: There is uniform distribution of actual values per 26ms quadrant

Also tested other COUNT. For COUNT 10 in particular, there is tendency to exceed acceptable threshold of 26ms quadrant. As COUNT becomes larger, the distribution becomes uniform

COUNT: 10 max: 112 min: 30 count20_45: 2, 20.000000 count46_71: 1, 10.000000 count72_97: 5, 50.000000 ✦ Again, this also exceeded range count98_125: 2, 20.000000

COUNT: 100 max: 123 min: 22 count20_45: 23, 23.000000 count46_71: 23, 23.000000 count72_97: 28, 28.000000 count98_125: 27, 27.000002

COUNT: 1000 max: 123 min: 21 count20_45: 238, 23.800001 count46_71: 280, 28.000000 count72_97: 256, 25.600000 count98_125: 227, 22.700001

For the arc4random_uniform(), modified mDNSResponder for a possible solution, but seems to still occur.

As sample size becomes larger, distribution becomes uniform. So assumption is that the issue occurs due to small sample size in BCT Shared Reply Timing test. Therefore, for BCT, is it possible to increase the test from 10 to 100. Or in the current version BCT 1.5.4 (15400), I would like to confirm if the result of SHARED REPLY TIMING with Warning is not an issue and can still result to BCT certification to Pass.

Thank you.

Accepted Answer

Thank you for providing the code. I modify a bit to be able to build in our DUT

FYI, my original code has some logic flaws that I eventually sorted out with a bit more testing and experimentation. The underlying math here is that the BCT binning test is equivalent to the combined probability of rolling 10 3-sided dice and having either or both of these occur:

  1. The same number appear on 4 or more dice -> ~31%

  2. At least one number not appearing at all ->21%

...and the combined probability of those two events works out to about ~40%. I suspect/assume that you're having test runs that OCCASIONALLY succeed, but the inherent failure rate might also be being skewed by other details of your implementation.

I've filed a bug on this already (r.172771068), but I'd appreciate your filing your own bug and posting the bug number back here.

I would like to confirm if the result of SHARED REPLY TIMING with Warning is not an issue and can still result to BCT certification to Pass.

This warning is not an issue and should not prevent certification.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi and thank you for confirmation for this issue.

I've filed a bug on this already (r.172771068), but I'd appreciate your filing your own bug and posting the bug number back here.

I have created a Feedback Assistant for this: https://feedbackassistant.apple.com/feedback/22266931 Also created a Code-Level Support case, with the same title as with Feedback Assistant but it seems to be private.

Please inform if I may have missed anything.

Once again, thank you for support.

I have created a Feedback Assistant for this: https://feedbackassistant.apple.com/feedback/22266931

Prefect, thank you.

Also created a Code-Level Support case, with the same title as with Feedback Assistant but it seems to be private.

Yep. I've replied to that with a summary of the situation as well.

Please inform if I may have missed anything.

Everything looks good to me. At this point, I think you should ignore the issue and proceed with development. This warning won't have any effect on the certification process.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Bonjour Conformance Test WARNING in Multicast DNS SHARED REPLY TIMING resolution
 
 
Q