2 * Copyright (c) 2015-2019 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #if ENABLE_BLE_TRIGGERED_BONJOUR
19 #include "mDNSEmbeddedAPI.h"
20 #include "DNSCommon.h"
21 #include "mDNSMacOSX.h"
27 #pragma mark - Browse and Registration Request Handling
29 // When set, enables BLE triggered discovery APIs.
30 mDNSBool EnableBLEBasedDiscovery
= mDNSfalse
;
32 // When set, the default mode is to promote all client requests made with
33 // kDNSServiceInterfaceIndexAny to BLE Triggered Discovery.
34 // Requests to promote will be filtered by either a service type whitelist or
35 // blacklist as noted below.
36 mDNSBool DefaultToBLETriggered
= mDNSfalse
;
38 #define USE_WHITELIST 1
42 // Current list of service types that will have BLE triggers applied by default
43 // when DefaultToBLETriggered is set to true.
45 const char * defaultServiceWhitelist
[] = {
55 // Return true if DefaultToBLETriggered is set and the operation should be
56 // promoted to use BLE triggered discovery by default.
57 bool shouldUseBLE(mDNSInterfaceID interfaceID
, DNS_TypeValues rrtype
, domainname
*serviceType
, domainname
*domain
)
61 if (!DefaultToBLETriggered
|| (interfaceID
!= mDNSInterface_Any
) || !IsLocalDomain(domain
))
64 // Address records don't have a service type to match on, but we'll trigger them
65 // here to support the case were the DNSServiceQueryRecord() was done using mDNSInterface_Any instead
66 // of the interface that the corresponding SRV record was returned over.
67 if ((rrtype
== kDNSType_A
) || (rrtype
== kDNSType_AAAA
))
70 ptr
= (const mDNSu8
**) defaultServiceWhitelist
;
73 if (SameDomainLabel(*ptr
, serviceType
->c
))
81 #else // USE_WHITELIST
83 // Current list of service types that will NOT have BLE triggers applied by default
84 // when DefaultToBLETriggered is set to true.
86 // _airplay and _airdrop discovery already employ BLE based triggering using Apple service specific
87 // BLE beacons. The rest of the entries here are default browses run in a standard OSX install
88 // that we don't want to have cluttering up the Bloom filter when using the service blacklist approach.
90 const char * defaultServiceBlacklist
[] = {
104 "\x0f_pdl-datastream",
109 // Return true if DefaultToBLETriggered is set and the operation should be
110 // promoted to use BLE triggered discovery by default.
111 bool shouldUseBLE(mDNSInterfaceID interfaceID
, DNS_TypeValues rrtype
, domainname
*serviceType
, domainname
*domain
)
116 if (!DefaultToBLETriggered
|| (interfaceID
!= mDNSInterface_Any
) || !IsLocalDomain(domain
))
119 ptr
= (const mDNSu8
**) defaultServiceBlacklist
;
122 if (SameDomainLabel(*ptr
, serviceType
->c
))
130 #endif // USE_WHITELIST
132 // Structure for linked list of BLE responses received that match
133 // a given client request.
134 typedef struct matchingResponses
136 struct matchingResponses
* next
;
138 } matchingResponses_t
;
140 // Max size of input key generated by DNSNameCompressionBuildLHS() is MAX_DOMAIN_NAME + 3
141 // where the three additional bytes are:
142 // two bytes for DNS_TypeValues and one byte for "compression_packet_v1", the D2D compression version number.
143 #define MAX_KEY_SIZE MAX_DOMAIN_NAME + 3
145 // Initially used for both the browse and registration lists.
146 typedef struct requestList
148 struct requestList
* next
;
149 unsigned int refCount
;
152 DNSServiceFlags flags
;
153 mDNSInterfaceID InterfaceID
;
154 serviceHash_t browseHash
;
155 serviceHash_t registeredHash
;
156 matchingResponses_t
* ourResponses
;
157 bool triggeredOnAWDL
;
159 // The following fields are only used for browse requests currently
160 mDNSu8 key
[MAX_KEY_SIZE
];
163 // The following fields are only used for registration requests currently
164 const ResourceRecord
* resourceRecord
;
167 // Lists for all DNSServiceBrowse() and DNSServiceRegister() requests using
168 // BLE beacon based triggering.
169 static requestList_t
* BLEBrowseListHead
= NULL
;
170 static requestList_t
* BLERegistrationListHead
= NULL
;
172 // The kDNSServiceFlagsAutoTrigger should only be set for a request that would normally apply to AWDL.
173 #define isAutoTriggerRequest(INTERFACE_INDEX, FLAGS) ( (FLAGS & kDNSServiceFlagsAutoTrigger) \
174 && ( (AWDLInterfaceID && (INTERFACE_INDEX == AWDLInterfaceID)) \
175 || ((INTERFACE_INDEX == kDNSServiceInterfaceIndexAny) && (FLAGS & kDNSServiceFlagsIncludeAWDL))))
177 #pragma mark - Manage list of responses that match this request.
179 // Return true if any response matches one of our current registrations.
180 mDNSlocal
bool responseMatchesRegistrations(void)
184 for (ptr
= BLERegistrationListHead
; ptr
; ptr
= ptr
->next
)
186 if (ptr
->ourResponses
)
192 // Return true if the response is already in the list of responses for this client request.
193 mDNSlocal
bool inResponseListForRequest(requestList_t
*request
, void * response
)
195 matchingResponses_t
* rp
;
197 for (rp
= request
->ourResponses
; rp
; rp
= rp
->next
)
198 if (rp
->response
== response
)
204 mDNSlocal
void addToResponseListForRequest(requestList_t
*request
, void * response
)
206 matchingResponses_t
*matchingResponse
= calloc(1, sizeof(matchingResponses_t
));
208 if (matchingResponse
== NULL
)
210 LogMsg("addToResponseListForRequest: calloc() failed!");
213 matchingResponse
->response
= response
;
214 matchingResponse
->next
= request
->ourResponses
;
215 request
->ourResponses
= matchingResponse
;
218 // If response is currently in the list of responses, remove it and return true.
219 // Othewise, return false.
220 mDNSlocal
bool removeFromResponseListForRequest(requestList_t
*request
, void * response
)
222 matchingResponses_t
** nextp
;
223 bool responseRemoved
= false;
225 for (nextp
= & request
->ourResponses
; *nextp
; nextp
= & (*nextp
)->next
)
226 if ((*nextp
)->response
== response
)
231 LogInfo("removeFromResponseListForRequest: response no longer matches for %##s %s ", request
->name
.c
, DNSTypeName(request
->type
));
233 responseRemoved
= true;
234 matchingResponses_t
*tmp
= *nextp
;
235 *nextp
= (*nextp
)->next
;
238 return responseRemoved
;
241 // Free all current entries on the response list for this request.
242 mDNSlocal
void freeResponseListEntriesForRequest(requestList_t
*request
)
244 matchingResponses_t
* ptr
;
246 ptr
= request
->ourResponses
;
249 matchingResponses_t
* tmp
;
255 request
->ourResponses
= 0;
258 #pragma mark - Manage request lists
260 // Return the address of the pointer to the entry, which can either be the address of "listHead"
261 // or the address of the prior entry on the lists "next" pointer.
262 mDNSlocal requestList_t
** findInRequestList(requestList_t
** listHead
, const domainname
*const name
, mDNSu16 type
)
264 requestList_t
**ptr
= listHead
;
266 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
267 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
273 mDNSlocal requestList_t
* addToRequestList(requestList_t
** listHead
, const domainname
*const name
, mDNSu16 type
, DNSServiceFlags flags
)
275 requestList_t
**ptr
= findInRequestList(listHead
, name
, type
);
279 *ptr
= (requestList_t
*) mDNSPlatformMemAllocateClear(sizeof(**ptr
));
281 (*ptr
)->flags
= flags
;
282 AssignDomainName(&(*ptr
)->name
, name
);
284 (*ptr
)->refCount
+= 1;
286 LogInfo("addToRequestList: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
291 mDNSlocal
void removeFromRequestList(requestList_t
** listHead
, const domainname
*const name
, mDNSu16 type
)
293 requestList_t
**ptr
= findInRequestList(listHead
, name
, type
);
295 if (!*ptr
) { LogMsg("removeFromRequestList: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return; }
297 (*ptr
)->refCount
-= 1;
299 LogInfo("removeFromRequestList: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
301 if (!(*ptr
)->refCount
)
303 requestList_t
*tmp
= *ptr
;
305 freeResponseListEntriesForRequest(tmp
);
306 mDNSPlatformMemFree(tmp
);
310 #pragma mark - Hashing and beacon state
312 // These SipHash routines were copied from CoreUtils-500.9.
313 // We use these when running an mDNSRespnder root on a system that does not
314 // have the SipHash() routine available and exported in CoreUtils.
315 // TODO: This local copy should be removed once we are no longer running mDNSResponder roots
316 // on systems that do no include CoreUtils-500.9 or newer.
318 // Start of code copied from: CoreUtils-500.9
320 /*! @group BitRotates
321 @abstract Rotates X COUNT bits to the left or right.
323 #define ROTL( X, N, SIZE ) ( ( (X) << (N) ) | ( (X) >> ( (SIZE) - N ) ) )
324 #define ROTR( X, N, SIZE ) ( ( (X) >> (N) ) | ( (X) << ( (SIZE) - N ) ) )
326 #define ROTL64( X, N ) ROTL( (X), (N), 64 )
327 #define ROTR64( X, N ) ROTR( (X), (N), 64 )
329 #define ReadLittle64( PTR ) \
331 ( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
332 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) | \
333 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 16 ) | \
334 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 24 ) | \
335 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 32 ) | \
336 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) << 40 ) | \
337 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 6 ] ) << 48 ) | \
338 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 7 ] ) << 56 ) ) )
340 // Based on <https://131002.net/siphash/>.
345 v0 += v1; v1 = ROTL64( v1, 13 ); v1 ^= v0; v0 = ROTL64( v0, 32 ); \
346 v2 += v3; v3 = ROTL64( v3, 16 ); v3 ^= v2; \
347 v0 += v3; v3 = ROTL64( v3, 21 ); v3 ^= v0; \
348 v2 += v1; v1 = ROTL64( v1, 17 ); v1 ^= v2; v2 = ROTL64( v2, 32 ); \
352 mDNSlocal
uint64_t local_SipHash( const uint8_t inKey
[ 16 ], const void *inSrc
, size_t inLen
)
354 const uint8_t * src
= (const uint8_t *) inSrc
;
355 size_t const left
= inLen
% 8;
356 const uint8_t * const end
= src
+ ( inLen
- left
);
357 uint64_t k0
, k1
, v0
, v1
, v2
, v3
, tmp
;
359 k0
= ReadLittle64( &inKey
[ 0 ] );
360 k1
= ReadLittle64( &inKey
[ 8 ] );
361 v0
= k0
^ UINT64_C( 0x736f6d6570736575 ); // 'somepseu'
362 v1
= k1
^ UINT64_C( 0x646f72616e646f6d ); // 'dorandom'
363 v2
= k0
^ UINT64_C( 0x6c7967656e657261 ); // 'lygenera'
364 v3
= k1
^ UINT64_C( 0x7465646279746573 ); // 'tedbytes'
366 for( ; src
!= end
; src
+= 8 )
368 tmp
= ReadLittle64( src
);
375 tmp
= ( (uint64_t)( inLen
& 0xFF ) ) << 56;
378 case 7: tmp
|= ( ( (uint64_t) src
[ 6 ] ) << 48 );
379 case 6: tmp
|= ( ( (uint64_t) src
[ 5 ] ) << 40 );
380 case 5: tmp
|= ( ( (uint64_t) src
[ 4 ] ) << 32 );
381 case 4: tmp
|= ( ( (uint64_t) src
[ 3 ] ) << 24 );
382 case 3: tmp
|= ( ( (uint64_t) src
[ 2 ] ) << 16 );
383 case 2: tmp
|= ( ( (uint64_t) src
[ 1 ] ) << 8 );
384 case 1: tmp
|= ( (uint64_t) src
[ 0 ] );
396 return( v0
^ v1
^ v2
^ v3
);
399 // See <https://spc.apple.com/AppleBLEInfo.html#_wifi_tds> for details.
401 #define kTDSSipHashKey ( (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" )
402 #define kTDSSipHashCount 5
404 #define kSizeCString ( (size_t) -1 )
406 // End of code copied from: CoreUtils-500.9
408 // Must link symbol from CoreUtils at runtime to avoid cyclic dependency cycles in the build process.
409 static uint64_t (*SipHash_p
)( const uint8_t inKey
[ 16 ], const void *inSrc
, size_t inLen
) = NULL
;
411 mDNSlocal
uint64_t local_TDSBloomFilterMake( uint32_t inBloomCount
, const void *inStr
, size_t inLen
)
413 uint64_t bloomFilter
= 0, hash
;
416 if( inLen
== kSizeCString
) inLen
= strlen( (const char *) inStr
);
418 hash
= SipHash_p( kTDSSipHashKey
, inStr
, inLen
);
420 hash
= local_SipHash( kTDSSipHashKey
, inStr
, inLen
);
422 for( i
= 0; i
< kTDSSipHashCount
; ++i
)
424 bloomFilter
|= ( UINT64_C( 1 ) << ( hash
% inBloomCount
) );
425 hash
/= inBloomCount
;
427 return( bloomFilter
);
430 mDNSlocal
void loadCoreUtils()
432 static mDNSBool runOnce
= mDNSfalse
;
433 static void *CoreUtils_p
= mDNSNULL
;
434 static const char path
[] = "/System/Library/PrivateFrameworks/CoreUtils.framework/CoreUtils";
441 CoreUtils_p
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
444 LogInfo("loadCoreUtils: dlopen() failed.");
451 SipHash_p
= dlsym(CoreUtils_p
, "SipHash");
454 LogInfo("loadCoreUtils: load of SipHash symbol failed.");
458 LogInfo("loadCoreUtils: found SipHash symbol.");
464 mDNSlocal serviceHash_t
BLELabelHash(unsigned char *str
, unsigned int length
)
468 return local_TDSBloomFilterMake(HASH_SIZE
, (const void *) str
, (size_t) length
);
472 // Maximum number of characters in string to hash should be:
473 // 2 for initial "s:" or "p:"
474 // 16 for "_" followed by up to 15 characters of service type
475 // 1 for separating "."
476 // 4 for "_udp" or "_tcp"
477 // 1 for the terminating NULL byte
478 #define MAX_HASH_STRING (2 + 16 + 1 + 4 + 1)
480 // Maximum service name length, including the initial "_"
481 #define MAX_SERVICE_NAME 16
483 // Convert the service name and transport protocol to a NULL terminated C string.
484 // stringBuf must point to least (MAX_HASH_STRING - 2) bytes of available space.
485 mDNSlocal
bool serviceNameStringFromDomain(const domainname
*const domain
, mDNSu8
* stringBuf
)
487 mDNSu8
* dst
= stringBuf
;
488 const mDNSu8
* src
= domain
->c
;
491 if (len
== 0 || len
> MAX_SERVICE_NAME
)
493 LogInfo("serviceNameStringFromDomain: Invalid name lenght: %d", len
);
498 LogInfo("serviceNameStringFromDomain: service name does not begin with a _");
501 // Copy the service type
507 if (!ValidTransportProtocol(src
))
509 LogInfo("serviceNameStringFromDomain: Transport protocol name must be _udp or _tcp");
512 // copy the transport protocol
521 mDNSlocal
bool setBLEServiceHash(const domainname
*const domain
, requestList_t
* ptr
)
523 // Initialize the string with the "s:" for the browser/seeker hash calculation.
524 mDNSu8 stringBuf
[MAX_HASH_STRING
] = { 's', ':', '\0' };
526 // Append the service name and protocol strings to the initial "s:" string.
527 if (!serviceNameStringFromDomain(domain
, &stringBuf
[2]))
529 LogInfo("setBLEServiceHash: serviceNameStringFromDomain() failed!");
533 ptr
->browseHash
= BLELabelHash(stringBuf
, strlen((const char *)stringBuf
));
534 LogInfo("setBLEServiceHash: seeker string %s, hashed to 0x%lx", stringBuf
, ptr
->browseHash
);
536 // Update string to start with "p:" for registration/provider hash calculation.
539 ptr
->registeredHash
= BLELabelHash(stringBuf
, strlen((const char *)stringBuf
));
540 LogInfo("setBLEServiceHash: provider string %s, hashed to 0x%lx", stringBuf
, ptr
->registeredHash
);
541 if (ptr
->browseHash
&& ptr
->registeredHash
)
547 // Indicates we are sending the final beacon with zeroed Bloom filter to let
548 // peers know we are no longer actively seeking or providing any services.
549 bool finalBeacon
= false;
551 // The last time we walked our response list looking for stale entries.
552 mDNSs32 lastScanForStaleResponses
;
554 // Forward declaration.
555 mDNSlocal
void removeStaleResponses(mDNSs32 currentTime
);
557 // Interval at which we scan the response lists to remove any stale entries.
558 #define StaleResponseScanInterval 30
560 // Called from mDNS_Execute() when NextBLEServiceTime is reached.
561 void serviceBLE(void)
563 // Note, we can access mDNSStorage.timenow since we are called from mDNS_Execute,
564 // which initializes that value by calling mDNS_Lock().
565 mDNSs32 currentTime
= mDNSStorage
.timenow
;
567 // Initialize if zero.
568 if (!lastScanForStaleResponses
)
569 lastScanForStaleResponses
= NonZeroTime(currentTime
- (StaleResponseScanInterval
* mDNSPlatformOneSecond
));
573 // We don't expect to do the finalBeacon processing if there are active browse requests,
574 if (BLEBrowseListHead
)
575 LogInfo("serviceBLE: finalBeacon set and called with active browse BLE requests ??");
577 // or active registrations but we are not in suppress beacons state.
578 if (BLERegistrationListHead
&& !suppressBeacons
)
579 LogInfo("serviceBLE: finalBeacon set and called with active registrations requests, but not in suppress beacons state ??");
585 if (!BLEBrowseListHead
&& !BLERegistrationListHead
)
587 LogInfo("serviceBLE: no active client requests, disabling service timer");
588 mDNSStorage
.NextBLEServiceTime
= 0;
590 else if ((currentTime
- lastScanForStaleResponses
) >= (StaleResponseScanInterval
* mDNSPlatformOneSecond
))
592 removeStaleResponses(currentTime
);
593 lastScanForStaleResponses
= currentTime
;
594 mDNSStorage
.NextBLEServiceTime
= NonZeroTime(currentTime
+ (StaleResponseScanInterval
* mDNSPlatformOneSecond
));
598 // Initialize the periodic service timer if we have active requests.
599 // The timer is disabled in the next call to serviceBLE() when no requests are active.
600 mDNSlocal
void updateServiceTimer()
602 if (!mDNSStorage
.NextBLEServiceTime
&& (BLEBrowseListHead
|| BLERegistrationListHead
))
603 mDNSStorage
.NextBLEServiceTime
= NonZeroTime(mDNSStorage
.timenow
+ (StaleResponseScanInterval
* mDNSPlatformOneSecond
));
606 // Set true when suppressing beacon transmissions for our registrations until we see
607 // a peer beacon indicating a browse for one of our services.
608 bool suppressBeacons
= false;
610 // Go through all the existing browses and registrations to create the
611 // current Bloom filter value for the BLE beacon.
612 // Update the current scan and beaconing state appropriately.
613 mDNSlocal
void updateBeaconAndScanState()
616 serviceHash_t beaconBloomFilter
= 0;
618 updateServiceTimer();
620 for (ptr
= BLEBrowseListHead
; ptr
; ptr
= ptr
->next
)
622 beaconBloomFilter
|= ptr
->browseHash
;
625 for (ptr
= BLERegistrationListHead
; ptr
; ptr
= ptr
->next
)
627 beaconBloomFilter
|= ptr
->registeredHash
;
630 // If only advertising registered services and not browsing, we don't start the beacon transmission
631 // until we receive a beacon from a peer matching one of our registrations.
632 if (BLERegistrationListHead
&& !BLEBrowseListHead
&& !responseMatchesRegistrations())
634 // If beacons are already suppressed, then no further action to take.
636 LogInfo("updateBeaconAndScanState: continuing to suppressing beacons");
639 LogInfo("updateBeaconAndScanState: suppressing beacons, no peers currently seeking our services");
640 suppressBeacons
= true;
642 // If currently beaconing, send a beacon for two seconds with a zeroed Bloom filter indicating we are
643 // no longer browsing for any services so that any matching auto triggered peer registrations have a
644 // chance to see our state change.
645 if (currentlyBeaconing())
650 // If beacons had been suppressed and we no longer have services to advertise, no
651 // need to send a beacon with a zeroed Bloom filter for two seconds, just stop
653 else if (suppressBeacons
== true && beaconBloomFilter
== 0)
655 suppressBeacons
= false;
658 // Update the beacon with the current Bloom filter values.
661 suppressBeacons
= false;
662 updateBLEBeacon(beaconBloomFilter
);
663 // Scan unless the Bloom filter is zero, indicating we are not currently
664 // seeking or providing any services.
665 if (beaconBloomFilter
)
672 #pragma mark - Peer response handling
674 // Structure used to track the beacons received from various peers.
675 typedef struct responseList
677 struct responseList
* next
;
678 serviceHash_t peerBloomFilter
;
679 mDNSs32 recievedTime
;
683 #define RESPONSE_LIST_NUMBER 8
684 static responseList_t
* BLEResponseListHeads
[RESPONSE_LIST_NUMBER
];
686 // Return the address of the pointer to the entry, which can either be the address of the
687 // corresponding BLEResponseListHeads[] entry, or the address of the prior responseList_t entry
688 // on the lists "next" pointer.
689 mDNSlocal responseList_t
** findInResponseList(mDNSEthAddr
* ptrToMAC
)
691 // Use the least significant byte of the MAC address as our hash index to find the list.
692 responseList_t
**ptr
= & BLEResponseListHeads
[ptrToMAC
->b
[5] % RESPONSE_LIST_NUMBER
];
694 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
696 if (memcmp(&(*ptr
)->peerMac
, ptrToMAC
, sizeof(mDNSEthAddr
)) == 0)
704 mDNSlocal responseList_t
* addToResponseList(serviceHash_t peerBloomFilter
, mDNSEthAddr
* ptrToMAC
)
706 responseList_t
**ptr
= findInResponseList(ptrToMAC
);
710 *ptr
= (responseList_t
*) mDNSPlatformMemAllocateClear(sizeof(**ptr
));
711 (*ptr
)->peerBloomFilter
= peerBloomFilter
;
712 memcpy(& (*ptr
)->peerMac
, ptrToMAC
, sizeof(mDNSEthAddr
));
718 mDNSlocal
void removeFromResponseList(mDNSEthAddr
* ptrToMAC
)
720 responseList_t
**ptr
= findInResponseList(ptrToMAC
);
724 LogMsg("removeFromResponseList: did not find entry for MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
725 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
729 LogInfo("removeFromResponseList: removing entry for MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
730 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
732 responseList_t
*tmp
= *ptr
;
734 mDNSPlatformMemFree(tmp
);
737 // Free all current entries on the BLE response lists, removing all pointers
738 // to freed structures from the lists.
739 mDNSlocal
void clearResponseLists()
741 responseList_t
**ptr
;
743 for (unsigned int i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
745 ptr
= & BLEResponseListHeads
[i
];
748 responseList_t
* tmp
;
752 mDNSPlatformMemFree(tmp
);
757 // Check to see if we have cached a response that matches a service for which we just started a browse or registration.
758 mDNSlocal
void checkCachedResponses(requestList_t
*browse
, requestList_t
*registration
)
762 for (unsigned int i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
764 for (ptr
= BLEResponseListHeads
[i
]; ptr
; ptr
= ptr
->next
)
766 // For browses, we are looking for responses that have a matching registration
767 // and for registrations we are looking for responses that have a matching browse.
768 if ( (browse
&& (browse
->registeredHash
& ptr
->peerBloomFilter
) == browse
->registeredHash
)
769 || (registration
&& (registration
->browseHash
& ptr
->peerBloomFilter
) == registration
->browseHash
))
771 // Clear the Bloom filter for the response.
772 // The next beacon from this peer will update the filter then autoTrigger
773 // any newly started client requests as appropriate.
774 ptr
->peerBloomFilter
= 0;
780 // Define a fixed name to use for the instance name denoting that one or more instances
781 // of a service are being advertised by peers in their BLE beacons.
782 // Name format is: length byte + bytes of name string + two byte pointer to the PTR record name.
783 // See compression_lhs definition in the D2D plugin code for background on 0xc027 DNS name compression pointer value.
784 static Byte
*BLEinstanceValue
= (Byte
*) "\x11ThresholdInstance\xc0\x27";
785 #define BLEValueSize strlen((const char *)BLEinstanceValue)
787 // Find each local browse that matches the registered service hash in the BLE response.
788 // Called on the CFRunLoop thread while handling a callback from CoreBluetooth.
789 // Caller should hold KQueueLock().
790 mDNSlocal
void findMatchingBrowse(responseList_t
*response
)
794 ptr
= BLEBrowseListHead
;
795 for ( ; ptr
; ptr
= ptr
->next
)
797 // See if we potentially match a corresponding registration in the beacon.
798 // thus, compare using the "registeredHash" of our browse..
799 if ((ptr
->registeredHash
& response
->peerBloomFilter
) == ptr
->registeredHash
)
802 LogInfo("findMatchingBrowse: Registration in response matched browse for: %##s", ptr
->name
.c
);
804 if (inResponseListForRequest(ptr
, response
))
806 LogInfo("findMatchingBrowse: Already on response list for browse: %##s", ptr
->name
.c
);
812 LogInfo("findMatchingBrowse: Adding to response list for browse: %##s", ptr
->name
.c
);
814 if (ptr
->ourResponses
== 0)
816 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
818 LogInfo("findMatchingBrowse: First BLE response, triggering browse for %##s on AWDL", ptr
->name
.c
);
819 // register with the AWDL D2D plugin,
820 internal_start_browsing_for_service(ptr
->InterfaceID
, & ptr
->name
, ptr
->type
, ptr
->flags
);
821 ptr
->triggeredOnAWDL
= true;
824 // Browse on mDNSInterface_BLE is used to determine if there are one or more instances of the
825 // service type discoveryed over BLE. If this is the first instance, add the psuedo instance defined by BLEinstanceValue.
826 if (ptr
->InterfaceID
== mDNSInterface_BLE
)
828 xD2DAddToCache(kD2DSuccess
, 0, D2DBLETransport
, ptr
->key
, ptr
->keySize
, BLEinstanceValue
, BLEValueSize
);
831 addToResponseListForRequest(ptr
, response
);
836 // If a previous response from this peer had matched the browse, remove that response from the
837 // list now. If this is the last matching response, remove the corresponding key from the AWDL D2D plugin
838 if (removeFromResponseListForRequest(ptr
, response
) && (ptr
->ourResponses
== 0))
840 if (ptr
->InterfaceID
== mDNSInterface_BLE
)
842 xD2DRemoveFromCache(kD2DSuccess
, 0, D2DBLETransport
, ptr
->key
, ptr
->keySize
, BLEinstanceValue
, BLEValueSize
);
845 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
847 LogInfo("findMatchingBrowse: Last BLE response, disabling browse for %##s on AWDL", ptr
->name
.c
);
848 internal_stop_browsing_for_service(ptr
->InterfaceID
, & ptr
->name
, ptr
->type
, ptr
->flags
);
849 ptr
->triggeredOnAWDL
= false;
856 // Find each local registration that matches the service browse hash BLE response Bloom filter.
857 // Called on the CFRunLoop thread while handling a callback from CoreBluetooth.
858 // Caller should hold KQueueLock().
859 mDNSlocal
void findMatchingRegistration(responseList_t
*response
)
864 ptr
= BLERegistrationListHead
;
865 for ( ; ptr
; ptr
= ptr
->next
)
867 // See if we potentially match a corresponding browse in the beacon,
868 // thus, compare using the "browseHash" of our registration.
869 if ((ptr
->browseHash
& response
->peerBloomFilter
) == ptr
->browseHash
)
871 LogInfo("findMatchingRegistration: Incoming browse matched registration for: %##s", ptr
->name
.c
);
873 if (inResponseListForRequest(ptr
, response
))
875 LogInfo("findMatchingRegistration: Already on response list for registration: %##s", ptr
->name
.c
);
881 LogInfo("findMatchingRegistration: Adding to response list for registration: %##s", ptr
->name
.c
);
883 // Also pass the registration to the AWDL D2D plugin if this is the first matching peer browse for
884 // an auto triggered local registration.
885 if ((ptr
->ourResponses
== 0) && isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
887 LogInfo("findMatchingRegistration: First BLE response, triggering registration for %##s on AWDL", ptr
->name
.c
);
888 if (ptr
->resourceRecord
== 0)
890 LogInfo("findMatchingRegistration: resourceRecord pointer is NULL ??");
894 internal_start_advertising_service(ptr
->resourceRecord
, (ptr
->flags
| kDNSServiceFlagsIncludeAWDL
));
895 // indicate the registration has been applied to the AWDL interface
896 ptr
->triggeredOnAWDL
= true;
899 addToResponseListForRequest(ptr
, response
);
904 // If a previous response from this peer had matched the browse, remove that response from the
905 // list now. If this is the last matching response for a local auto triggered registration,
906 // remove the advertised key/value pairs from the AWDL D2D plugin.
907 if (removeFromResponseListForRequest(ptr
, response
) && (ptr
->ourResponses
== 0) && isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
909 LogInfo("findMatchingRegistration: Last BLE response, disabling registration for %##s on AWDL", ptr
->name
.c
);
911 // Restore the saved ARType and call into the AWDL D2D plugin to stop the corresponding record advertisements over AWDL.
912 internal_stop_advertising_service(ptr
->resourceRecord
, (ptr
->flags
| kDNSServiceFlagsIncludeAWDL
));
913 ptr
->triggeredOnAWDL
= false;
918 // If beacons for our registrations had been suppressed, see if we now have a match and need to restart them.
919 matchingPeer
= responseMatchesRegistrations();
920 if (suppressBeacons
&& matchingPeer
)
922 LogInfo("findMatchingRegistration: peer searching for our service, starting beacon transmission");
923 updateBeaconAndScanState();
925 if (suppressBeacons
== true)
926 LogInfo("findMatchingRegistration: NOTE: suppressBeacons is true after updateBeaconAndScanState() call ??");
928 // If we have only registrations, but no matching peers, we can suppress beacons until we get a matching peer beacon.
929 else if (!suppressBeacons
&& !matchingPeer
&& BLERegistrationListHead
&& !BLEBrowseListHead
)
931 LogInfo("findMatchingRegistration: no peer beacons match our registrations, suppressing beacon transmission");
932 suppressBeacons
= true;
938 // Time limit before a beacon is aged out of our received list.
939 #define MAX_RESPONSE_AGE 10
941 // If we have responses from peers that are more than MAX_RESPONSE_AGE seconds
942 // old, remove them since a peer with active requests should be beaconing multiple
943 // times per second if still within BLE range.
944 mDNSlocal
void removeStaleResponses(mDNSs32 currentTime
)
946 responseList_t
**ptr
;
948 for (unsigned int i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
950 ptr
= & BLEResponseListHeads
[i
];
953 if ((currentTime
- (*ptr
)->recievedTime
) > (MAX_RESPONSE_AGE
* mDNSPlatformOneSecond
))
955 responseList_t
* tmp
;
957 // Clear the Bloom filter so that it will be removed from any matching response list
958 // by the following calls.
959 (*ptr
)->peerBloomFilter
= 0;
961 LogInfo("removeStaleResponses: clearing stale response from peer MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
962 (*ptr
)->peerMac
.b
[0], (*ptr
)->peerMac
.b
[1], (*ptr
)->peerMac
.b
[2], (*ptr
)->peerMac
.b
[3], (*ptr
)->peerMac
.b
[4], (*ptr
)->peerMac
.b
[5]);
964 findMatchingBrowse(*ptr
);
965 findMatchingRegistration(*ptr
);
967 // Unlink and free the response structure
970 mDNSPlatformMemFree(tmp
);
972 // Move to the next response on this linked list.
974 ptr
= & (*ptr
)->next
;
979 // Called on CFRunLoop thread during CoreBluetooth beacon response processing.
980 // Thus, must call KQueueLock() prior to calling any core mDNSResponder routines to register records, etc.
981 void responseReceived(serviceHash_t peerBloomFilter
, mDNSEthAddr
* ptrToMAC
)
983 responseList_t
* ptr
;
986 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow
988 ptr
= *(findInResponseList(ptrToMAC
));
991 // Only add to list if peer is actively browsing or advertising.
994 LogInfo("responseReceived: First beacon of this type, adding to list");
995 LogInfo("responseReceived: peerBloomFilter = 0x%lx", peerBloomFilter
);
996 LogInfo("responseReceived: peer MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
997 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
999 ptr
= addToResponseList(peerBloomFilter
, ptrToMAC
);
1000 // Update the received time.
1001 ptr
->recievedTime
= mDNSStorage
.timenow
;
1002 // See if we are browsing for any of the peers advertised services.
1003 findMatchingBrowse(ptr
);
1004 // See if we have a registration that matches the peer's browse.
1005 findMatchingRegistration(ptr
);
1008 else // Have an entry from this MAC in the list.
1010 // Update the received time.
1011 ptr
->recievedTime
= mDNSStorage
.timenow
;
1013 if (ptr
->peerBloomFilter
== peerBloomFilter
)
1015 // A duplicate of a current entry.
1016 #if VERBOSE_BLE_DEBUG
1017 LogInfo("responseReceived: Duplicate of previous beacon, ignoring");
1018 LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
1019 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
1020 #endif // VERBOSE_BLE_DEBUG
1024 LogInfo("responseReceived: Update of previous beacon");
1025 LogInfo("responseReceived: peerBloomFilter = 0x%lx", peerBloomFilter
);
1026 LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
1027 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
1029 ptr
->peerBloomFilter
= peerBloomFilter
;
1030 findMatchingBrowse(ptr
);
1031 findMatchingRegistration(ptr
);
1034 // If peer is no longer browsing or advertising, remove from list.
1035 if (peerBloomFilter
== 0)
1037 LogInfo("responseReceived: Removing peer entry from the list");
1039 removeFromResponseList(ptrToMAC
);
1043 mDNS_Unlock(& mDNSStorage
); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
1044 KQueueUnlock("BLE responseReceived");
1047 #pragma mark - Client request handling
1049 void start_BLE_browse(mDNSInterfaceID InterfaceID
, const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
, mDNSu8
*key
, size_t keySize
)
1051 requestList_t
* ptr
;
1052 const domainname
*serviceType
= domain
;
1054 if (!EnableBLEBasedDiscovery
)
1056 LogMsg("start_BLE_browse: EnableBLEBasedDiscovery disabled");
1060 if (keySize
> MAX_KEY_SIZE
)
1062 LogMsg("start_BLE_browse: keySize = %d, maximum allowable is %d", keySize
, MAX_KEY_SIZE
);
1066 // Verify that the request to be auto triggered applies to AWDL, or is using the pseudo interface for
1067 // BLE threshold browsing.
1068 if (!isAutoTriggerRequest(InterfaceID
, flags
) && (InterfaceID
!= mDNSInterface_BLE
))
1070 LogMsg("start_BLE_browse: invalid request: InterfaceID = %d, flags = 0x%x", InterfaceID
, flags
);
1074 // Address records don't have a service type to hash and match on, so pass them directly to the D2D plugin.
1075 if ((type
== kDNSType_A
) || (type
== kDNSType_AAAA
))
1077 LogInfo("start_BLE_browse: Passing directly to D2D layer: %##s %s", domain
->c
, DNSTypeName(type
));
1078 internal_start_browsing_for_service(InterfaceID
, domain
, type
, flags
);
1082 // Skip the instance to get to the service type for non PTR records
1083 if (type
!= kDNSType_PTR
)
1084 serviceType
= SkipLeadingLabels(domain
, 1);
1086 LogInfo("start_BLE_browse: Starting BLE service type browse for: %##s %s", domain
->c
, DNSTypeName(type
));
1088 ptr
= addToRequestList(&BLEBrowseListHead
, domain
, type
, flags
);
1090 // If equivalent BLE browse is already running, just return.
1091 if (ptr
->refCount
> 1)
1093 LogInfo("start_BLE_browse: Dup of existing BLE browse.");
1097 if (!setBLEServiceHash(serviceType
, ptr
))
1099 LogInfo("setBLEServiceHash failed!");
1100 removeFromRequestList(&BLEBrowseListHead
, domain
, type
);
1104 // Save these for use in D2D plugin callback logic.
1105 memcpy(ptr
->key
, key
, keySize
);
1106 ptr
->keySize
= keySize
;
1107 ptr
->InterfaceID
= InterfaceID
;
1109 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1110 updateBeaconAndScanState();
1111 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1112 checkCachedResponses(ptr
, NULL
);
1116 // Return true if this is the last reference to the browse, false otherwise.
1117 bool stop_BLE_browse(mDNSInterfaceID InterfaceID
, const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
)
1119 (void) flags
; // not used initially
1120 requestList_t
* ptr
;
1121 bool lastReference
= false;
1123 if (!EnableBLEBasedDiscovery
)
1125 LogMsg("stop_BLE_browse: EnableBLEBasedDiscovery disabled");
1126 return lastReference
;
1129 // Address records don't have a service type to hash and match on, so pass them directly to the D2D plugin.
1130 if ((type
== kDNSType_A
) || (type
== kDNSType_AAAA
))
1132 LogInfo("stop_BLE_browse: Passing directly to D2D layer: %##s %s", domain
->c
, DNSTypeName(type
));
1133 internal_stop_browsing_for_service(InterfaceID
, domain
, type
, flags
);
1134 return lastReference
;
1137 LogInfo("stop_BLE_browse: Stopping BLE service type browse for: %##s %s", domain
->c
, DNSTypeName(type
));
1139 ptr
= *(findInRequestList(&BLEBrowseListHead
, domain
, type
));
1142 LogInfo("stop_BLE_browse: No matching browse found.");
1143 return lastReference
;
1146 // If this is the last reference for this browse, and it was autoTriggered on AWDL,
1147 // remove the request from the AWDL pluggin.
1148 if (ptr
->refCount
== 1)
1150 lastReference
= true;
1152 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
) && ptr
->triggeredOnAWDL
)
1154 internal_stop_browsing_for_service(ptr
->InterfaceID
, & ptr
->name
, ptr
->type
, ptr
->flags
);
1155 ptr
->triggeredOnAWDL
= false;
1159 removeFromRequestList(&BLEBrowseListHead
, domain
, type
);
1161 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1163 updateBeaconAndScanState();
1164 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1166 // If there are no active browse or registration requests, BLE scanning will be disabled.
1167 // Clear the list of responses received to remove any stale response state.
1168 if (BLEBrowseListHead
== NULL
&& BLERegistrationListHead
== 0)
1169 clearResponseLists();
1171 return lastReference
;
1174 void start_BLE_advertise(const ResourceRecord
*const resourceRecord
, const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
)
1176 requestList_t
* ptr
;
1177 const domainname
* serviceType
= domain
;
1179 if (!EnableBLEBasedDiscovery
)
1181 LogMsg("start_BLE_advertise: EnableBLEBasedDiscovery disabled");
1185 if (resourceRecord
== NULL
)
1187 LogInfo("start_BLE_advertise: NULL resourceRecord for: %##s %s, returning", domain
->c
, DNSTypeName(type
));
1191 // Verify that the request to be auto triggered applies to AWDL, or is using the pseudo interface for
1192 // BLE threshold browsing.
1193 if (!isAutoTriggerRequest(resourceRecord
->InterfaceID
, flags
) && (resourceRecord
->InterfaceID
!= mDNSInterface_BLE
))
1195 LogMsg("start_BLE_advertise: invalid request: InterfaceID = %d, flags = 0x%x", resourceRecord
->InterfaceID
, flags
);
1199 LogInfo("start_BLE_advertise: Starting BLE service type advertisement for: %##s %s", domain
->c
, DNSTypeName(type
));
1201 // Skip the instance to get to the service type for non PTR records
1202 if (type
!= kDNSType_PTR
)
1203 serviceType
= SkipLeadingLabels(domain
, 1);
1205 ptr
= addToRequestList(&BLERegistrationListHead
, domain
, type
, flags
);
1207 // If equivalent BLE registration is already running, just return.
1208 if (ptr
->refCount
> 1)
1210 LogInfo("start_BLE_advertise: Dup of existing BLE advertisement.");
1214 if (!setBLEServiceHash(serviceType
, ptr
))
1216 LogInfo("setBLEServiceHash failed!");
1217 removeFromRequestList(&BLERegistrationListHead
, domain
, type
);
1220 ptr
->resourceRecord
= resourceRecord
;
1221 ptr
->InterfaceID
= resourceRecord
->InterfaceID
;
1223 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1224 updateBeaconAndScanState();
1225 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1226 checkCachedResponses(NULL
, ptr
);
1229 void stop_BLE_advertise(const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
)
1231 (void) flags
; // not used initially
1232 requestList_t
* ptr
;
1233 bool lastReference
= false;
1235 LogInfo("stop_BLE_advertise: Stopping BLE service type advertisement for: %##s %s", domain
->c
, DNSTypeName(type
));
1237 // Get the request pointer from the indirect pointer returned.
1238 ptr
= *(findInRequestList(&BLERegistrationListHead
, domain
, type
));
1242 LogInfo("stop_BLE_advertise: No matching advertisement found.");
1246 // If this is the last reference for this registration, and it was autoTriggered on AWDL,
1247 // remove the request from the AWDL pluggin.
1248 if (ptr
->refCount
== 1)
1250 lastReference
= true;
1252 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
) && ptr
->triggeredOnAWDL
)
1254 // And remove the corresponding advertisements from the AWDL D2D plugin if we had previously
1255 // passed this advertisement request to the plugin.
1256 internal_stop_advertising_service(ptr
->resourceRecord
, (ptr
->flags
| kDNSServiceFlagsIncludeAWDL
));
1257 ptr
->triggeredOnAWDL
= false;
1260 removeFromRequestList(&BLERegistrationListHead
, domain
, type
);
1262 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1263 // If this is the last reference for this registration, update advertising and browsing bits set in the beacon.
1265 updateBeaconAndScanState();
1266 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1268 // If there are no active browse or registration requests, BLE scanning will be disabled.
1269 // Clear the list of responses received to remove any stale response state.
1270 if (BLEBrowseListHead
== NULL
&& BLERegistrationListHead
== 0)
1271 clearResponseLists();
1275 #pragma mark - Unit test support routines
1277 // These unit test support routines are called from unittests/ framework
1278 // and are not compiled for the mDNSResponder runtime code paths.
1280 #define MAX_ENTRIES 42
1281 #define FAILED exit(1)
1283 mDNSlocal
void BLE_requestListTests(void)
1285 const domainname
*domainArray
[] = { (const domainname
*)"\x6" "_test0" "\x4" "_tcp" "\x5" "local",
1286 (const domainname
*)"\x6" "_test1" "\x4" "_tcp" "\x5" "local",
1287 (const domainname
*)"\x6" "_test2" "\x4" "_tcp" "\x5" "local",
1288 (const domainname
*)"\x6" "_test3" "\x4" "_tcp" "\x5" "local",
1289 (const domainname
*)"\x6" "_test4" "\x4" "_tcp" "\x5" "local",
1292 mDNSu16 type
= kDNSServiceType_PTR
;
1293 DNSServiceFlags flags
= 0;
1294 requestList_t
* ptr
;
1295 void * response
= 0;
1297 int numOfdomains
= sizeof(domainArray
)/sizeof(domainArray
[0]);
1299 printf("BLE_requestListTests() entry:\n");
1301 // Basic request list unit tests.
1302 for (i
= 0; i
< numOfdomains
; i
++)
1304 ptr
= addToRequestList(&BLEBrowseListHead
, domainArray
[i
], type
, flags
);
1308 printf("addToRequestList() FAILED:\n");
1312 for (i
= 0; i
< numOfdomains
; i
++)
1314 // should now find the entry
1315 if (*(findInRequestList(&BLEBrowseListHead
, domainArray
[i
], type
)) == 0)
1317 printf("findInRequestList() did not find valid entry FAILED:\n");
1320 // but not find an entry with the same domain, but different type
1321 if (*(findInRequestList(&BLEBrowseListHead
, domainArray
[i
], kDNSServiceType_NULL
)) != 0)
1323 printf("findInRequestList() invalid entry matched FAILED:\n");
1327 // remove all the entries
1328 for (i
= 0; i
< numOfdomains
; i
++)
1330 removeFromRequestList(&BLEBrowseListHead
, domainArray
[i
], type
);
1332 // and sanity check the list is now empty
1333 if (BLEBrowseListHead
)
1335 printf("BLEBrowseListHead not empty after all entries removed.\n");
1339 // Identical request reference count management tests.
1340 // Add identical requests to the list and verify the corresponding refCount is managed correctly
1341 for (i
= 0; i
< MAX_ENTRIES
; i
++)
1343 ptr
= addToRequestList(&BLEBrowseListHead
, domainArray
[0], type
, flags
);
1347 printf("addToRequestList() of duplicate request FAILED:\n");
1352 if (ptr
->refCount
!= MAX_ENTRIES
)
1354 printf("refCount = %d, should be %d\n", ptr
->refCount
, MAX_ENTRIES
);
1358 // Remove all but one entry
1359 for (i
= 0; i
< (MAX_ENTRIES
- 1); i
++)
1361 removeFromRequestList(&BLEBrowseListHead
, domainArray
[0], type
);
1363 if (ptr
->refCount
!= 1)
1365 printf("refCount = %d, should be %d\n", ptr
->refCount
, 1);
1369 // Basic response list unit tests.
1370 // Note that responses per request are not checked for duplicates at this level, so
1371 // we can unit test with the same (NULL) response pointer to add multiple responses.
1373 // add MAX_ENTRIES responses
1374 for (i
= 0; i
< MAX_ENTRIES
; i
++)
1375 addToResponseListForRequest(ptr
, response
);
1377 // remove the responses, counting that MAX_ENTRIES were removed
1379 while (inResponseListForRequest(ptr
, response
) && removeFromResponseListForRequest(ptr
, response
))
1383 if (i
!= MAX_ENTRIES
)
1385 printf("removed %d responses, should have been %d\n", i
, MAX_ENTRIES
);
1389 // response list should be empty at this point
1390 if (ptr
->ourResponses
)
1392 printf("response list should be empty\n");
1396 // add MAX_ENTRIES responses
1397 for (i
= 0; i
< MAX_ENTRIES
; i
++)
1398 addToResponseListForRequest(ptr
, response
);
1401 freeResponseListEntriesForRequest(ptr
);
1403 if (ptr
->ourResponses
)
1405 printf("freeResponseListEntriesForRequest() should have removed all responses\n");
1410 mDNSlocal mDNSEthAddr etherAddress
[] = {
1411 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
1412 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
1413 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
1414 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } },
1415 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 } },
1416 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 } },
1417 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06 } },
1418 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } },
1419 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 } },
1420 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 } },
1421 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a } },
1422 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b } },
1423 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c } },
1424 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d } },
1425 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e } },
1426 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f } },
1429 mDNSlocal
void BLE_responseListTests(void)
1431 int numOfEtherAddresses
= sizeof(etherAddress
)/sizeof(etherAddress
[0]);
1434 printf("BLE_responseListTests() entry:\n");
1436 // Just use the index as to generate the peerBloomFilter value to vary it per entry.
1437 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1438 (void)addToResponseList(1 << i
, ðerAddress
[i
]);
1440 // Verify all entries are found.
1441 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1443 if (*(findInResponseList(ðerAddress
[i
])) == 0)
1445 printf("findInResponseList() did not find entry in list\n");
1450 // Remove all entries.
1451 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1452 removeFromResponseList(ðerAddress
[i
]);
1454 // Sanity check that all response lists are empty
1455 for (i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
1457 if (BLEResponseListHeads
[i
])
1459 printf("BLEResponseListHeads[%d] not empty after removeFromResponseList() calls \n", i
);
1464 // Add them back again.
1465 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1466 (void)addToResponseList(1 << i
, ðerAddress
[i
]);
1468 // And verify that clearResponseLists() clears all entries.
1469 clearResponseLists();
1470 for (i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
1472 if (BLEResponseListHeads
[i
])
1474 printf("BLEResponseListHeads[%d] not empty after clearResponseLists() call\n", i
);
1480 void BLE_unitTest(void)
1482 BLE_requestListTests();
1483 BLE_responseListTests();
1484 printf("All BLE.c unit tests PASSED.\n");
1489 #endif // ENABLE_BLE_TRIGGERED_BONJOUR