1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #if ENABLE_BLE_TRIGGERED_BONJOUR
20 #include "mDNSEmbeddedAPI.h"
21 #include "DNSCommon.h"
22 #include "mDNSMacOSX.h"
28 #pragma mark - Browse and Registration Request Handling
30 // When set, enables BLE triggered discovery APIs.
31 mDNSBool EnableBLEBasedDiscovery
= mDNSfalse
;
33 // When set, the default mode is to promote all client requests made with
34 // kDNSServiceInterfaceIndexAny to BLE Triggered Discovery.
35 // Requests to promote will be filtered by either a service type whitelist or
36 // blacklist as noted below.
37 mDNSBool DefaultToBLETriggered
= mDNSfalse
;
39 #define USE_WHITELIST 1
43 // Current list of service types that will have BLE triggers applied by default
44 // when DefaultToBLETriggered is set to true.
46 const char * defaultServiceWhitelist
[] = {
56 // Return true if DefaultToBLETriggered is set and the operation should be
57 // promoted to use BLE triggered discovery by default.
58 bool shouldUseBLE(mDNSInterfaceID interfaceID
, DNS_TypeValues rrtype
, domainname
*serviceType
, domainname
*domain
)
62 if (!DefaultToBLETriggered
|| (interfaceID
!= mDNSInterface_Any
) || !IsLocalDomain(domain
))
65 // Address records don't have a service type to match on, but we'll trigger them
66 // here to support the case were the DNSServiceQueryRecord() was done using mDNSInterface_Any instead
67 // of the interface that the corresponding SRV record was returned over.
68 if ((rrtype
== kDNSType_A
) || (rrtype
== kDNSType_AAAA
))
71 ptr
= (const mDNSu8
**) defaultServiceWhitelist
;
74 if (SameDomainLabel(*ptr
, serviceType
->c
))
82 #else // USE_WHITELIST
84 // Current list of service types that will NOT have BLE triggers applied by default
85 // when DefaultToBLETriggered is set to true.
87 // _airplay and _airdrop discovery already employ BLE based triggering using Apple service specific
88 // BLE beacons. The rest of the entries here are default browses run in a standard OSX install
89 // that we don't want to have cluttering up the Bloom filter when using the service blacklist approach.
91 const char * defaultServiceBlacklist
[] = {
100 "\x0e_apple-mobdev2",
105 "\x0f_pdl-datastream",
110 // Return true if DefaultToBLETriggered is set and the operation should be
111 // promoted to use BLE triggered discovery by default.
112 bool shouldUseBLE(mDNSInterfaceID interfaceID
, DNS_TypeValues rrtype
, domainname
*serviceType
, domainname
*domain
)
117 if (!DefaultToBLETriggered
|| (interfaceID
!= mDNSInterface_Any
) || !IsLocalDomain(domain
))
120 ptr
= (const mDNSu8
**) defaultServiceBlacklist
;
123 if (SameDomainLabel(*ptr
, serviceType
->c
))
131 #endif // USE_WHITELIST
133 // Structure for linked list of BLE responses received that match
134 // a given client request.
135 typedef struct matchingResponses
137 struct matchingResponses
* next
;
139 } matchingResponses_t
;
141 // Max size of input key generated by DNSNameCompressionBuildLHS() is MAX_DOMAIN_NAME + 3
142 // where the three additional bytes are:
143 // two bytes for DNS_TypeValues and one byte for "compression_packet_v1", the D2D compression version number.
144 #define MAX_KEY_SIZE MAX_DOMAIN_NAME + 3
146 // Initially used for both the browse and registration lists.
147 typedef struct requestList
149 struct requestList
* next
;
150 unsigned int refCount
;
153 DNSServiceFlags flags
;
154 mDNSInterfaceID InterfaceID
;
155 serviceHash_t browseHash
;
156 serviceHash_t registeredHash
;
157 matchingResponses_t
* ourResponses
;
158 bool triggeredOnAWDL
;
160 // The following fields are only used for browse requests currently
161 mDNSu8 key
[MAX_KEY_SIZE
];
164 // The following fields are only used for registration requests currently
165 const ResourceRecord
* resourceRecord
;
168 // Lists for all DNSServiceBrowse() and DNSServiceRegister() requests using
169 // BLE beacon based triggering.
170 static requestList_t
* BLEBrowseListHead
= NULL
;
171 static requestList_t
* BLERegistrationListHead
= NULL
;
173 // The kDNSServiceFlagsAutoTrigger should only be set for a request that would normally apply to AWDL.
174 #define isAutoTriggerRequest(INTERFACE_INDEX, FLAGS) ( (FLAGS & kDNSServiceFlagsAutoTrigger) \
175 && ( (AWDLInterfaceID && (INTERFACE_INDEX == AWDLInterfaceID)) \
176 || ((INTERFACE_INDEX == kDNSServiceInterfaceIndexAny) && (FLAGS & kDNSServiceFlagsIncludeAWDL))))
178 #pragma mark - Manage list of responses that match this request.
180 // Return true if any response matches one of our current registrations.
181 mDNSlocal
bool responseMatchesRegistrations(void)
185 for (ptr
= BLERegistrationListHead
; ptr
; ptr
= ptr
->next
)
187 if (ptr
->ourResponses
)
193 // Return true if the response is already in the list of responses for this client request.
194 mDNSlocal
bool inResponseListForRequest(requestList_t
*request
, void * response
)
196 matchingResponses_t
* rp
;
198 for (rp
= request
->ourResponses
; rp
; rp
= rp
->next
)
199 if (rp
->response
== response
)
205 mDNSlocal
void addToResponseListForRequest(requestList_t
*request
, void * response
)
207 matchingResponses_t
*matchingResponse
= calloc(1, sizeof(matchingResponses_t
));
209 if (matchingResponse
== NULL
)
211 LogMsg("addToResponseListForRequest: calloc() failed!");
214 matchingResponse
->response
= response
;
215 matchingResponse
->next
= request
->ourResponses
;
216 request
->ourResponses
= matchingResponse
;
219 // If response is currently in the list of responses, remove it and return true.
220 // Othewise, return false.
221 mDNSlocal
bool removeFromResponseListForRequest(requestList_t
*request
, void * response
)
223 matchingResponses_t
** nextp
;
224 bool responseRemoved
= false;
226 for (nextp
= & request
->ourResponses
; *nextp
; nextp
= & (*nextp
)->next
)
227 if ((*nextp
)->response
== response
)
232 LogInfo("removeFromResponseListForRequest: response no longer matches for %##s %s ", request
->name
.c
, DNSTypeName(request
->type
));
234 responseRemoved
= true;
235 matchingResponses_t
*tmp
= *nextp
;
236 *nextp
= (*nextp
)->next
;
239 return responseRemoved
;
242 // Free all current entries on the response list for this request.
243 mDNSlocal
void freeResponseListEntriesForRequest(requestList_t
*request
)
245 matchingResponses_t
* ptr
;
247 ptr
= request
->ourResponses
;
250 matchingResponses_t
* tmp
;
256 request
->ourResponses
= 0;
259 #pragma mark - Manage request lists
261 // Return the address of the pointer to the entry, which can either be the address of "listHead"
262 // or the address of the prior entry on the lists "next" pointer.
263 mDNSlocal requestList_t
** findInRequestList(requestList_t
** listHead
, const domainname
*const name
, mDNSu16 type
)
265 requestList_t
**ptr
= listHead
;
267 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
268 if ((*ptr
)->type
== type
&& SameDomainName(&(*ptr
)->name
, name
))
274 mDNSlocal requestList_t
* addToRequestList(requestList_t
** listHead
, const domainname
*const name
, mDNSu16 type
, DNSServiceFlags flags
)
276 requestList_t
**ptr
= findInRequestList(listHead
, name
, type
);
280 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
281 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
283 (*ptr
)->flags
= flags
;
284 AssignDomainName(&(*ptr
)->name
, name
);
286 (*ptr
)->refCount
+= 1;
288 LogInfo("addToRequestList: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
293 mDNSlocal
void removeFromRequestList(requestList_t
** listHead
, const domainname
*const name
, mDNSu16 type
)
295 requestList_t
**ptr
= findInRequestList(listHead
, name
, type
);
297 if (!*ptr
) { LogMsg("removeFromRequestList: Didn't find %##s %s in list", name
->c
, DNSTypeName(type
)); return; }
299 (*ptr
)->refCount
-= 1;
301 LogInfo("removeFromRequestList: %##s %s refcount now %u", (*ptr
)->name
.c
, DNSTypeName((*ptr
)->type
), (*ptr
)->refCount
);
303 if (!(*ptr
)->refCount
)
305 requestList_t
*tmp
= *ptr
;
307 freeResponseListEntriesForRequest(tmp
);
308 mDNSPlatformMemFree(tmp
);
312 #pragma mark - Hashing and beacon state
314 // These SipHash routines were copied from CoreUtils-500.9.
315 // We use these when running an mDNSRespnder root on a system that does not
316 // have the SipHash() routine available and exported in CoreUtils.
317 // TODO: This local copy should be removed once we are no longer running mDNSResponder roots
318 // on systems that do no include CoreUtils-500.9 or newer.
320 // Start of code copied from: CoreUtils-500.9
322 /*! @group BitRotates
323 @abstract Rotates X COUNT bits to the left or right.
325 #define ROTL( X, N, SIZE ) ( ( (X) << (N) ) | ( (X) >> ( (SIZE) - N ) ) )
326 #define ROTR( X, N, SIZE ) ( ( (X) >> (N) ) | ( (X) << ( (SIZE) - N ) ) )
328 #define ROTL64( X, N ) ROTL( (X), (N), 64 )
329 #define ROTR64( X, N ) ROTR( (X), (N), 64 )
331 #define ReadLittle64( PTR ) \
333 ( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
334 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) | \
335 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 16 ) | \
336 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 24 ) | \
337 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 32 ) | \
338 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) << 40 ) | \
339 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 6 ] ) << 48 ) | \
340 ( ( (uint64_t)( (uint8_t *)(PTR) )[ 7 ] ) << 56 ) ) )
342 // Based on <https://131002.net/siphash/>.
347 v0 += v1; v1 = ROTL64( v1, 13 ); v1 ^= v0; v0 = ROTL64( v0, 32 ); \
348 v2 += v3; v3 = ROTL64( v3, 16 ); v3 ^= v2; \
349 v0 += v3; v3 = ROTL64( v3, 21 ); v3 ^= v0; \
350 v2 += v1; v1 = ROTL64( v1, 17 ); v1 ^= v2; v2 = ROTL64( v2, 32 ); \
354 mDNSlocal
uint64_t local_SipHash( const uint8_t inKey
[ 16 ], const void *inSrc
, size_t inLen
)
356 const uint8_t * src
= (const uint8_t *) inSrc
;
357 size_t const left
= inLen
% 8;
358 const uint8_t * const end
= src
+ ( inLen
- left
);
359 uint64_t k0
, k1
, v0
, v1
, v2
, v3
, tmp
;
361 k0
= ReadLittle64( &inKey
[ 0 ] );
362 k1
= ReadLittle64( &inKey
[ 8 ] );
363 v0
= k0
^ UINT64_C( 0x736f6d6570736575 ); // 'somepseu'
364 v1
= k1
^ UINT64_C( 0x646f72616e646f6d ); // 'dorandom'
365 v2
= k0
^ UINT64_C( 0x6c7967656e657261 ); // 'lygenera'
366 v3
= k1
^ UINT64_C( 0x7465646279746573 ); // 'tedbytes'
368 for( ; src
!= end
; src
+= 8 )
370 tmp
= ReadLittle64( src
);
377 tmp
= ( (uint64_t)( inLen
& 0xFF ) ) << 56;
380 case 7: tmp
|= ( ( (uint64_t) src
[ 6 ] ) << 48 );
381 case 6: tmp
|= ( ( (uint64_t) src
[ 5 ] ) << 40 );
382 case 5: tmp
|= ( ( (uint64_t) src
[ 4 ] ) << 32 );
383 case 4: tmp
|= ( ( (uint64_t) src
[ 3 ] ) << 24 );
384 case 3: tmp
|= ( ( (uint64_t) src
[ 2 ] ) << 16 );
385 case 2: tmp
|= ( ( (uint64_t) src
[ 1 ] ) << 8 );
386 case 1: tmp
|= ( (uint64_t) src
[ 0 ] );
398 return( v0
^ v1
^ v2
^ v3
);
401 // See <https://spc.apple.com/AppleBLEInfo.html#_wifi_tds> for details.
403 #define kTDSSipHashKey ( (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" )
404 #define kTDSSipHashCount 5
406 #define kSizeCString ( (size_t) -1 )
408 // End of code copied from: CoreUtils-500.9
410 // Must link symbol from CoreUtils at runtime to avoid cyclic dependency cycles in the build process.
411 static uint64_t (*SipHash_p
)( const uint8_t inKey
[ 16 ], const void *inSrc
, size_t inLen
) = NULL
;
413 mDNSlocal
uint64_t local_TDSBloomFilterMake( uint32_t inBloomCount
, const void *inStr
, size_t inLen
)
415 uint64_t bloomFilter
= 0, hash
;
418 if( inLen
== kSizeCString
) inLen
= strlen( (const char *) inStr
);
420 hash
= SipHash_p( kTDSSipHashKey
, inStr
, inLen
);
422 hash
= local_SipHash( kTDSSipHashKey
, inStr
, inLen
);
424 for( i
= 0; i
< kTDSSipHashCount
; ++i
)
426 bloomFilter
|= ( UINT64_C( 1 ) << ( hash
% inBloomCount
) );
427 hash
/= inBloomCount
;
429 return( bloomFilter
);
432 mDNSlocal
void loadCoreUtils()
434 static mDNSBool runOnce
= mDNSfalse
;
435 static void *CoreUtils_p
= mDNSNULL
;
436 static const char path
[] = "/System/Library/PrivateFrameworks/CoreUtils.framework/CoreUtils";
443 CoreUtils_p
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
446 LogInfo("loadCoreUtils: dlopen() failed.");
453 SipHash_p
= dlsym(CoreUtils_p
, "SipHash");
456 LogInfo("loadCoreUtils: load of SipHash symbol failed.");
460 LogInfo("loadCoreUtils: found SipHash symbol.");
466 mDNSlocal serviceHash_t
BLELabelHash(unsigned char *str
, unsigned int length
)
470 return local_TDSBloomFilterMake(HASH_SIZE
, (const void *) str
, (size_t) length
);
474 // Maximum number of characters in string to hash should be:
475 // 2 for initial "s:" or "p:"
476 // 16 for "_" followed by up to 15 characters of service type
477 // 1 for separating "."
478 // 4 for "_udp" or "_tcp"
479 // 1 for the terminating NULL byte
480 #define MAX_HASH_STRING (2 + 16 + 1 + 4 + 1)
482 // Maximum service name length, including the initial "_"
483 #define MAX_SERVICE_NAME 16
485 // Convert the service name and transport protocol to a NULL terminated C string.
486 // stringBuf must point to least (MAX_HASH_STRING - 2) bytes of available space.
487 mDNSlocal
bool serviceNameStringFromDomain(const domainname
*const domain
, mDNSu8
* stringBuf
)
489 mDNSu8
* dst
= stringBuf
;
490 const mDNSu8
* src
= domain
->c
;
493 if (len
== 0 || len
> MAX_SERVICE_NAME
)
495 LogInfo("serviceNameStringFromDomain: Invalid name lenght: %d", len
);
500 LogInfo("serviceNameStringFromDomain: service name does not begin with a _");
503 // Copy the service type
509 if (!ValidTransportProtocol(src
))
511 LogInfo("serviceNameStringFromDomain: Transport protocol name must be _udp or _tcp");
514 // copy the transport protocol
523 mDNSlocal
bool setBLEServiceHash(const domainname
*const domain
, requestList_t
* ptr
)
525 // Initialize the string with the "s:" for the browser/seeker hash calculation.
526 mDNSu8 stringBuf
[MAX_HASH_STRING
] = { 's', ':', '\0' };
528 // Append the service name and protocol strings to the initial "s:" string.
529 if (!serviceNameStringFromDomain(domain
, &stringBuf
[2]))
531 LogInfo("setBLEServiceHash: serviceNameStringFromDomain() failed!");
535 ptr
->browseHash
= BLELabelHash(stringBuf
, strlen((const char *)stringBuf
));
536 LogInfo("setBLEServiceHash: seeker string %s, hashed to 0x%lx", stringBuf
, ptr
->browseHash
);
538 // Update string to start with "p:" for registration/provider hash calculation.
541 ptr
->registeredHash
= BLELabelHash(stringBuf
, strlen((const char *)stringBuf
));
542 LogInfo("setBLEServiceHash: provider string %s, hashed to 0x%lx", stringBuf
, ptr
->registeredHash
);
543 if (ptr
->browseHash
&& ptr
->registeredHash
)
549 // Indicates we are sending the final beacon with zeroed Bloom filter to let
550 // peers know we are no longer actively seeking or providing any services.
551 bool finalBeacon
= false;
553 // The last time we walked our response list looking for stale entries.
554 mDNSs32 lastScanForStaleResponses
;
556 // Forward declaration.
557 mDNSlocal
void removeStaleResponses(mDNSs32 currentTime
);
559 // Interval at which we scan the response lists to remove any stale entries.
560 #define StaleResponseScanInterval 30
562 // Called from mDNS_Execute() when NextBLEServiceTime is reached.
563 void serviceBLE(void)
565 // Note, we can access mDNSStorage.timenow since we are called from mDNS_Execute,
566 // which initializes that value by calling mDNS_Lock().
567 mDNSs32 currentTime
= mDNSStorage
.timenow
;
569 // Initialize if zero.
570 if (!lastScanForStaleResponses
)
571 lastScanForStaleResponses
= NonZeroTime(currentTime
- (StaleResponseScanInterval
* mDNSPlatformOneSecond
));
575 // We don't expect to do the finalBeacon processing if there are active browse requests,
576 if (BLEBrowseListHead
)
577 LogInfo("serviceBLE: finalBeacon set and called with active browse BLE requests ??");
579 // or active registrations but we are not in suppress beacons state.
580 if (BLERegistrationListHead
&& !suppressBeacons
)
581 LogInfo("serviceBLE: finalBeacon set and called with active registrations requests, but not in suppress beacons state ??");
587 if (!BLEBrowseListHead
&& !BLERegistrationListHead
)
589 LogInfo("serviceBLE: no active client requests, disabling service timer");
590 mDNSStorage
.NextBLEServiceTime
= 0;
592 else if ((currentTime
- lastScanForStaleResponses
) >= (StaleResponseScanInterval
* mDNSPlatformOneSecond
))
594 removeStaleResponses(currentTime
);
595 lastScanForStaleResponses
= currentTime
;
596 mDNSStorage
.NextBLEServiceTime
= NonZeroTime(currentTime
+ (StaleResponseScanInterval
* mDNSPlatformOneSecond
));
600 // Initialize the periodic service timer if we have active requests.
601 // The timer is disabled in the next call to serviceBLE() when no requests are active.
602 mDNSlocal
void updateServiceTimer()
604 if (!mDNSStorage
.NextBLEServiceTime
&& (BLEBrowseListHead
|| BLERegistrationListHead
))
605 mDNSStorage
.NextBLEServiceTime
= NonZeroTime(mDNSStorage
.timenow
+ (StaleResponseScanInterval
* mDNSPlatformOneSecond
));
608 // Set true when suppressing beacon transmissions for our registrations until we see
609 // a peer beacon indicating a browse for one of our services.
610 bool suppressBeacons
= false;
612 // Go through all the existing browses and registrations to create the
613 // current Bloom filter value for the BLE beacon.
614 // Update the current scan and beaconing state appropriately.
615 mDNSlocal
void updateBeaconAndScanState()
618 serviceHash_t beaconBloomFilter
= 0;
620 updateServiceTimer();
622 for (ptr
= BLEBrowseListHead
; ptr
; ptr
= ptr
->next
)
624 beaconBloomFilter
|= ptr
->browseHash
;
627 for (ptr
= BLERegistrationListHead
; ptr
; ptr
= ptr
->next
)
629 beaconBloomFilter
|= ptr
->registeredHash
;
632 // If only advertising registered services and not browsing, we don't start the beacon transmission
633 // until we receive a beacon from a peer matching one of our registrations.
634 if (BLERegistrationListHead
&& !BLEBrowseListHead
&& !responseMatchesRegistrations())
636 // If beacons are already suppressed, then no further action to take.
638 LogInfo("updateBeaconAndScanState: continuing to suppressing beacons");
641 LogInfo("updateBeaconAndScanState: suppressing beacons, no peers currently seeking our services");
642 suppressBeacons
= true;
644 // If currently beaconing, send a beacon for two seconds with a zeroed Bloom filter indicating we are
645 // no longer browsing for any services so that any matching auto triggered peer registrations have a
646 // chance to see our state change.
647 if (currentlyBeaconing())
652 // If beacons had been suppressed and we no longer have services to advertise, no
653 // need to send a beacon with a zeroed Bloom filter for two seconds, just stop
655 else if (suppressBeacons
== true && beaconBloomFilter
== 0)
657 suppressBeacons
= false;
660 // Update the beacon with the current Bloom filter values.
663 suppressBeacons
= false;
664 updateBLEBeacon(beaconBloomFilter
);
665 // Scan unless the Bloom filter is zero, indicating we are not currently
666 // seeking or providing any services.
667 if (beaconBloomFilter
)
674 #pragma mark - Peer response handling
676 // Structure used to track the beacons received from various peers.
677 typedef struct responseList
679 struct responseList
* next
;
680 serviceHash_t peerBloomFilter
;
681 mDNSs32 recievedTime
;
685 #define RESPONSE_LIST_NUMBER 8
686 static responseList_t
* BLEResponseListHeads
[RESPONSE_LIST_NUMBER
];
688 // Return the address of the pointer to the entry, which can either be the address of the
689 // corresponding BLEResponseListHeads[] entry, or the address of the prior responseList_t entry
690 // on the lists "next" pointer.
691 mDNSlocal responseList_t
** findInResponseList(mDNSEthAddr
* ptrToMAC
)
693 // Use the least significant byte of the MAC address as our hash index to find the list.
694 responseList_t
**ptr
= & BLEResponseListHeads
[ptrToMAC
->b
[5] % RESPONSE_LIST_NUMBER
];
696 for ( ; *ptr
; ptr
= &(*ptr
)->next
)
698 if (memcmp(&(*ptr
)->peerMac
, ptrToMAC
, sizeof(mDNSEthAddr
)) == 0)
706 mDNSlocal responseList_t
* addToResponseList(serviceHash_t peerBloomFilter
, mDNSEthAddr
* ptrToMAC
)
708 responseList_t
**ptr
= findInResponseList(ptrToMAC
);
712 *ptr
= mDNSPlatformMemAllocate(sizeof(**ptr
));
713 mDNSPlatformMemZero(*ptr
, sizeof(**ptr
));
714 (*ptr
)->peerBloomFilter
= peerBloomFilter
;
715 memcpy(& (*ptr
)->peerMac
, ptrToMAC
, sizeof(mDNSEthAddr
));
721 mDNSlocal
void removeFromResponseList(mDNSEthAddr
* ptrToMAC
)
723 responseList_t
**ptr
= findInResponseList(ptrToMAC
);
727 LogMsg("removeFromResponseList: did not find entry for MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
728 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
732 LogInfo("removeFromResponseList: removing entry for MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
733 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
735 responseList_t
*tmp
= *ptr
;
737 mDNSPlatformMemFree(tmp
);
740 // Free all current entries on the BLE response lists, removing all pointers
741 // to freed structures from the lists.
742 mDNSlocal
void clearResponseLists()
744 responseList_t
**ptr
;
746 for (unsigned int i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
748 ptr
= & BLEResponseListHeads
[i
];
751 responseList_t
* tmp
;
755 mDNSPlatformMemFree(tmp
);
760 // Check to see if we have cached a response that matches a service for which we just started a browse or registration.
761 mDNSlocal
void checkCachedResponses(requestList_t
*browse
, requestList_t
*registration
)
765 for (unsigned int i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
767 for (ptr
= BLEResponseListHeads
[i
]; ptr
; ptr
= ptr
->next
)
769 // For browses, we are looking for responses that have a matching registration
770 // and for registrations we are looking for responses that have a matching browse.
771 if ( (browse
&& (browse
->registeredHash
& ptr
->peerBloomFilter
) == browse
->registeredHash
)
772 || (registration
&& (registration
->browseHash
& ptr
->peerBloomFilter
) == registration
->browseHash
))
774 // Clear the Bloom filter for the response.
775 // The next beacon from this peer will update the filter then autoTrigger
776 // any newly started client requests as appropriate.
777 ptr
->peerBloomFilter
= 0;
783 // Define a fixed name to use for the instance name denoting that one or more instances
784 // of a service are being advertised by peers in their BLE beacons.
785 // Name format is: length byte + bytes of name string + two byte pointer to the PTR record name.
786 // See compression_lhs definition in the D2D plugin code for background on 0xc027 DNS name compression pointer value.
787 static Byte
*BLEinstanceValue
= (Byte
*) "\x11ThresholdInstance\xc0\x27";
788 #define BLEValueSize strlen((const char *)BLEinstanceValue)
790 // Find each local browse that matches the registered service hash in the BLE response.
791 // Called on the CFRunLoop thread while handling a callback from CoreBluetooth.
792 // Caller should hold KQueueLock().
793 mDNSlocal
void findMatchingBrowse(responseList_t
*response
)
797 ptr
= BLEBrowseListHead
;
798 for ( ; ptr
; ptr
= ptr
->next
)
800 // See if we potentially match a corresponding registration in the beacon.
801 // thus, compare using the "registeredHash" of our browse..
802 if ((ptr
->registeredHash
& response
->peerBloomFilter
) == ptr
->registeredHash
)
805 LogInfo("findMatchingBrowse: Registration in response matched browse for: %##s", ptr
->name
.c
);
807 if (inResponseListForRequest(ptr
, response
))
809 LogInfo("findMatchingBrowse: Already on response list for browse: %##s", ptr
->name
.c
);
815 LogInfo("findMatchingBrowse: Adding to response list for browse: %##s", ptr
->name
.c
);
817 if (ptr
->ourResponses
== 0)
819 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
821 LogInfo("findMatchingBrowse: First BLE response, triggering browse for %##s on AWDL", ptr
->name
.c
);
822 // register with the AWDL D2D plugin,
823 internal_start_browsing_for_service(ptr
->InterfaceID
, & ptr
->name
, ptr
->type
, ptr
->flags
);
824 ptr
->triggeredOnAWDL
= true;
827 // Browse on mDNSInterface_BLE is used to determine if there are one or more instances of the
828 // service type discoveryed over BLE. If this is the first instance, add the psuedo instance defined by BLEinstanceValue.
829 if (ptr
->InterfaceID
== mDNSInterface_BLE
)
831 xD2DAddToCache(kD2DSuccess
, 0, D2DBLETransport
, ptr
->key
, ptr
->keySize
, BLEinstanceValue
, BLEValueSize
);
834 addToResponseListForRequest(ptr
, response
);
839 // If a previous response from this peer had matched the browse, remove that response from the
840 // list now. If this is the last matching response, remove the corresponding key from the AWDL D2D plugin
841 if (removeFromResponseListForRequest(ptr
, response
) && (ptr
->ourResponses
== 0))
843 if (ptr
->InterfaceID
== mDNSInterface_BLE
)
845 xD2DRemoveFromCache(kD2DSuccess
, 0, D2DBLETransport
, ptr
->key
, ptr
->keySize
, BLEinstanceValue
, BLEValueSize
);
848 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
850 LogInfo("findMatchingBrowse: Last BLE response, disabling browse for %##s on AWDL", ptr
->name
.c
);
851 internal_stop_browsing_for_service(ptr
->InterfaceID
, & ptr
->name
, ptr
->type
, ptr
->flags
);
852 ptr
->triggeredOnAWDL
= false;
859 // Find each local registration that matches the service browse hash BLE response Bloom filter.
860 // Called on the CFRunLoop thread while handling a callback from CoreBluetooth.
861 // Caller should hold KQueueLock().
862 mDNSlocal
void findMatchingRegistration(responseList_t
*response
)
867 ptr
= BLERegistrationListHead
;
868 for ( ; ptr
; ptr
= ptr
->next
)
870 // See if we potentially match a corresponding browse in the beacon,
871 // thus, compare using the "browseHash" of our registration.
872 if ((ptr
->browseHash
& response
->peerBloomFilter
) == ptr
->browseHash
)
874 LogInfo("findMatchingRegistration: Incoming browse matched registration for: %##s", ptr
->name
.c
);
876 if (inResponseListForRequest(ptr
, response
))
878 LogInfo("findMatchingRegistration: Already on response list for registration: %##s", ptr
->name
.c
);
884 LogInfo("findMatchingRegistration: Adding to response list for registration: %##s", ptr
->name
.c
);
886 // Also pass the registration to the AWDL D2D plugin if this is the first matching peer browse for
887 // an auto triggered local registration.
888 if ((ptr
->ourResponses
== 0) && isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
890 LogInfo("findMatchingRegistration: First BLE response, triggering registration for %##s on AWDL", ptr
->name
.c
);
891 if (ptr
->resourceRecord
== 0)
893 LogInfo("findMatchingRegistration: resourceRecord pointer is NULL ??");
897 internal_start_advertising_service(ptr
->resourceRecord
, (ptr
->flags
| kDNSServiceFlagsIncludeAWDL
));
898 // indicate the registration has been applied to the AWDL interface
899 ptr
->triggeredOnAWDL
= true;
902 addToResponseListForRequest(ptr
, response
);
907 // If a previous response from this peer had matched the browse, remove that response from the
908 // list now. If this is the last matching response for a local auto triggered registration,
909 // remove the advertised key/value pairs from the AWDL D2D plugin.
910 if (removeFromResponseListForRequest(ptr
, response
) && (ptr
->ourResponses
== 0) && isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
))
912 LogInfo("findMatchingRegistration: Last BLE response, disabling registration for %##s on AWDL", ptr
->name
.c
);
914 // Restore the saved ARType and call into the AWDL D2D plugin to stop the corresponding record advertisements over AWDL.
915 internal_stop_advertising_service(ptr
->resourceRecord
, (ptr
->flags
| kDNSServiceFlagsIncludeAWDL
));
916 ptr
->triggeredOnAWDL
= false;
921 // If beacons for our registrations had been suppressed, see if we now have a match and need to restart them.
922 matchingPeer
= responseMatchesRegistrations();
923 if (suppressBeacons
&& matchingPeer
)
925 LogInfo("findMatchingRegistration: peer searching for our service, starting beacon transmission");
926 updateBeaconAndScanState();
928 if (suppressBeacons
== true)
929 LogInfo("findMatchingRegistration: NOTE: suppressBeacons is true after updateBeaconAndScanState() call ??");
931 // If we have only registrations, but no matching peers, we can suppress beacons until we get a matching peer beacon.
932 else if (!suppressBeacons
&& !matchingPeer
&& BLERegistrationListHead
&& !BLEBrowseListHead
)
934 LogInfo("findMatchingRegistration: no peer beacons match our registrations, suppressing beacon transmission");
935 suppressBeacons
= true;
941 // Time limit before a beacon is aged out of our received list.
942 #define MAX_RESPONSE_AGE 10
944 // If we have responses from peers that are more than MAX_RESPONSE_AGE seconds
945 // old, remove them since a peer with active requests should be beaconing multiple
946 // times per second if still within BLE range.
947 mDNSlocal
void removeStaleResponses(mDNSs32 currentTime
)
949 responseList_t
**ptr
;
951 for (unsigned int i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
953 ptr
= & BLEResponseListHeads
[i
];
956 if ((currentTime
- (*ptr
)->recievedTime
) > (MAX_RESPONSE_AGE
* mDNSPlatformOneSecond
))
958 responseList_t
* tmp
;
960 // Clear the Bloom filter so that it will be removed from any matching response list
961 // by the following calls.
962 (*ptr
)->peerBloomFilter
= 0;
964 LogInfo("removeStaleResponses: clearing stale response from peer MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
965 (*ptr
)->peerMac
.b
[0], (*ptr
)->peerMac
.b
[1], (*ptr
)->peerMac
.b
[2], (*ptr
)->peerMac
.b
[3], (*ptr
)->peerMac
.b
[4], (*ptr
)->peerMac
.b
[5]);
967 findMatchingBrowse(*ptr
);
968 findMatchingRegistration(*ptr
);
970 // Unlink and free the response structure
973 mDNSPlatformMemFree(tmp
);
975 // Move to the next response on this linked list.
977 ptr
= & (*ptr
)->next
;
982 // Called on CFRunLoop thread during CoreBluetooth beacon response processing.
983 // Thus, must call KQueueLock() prior to calling any core mDNSResponder routines to register records, etc.
984 void responseReceived(serviceHash_t peerBloomFilter
, mDNSEthAddr
* ptrToMAC
)
986 responseList_t
* ptr
;
989 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow
991 ptr
= *(findInResponseList(ptrToMAC
));
994 // Only add to list if peer is actively browsing or advertising.
997 LogInfo("responseReceived: First beacon of this type, adding to list");
998 LogInfo("responseReceived: peerBloomFilter = 0x%lx", peerBloomFilter
);
999 LogInfo("responseReceived: peer MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
1000 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
1002 ptr
= addToResponseList(peerBloomFilter
, ptrToMAC
);
1003 // Update the received time.
1004 ptr
->recievedTime
= mDNSStorage
.timenow
;
1005 // See if we are browsing for any of the peers advertised services.
1006 findMatchingBrowse(ptr
);
1007 // See if we have a registration that matches the peer's browse.
1008 findMatchingRegistration(ptr
);
1011 else // Have an entry from this MAC in the list.
1013 // Update the received time.
1014 ptr
->recievedTime
= mDNSStorage
.timenow
;
1016 if (ptr
->peerBloomFilter
== peerBloomFilter
)
1018 // A duplicate of a current entry.
1019 #if VERBOSE_BLE_DEBUG
1020 LogInfo("responseReceived: Duplicate of previous beacon, ignoring");
1021 LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
1022 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
1023 #endif // VERBOSE_BLE_DEBUG
1027 LogInfo("responseReceived: Update of previous beacon");
1028 LogInfo("responseReceived: peerBloomFilter = 0x%lx", peerBloomFilter
);
1029 LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
1030 ptrToMAC
->b
[0], ptrToMAC
->b
[1], ptrToMAC
->b
[2], ptrToMAC
->b
[3], ptrToMAC
->b
[4], ptrToMAC
->b
[5]);
1032 ptr
->peerBloomFilter
= peerBloomFilter
;
1033 findMatchingBrowse(ptr
);
1034 findMatchingRegistration(ptr
);
1037 // If peer is no longer browsing or advertising, remove from list.
1038 if (peerBloomFilter
== 0)
1040 LogInfo("responseReceived: Removing peer entry from the list");
1042 removeFromResponseList(ptrToMAC
);
1046 mDNS_Unlock(& mDNSStorage
); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
1047 KQueueUnlock("BLE responseReceived");
1050 #pragma mark - Client request handling
1052 void start_BLE_browse(mDNSInterfaceID InterfaceID
, const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
, mDNSu8
*key
, size_t keySize
)
1054 requestList_t
* ptr
;
1055 const domainname
*serviceType
= domain
;
1057 if (!EnableBLEBasedDiscovery
)
1059 LogMsg("start_BLE_browse: EnableBLEBasedDiscovery disabled");
1063 if (keySize
> MAX_KEY_SIZE
)
1065 LogMsg("start_BLE_browse: keySize = %d, maximum allowable is %d", keySize
, MAX_KEY_SIZE
);
1069 // Verify that the request to be auto triggered applies to AWDL, or is using the pseudo interface for
1070 // BLE threshold browsing.
1071 if (!isAutoTriggerRequest(InterfaceID
, flags
) && (InterfaceID
!= mDNSInterface_BLE
))
1073 LogMsg("start_BLE_browse: invalid request: InterfaceID = %d, flags = 0x%x", InterfaceID
, flags
);
1077 // Address records don't have a service type to hash and match on, so pass them directly to the D2D plugin.
1078 if ((type
== kDNSType_A
) || (type
== kDNSType_AAAA
))
1080 LogInfo("start_BLE_browse: Passing directly to D2D layer: %##s %s", domain
->c
, DNSTypeName(type
));
1081 internal_start_browsing_for_service(InterfaceID
, domain
, type
, flags
);
1085 // Skip the instance to get to the service type for non PTR records
1086 if (type
!= kDNSType_PTR
)
1087 serviceType
= SkipLeadingLabels(domain
, 1);
1089 LogInfo("start_BLE_browse: Starting BLE service type browse for: %##s %s", domain
->c
, DNSTypeName(type
));
1091 ptr
= addToRequestList(&BLEBrowseListHead
, domain
, type
, flags
);
1093 // If equivalent BLE browse is already running, just return.
1094 if (ptr
->refCount
> 1)
1096 LogInfo("start_BLE_browse: Dup of existing BLE browse.");
1100 if (!setBLEServiceHash(serviceType
, ptr
))
1102 LogInfo("setBLEServiceHash failed!");
1103 removeFromRequestList(&BLEBrowseListHead
, domain
, type
);
1107 // Save these for use in D2D plugin callback logic.
1108 memcpy(ptr
->key
, key
, keySize
);
1109 ptr
->keySize
= keySize
;
1110 ptr
->InterfaceID
= InterfaceID
;
1112 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1113 updateBeaconAndScanState();
1114 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1115 checkCachedResponses(ptr
, NULL
);
1119 // Return true if this is the last reference to the browse, false otherwise.
1120 bool stop_BLE_browse(mDNSInterfaceID InterfaceID
, const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
)
1122 (void) flags
; // not used initially
1123 requestList_t
* ptr
;
1124 bool lastReference
= false;
1126 if (!EnableBLEBasedDiscovery
)
1128 LogMsg("stop_BLE_browse: EnableBLEBasedDiscovery disabled");
1129 return lastReference
;
1132 // Address records don't have a service type to hash and match on, so pass them directly to the D2D plugin.
1133 if ((type
== kDNSType_A
) || (type
== kDNSType_AAAA
))
1135 LogInfo("stop_BLE_browse: Passing directly to D2D layer: %##s %s", domain
->c
, DNSTypeName(type
));
1136 internal_stop_browsing_for_service(InterfaceID
, domain
, type
, flags
);
1137 return lastReference
;
1140 LogInfo("stop_BLE_browse: Stopping BLE service type browse for: %##s %s", domain
->c
, DNSTypeName(type
));
1142 ptr
= *(findInRequestList(&BLEBrowseListHead
, domain
, type
));
1145 LogInfo("stop_BLE_browse: No matching browse found.");
1146 return lastReference
;
1149 // If this is the last reference for this browse, and it was autoTriggered on AWDL,
1150 // remove the request from the AWDL pluggin.
1151 if (ptr
->refCount
== 1)
1153 lastReference
= true;
1155 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
) && ptr
->triggeredOnAWDL
)
1157 internal_stop_browsing_for_service(ptr
->InterfaceID
, & ptr
->name
, ptr
->type
, ptr
->flags
);
1158 ptr
->triggeredOnAWDL
= false;
1162 removeFromRequestList(&BLEBrowseListHead
, domain
, type
);
1164 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1166 updateBeaconAndScanState();
1167 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1169 // If there are no active browse or registration requests, BLE scanning will be disabled.
1170 // Clear the list of responses received to remove any stale response state.
1171 if (BLEBrowseListHead
== NULL
&& BLERegistrationListHead
== 0)
1172 clearResponseLists();
1174 return lastReference
;
1177 void start_BLE_advertise(const ResourceRecord
*const resourceRecord
, const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
)
1179 requestList_t
* ptr
;
1180 const domainname
* serviceType
= domain
;
1182 if (!EnableBLEBasedDiscovery
)
1184 LogMsg("start_BLE_advertise: EnableBLEBasedDiscovery disabled");
1188 if (resourceRecord
== NULL
)
1190 LogInfo("start_BLE_advertise: NULL resourceRecord for: %##s %s, returning", domain
->c
, DNSTypeName(type
));
1194 // Verify that the request to be auto triggered applies to AWDL, or is using the pseudo interface for
1195 // BLE threshold browsing.
1196 if (!isAutoTriggerRequest(resourceRecord
->InterfaceID
, flags
) && (resourceRecord
->InterfaceID
!= mDNSInterface_BLE
))
1198 LogMsg("start_BLE_advertise: invalid request: InterfaceID = %d, flags = 0x%x", resourceRecord
->InterfaceID
, flags
);
1202 LogInfo("start_BLE_advertise: Starting BLE service type advertisement for: %##s %s", domain
->c
, DNSTypeName(type
));
1204 // Skip the instance to get to the service type for non PTR records
1205 if (type
!= kDNSType_PTR
)
1206 serviceType
= SkipLeadingLabels(domain
, 1);
1208 ptr
= addToRequestList(&BLERegistrationListHead
, domain
, type
, flags
);
1210 // If equivalent BLE registration is already running, just return.
1211 if (ptr
->refCount
> 1)
1213 LogInfo("start_BLE_advertise: Dup of existing BLE advertisement.");
1217 if (!setBLEServiceHash(serviceType
, ptr
))
1219 LogInfo("setBLEServiceHash failed!");
1220 removeFromRequestList(&BLERegistrationListHead
, domain
, type
);
1223 ptr
->resourceRecord
= resourceRecord
;
1224 ptr
->InterfaceID
= resourceRecord
->InterfaceID
;
1226 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1227 updateBeaconAndScanState();
1228 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1229 checkCachedResponses(NULL
, ptr
);
1232 void stop_BLE_advertise(const domainname
*const domain
, DNS_TypeValues type
, DNSServiceFlags flags
)
1234 (void) flags
; // not used initially
1235 requestList_t
* ptr
;
1236 bool lastReference
= false;
1238 LogInfo("stop_BLE_advertise: Stopping BLE service type advertisement for: %##s %s", domain
->c
, DNSTypeName(type
));
1240 // Get the request pointer from the indirect pointer returned.
1241 ptr
= *(findInRequestList(&BLERegistrationListHead
, domain
, type
));
1245 LogInfo("stop_BLE_advertise: No matching advertisement found.");
1249 // If this is the last reference for this registration, and it was autoTriggered on AWDL,
1250 // remove the request from the AWDL pluggin.
1251 if (ptr
->refCount
== 1)
1253 lastReference
= true;
1255 if (isAutoTriggerRequest(ptr
->InterfaceID
, ptr
->flags
) && ptr
->triggeredOnAWDL
)
1257 // And remove the corresponding advertisements from the AWDL D2D plugin if we had previously
1258 // passed this advertisement request to the plugin.
1259 internal_stop_advertising_service(ptr
->resourceRecord
, (ptr
->flags
| kDNSServiceFlagsIncludeAWDL
));
1260 ptr
->triggeredOnAWDL
= false;
1263 removeFromRequestList(&BLERegistrationListHead
, domain
, type
);
1265 mDNS_Lock(& mDNSStorage
); // Must lock to initialize mDNSStorage.timenow.
1266 // If this is the last reference for this registration, update advertising and browsing bits set in the beacon.
1268 updateBeaconAndScanState();
1269 mDNS_Unlock(& mDNSStorage
); // Updates mDNSStorage.NextScheduledEvent.
1271 // If there are no active browse or registration requests, BLE scanning will be disabled.
1272 // Clear the list of responses received to remove any stale response state.
1273 if (BLEBrowseListHead
== NULL
&& BLERegistrationListHead
== 0)
1274 clearResponseLists();
1278 #pragma mark - Unit test support routines
1280 // These unit test support routines are called from unittests/ framework
1281 // and are not compiled for the mDNSResponder runtime code paths.
1283 #define MAX_ENTRIES 42
1284 #define FAILED exit(1)
1286 mDNSlocal
void BLE_requestListTests(void)
1288 const domainname
*domainArray
[] = { (const domainname
*)"\x6" "_test0" "\x4" "_tcp" "\x5" "local",
1289 (const domainname
*)"\x6" "_test1" "\x4" "_tcp" "\x5" "local",
1290 (const domainname
*)"\x6" "_test2" "\x4" "_tcp" "\x5" "local",
1291 (const domainname
*)"\x6" "_test3" "\x4" "_tcp" "\x5" "local",
1292 (const domainname
*)"\x6" "_test4" "\x4" "_tcp" "\x5" "local",
1295 mDNSu16 type
= kDNSServiceType_PTR
;
1296 DNSServiceFlags flags
= 0;
1297 requestList_t
* ptr
;
1298 void * response
= 0;
1300 int numOfdomains
= sizeof(domainArray
)/sizeof(domainArray
[0]);
1302 printf("BLE_requestListTests() entry:\n");
1304 // Basic request list unit tests.
1305 for (i
= 0; i
< numOfdomains
; i
++)
1307 ptr
= addToRequestList(&BLEBrowseListHead
, domainArray
[i
], type
, flags
);
1311 printf("addToRequestList() FAILED:\n");
1315 for (i
= 0; i
< numOfdomains
; i
++)
1317 // should now find the entry
1318 if (*(findInRequestList(&BLEBrowseListHead
, domainArray
[i
], type
)) == 0)
1320 printf("findInRequestList() did not find valid entry FAILED:\n");
1323 // but not find an entry with the same domain, but different type
1324 if (*(findInRequestList(&BLEBrowseListHead
, domainArray
[i
], kDNSServiceType_NULL
)) != 0)
1326 printf("findInRequestList() invalid entry matched FAILED:\n");
1330 // remove all the entries
1331 for (i
= 0; i
< numOfdomains
; i
++)
1333 removeFromRequestList(&BLEBrowseListHead
, domainArray
[i
], type
);
1335 // and sanity check the list is now empty
1336 if (BLEBrowseListHead
)
1338 printf("BLEBrowseListHead not empty after all entries removed.\n");
1342 // Identical request reference count management tests.
1343 // Add identical requests to the list and verify the corresponding refCount is managed correctly
1344 for (i
= 0; i
< MAX_ENTRIES
; i
++)
1346 ptr
= addToRequestList(&BLEBrowseListHead
, domainArray
[0], type
, flags
);
1350 printf("addToRequestList() of duplicate request FAILED:\n");
1355 if (ptr
->refCount
!= MAX_ENTRIES
)
1357 printf("refCount = %d, should be %d\n", ptr
->refCount
, MAX_ENTRIES
);
1361 // Remove all but one entry
1362 for (i
= 0; i
< (MAX_ENTRIES
- 1); i
++)
1364 removeFromRequestList(&BLEBrowseListHead
, domainArray
[0], type
);
1366 if (ptr
->refCount
!= 1)
1368 printf("refCount = %d, should be %d\n", ptr
->refCount
, 1);
1372 // Basic response list unit tests.
1373 // Note that responses per request are not checked for duplicates at this level, so
1374 // we can unit test with the same (NULL) response pointer to add multiple responses.
1376 // add MAX_ENTRIES responses
1377 for (i
= 0; i
< MAX_ENTRIES
; i
++)
1378 addToResponseListForRequest(ptr
, response
);
1380 // remove the responses, counting that MAX_ENTRIES were removed
1382 while (inResponseListForRequest(ptr
, response
) && removeFromResponseListForRequest(ptr
, response
))
1386 if (i
!= MAX_ENTRIES
)
1388 printf("removed %d responses, should have been %d\n", i
, MAX_ENTRIES
);
1392 // response list should be empty at this point
1393 if (ptr
->ourResponses
)
1395 printf("response list should be empty\n");
1399 // add MAX_ENTRIES responses
1400 for (i
= 0; i
< MAX_ENTRIES
; i
++)
1401 addToResponseListForRequest(ptr
, response
);
1404 freeResponseListEntriesForRequest(ptr
);
1406 if (ptr
->ourResponses
)
1408 printf("freeResponseListEntriesForRequest() should have removed all responses\n");
1413 mDNSlocal mDNSEthAddr etherAddress
[] = {
1414 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
1415 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
1416 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
1417 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } },
1418 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 } },
1419 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 } },
1420 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06 } },
1421 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } },
1422 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 } },
1423 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 } },
1424 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a } },
1425 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b } },
1426 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c } },
1427 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d } },
1428 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e } },
1429 { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f } },
1432 mDNSlocal
void BLE_responseListTests(void)
1434 int numOfEtherAddresses
= sizeof(etherAddress
)/sizeof(etherAddress
[0]);
1437 printf("BLE_responseListTests() entry:\n");
1439 // Just use the index as to generate the peerBloomFilter value to vary it per entry.
1440 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1441 (void)addToResponseList(1 << i
, ðerAddress
[i
]);
1443 // Verify all entries are found.
1444 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1446 if (*(findInResponseList(ðerAddress
[i
])) == 0)
1448 printf("findInResponseList() did not find entry in list\n");
1453 // Remove all entries.
1454 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1455 removeFromResponseList(ðerAddress
[i
]);
1457 // Sanity check that all response lists are empty
1458 for (i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
1460 if (BLEResponseListHeads
[i
])
1462 printf("BLEResponseListHeads[%d] not empty after removeFromResponseList() calls \n", i
);
1467 // Add them back again.
1468 for (i
= 0; i
< numOfEtherAddresses
; i
++)
1469 (void)addToResponseList(1 << i
, ðerAddress
[i
]);
1471 // And verify that clearResponseLists() clears all entries.
1472 clearResponseLists();
1473 for (i
= 0; i
< RESPONSE_LIST_NUMBER
; i
++)
1475 if (BLEResponseListHeads
[i
])
1477 printf("BLEResponseListHeads[%d] not empty after clearResponseLists() call\n", i
);
1483 void BLE_unitTest(void)
1485 BLE_requestListTests();
1486 BLE_responseListTests();
1487 printf("All BLE.c unit tests PASSED.\n");
1492 #endif // ENABLE_BLE_TRIGGERED_BONJOUR