3 * Copyright (c) 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 #import "_CNDomainBrowser.h"
19 #import "CNDomainBrowserPathUtils.h"
22 const NSString * _CNSubDomainKey_defaultFlag = @"defaultFlag";
23 const NSString * _CNSubDomainKey_subPath = @"subPath";
24 const NSString * _CNSubDomainKey_reverseDomainPath = @"reverseDomainPath";
26 @interface _CNDomainBrowser ()
28 @property (assign) DNSServiceRef browseDomainR;
29 @property (strong) NSMutableDictionary * browseDomainD;
31 @property (weak) id<_CNDomainBrowserDelegate> delegate;
35 @implementation _CNDomainBrowser
37 void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
39 - (instancetype)initWithDelegate:(id<_CNDomainBrowserDelegate>)delegate
41 if (self = [super init])
51 self.browseDomainD = [NSMutableDictionary dictionary];
52 self.callbackQueue = dispatch_get_main_queue();
64 dispatch_async(dispatch_get_main_queue(), ^{
65 dispatch_queue_t queue = dispatch_queue_create("DNSServiceEnumerateDomains", DISPATCH_QUEUE_PRIORITY_DEFAULT);
66 dispatch_set_context(queue, (void *)CFBridgingRetain(self));
67 dispatch_set_finalizer_f(queue, finalizer);
70 if (DNSServiceEnumerateDomains(&ref, _browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self))
71 NSLog(@"DNSServiceEnumerateDomains failed");
75 (void)DNSServiceSetDispatchQueue(_browseDomainR, queue);
85 DNSServiceRefDeallocate(_browseDomainR);
90 - (NSArray *)defaultDomainPath
92 NSArray * revDomainArray = nil;
94 NSArray *defaults = [[self.browseDomainD allValues] filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @"(%K == %@)", _CNSubDomainKey_defaultFlag, @YES]];
95 if (defaults.count) revDomainArray = defaults[0][_CNSubDomainKey_reverseDomainPath];
96 if (!revDomainArray) revDomainArray = [NSArray arrayWithObject: @"local"]; // If no defaults found
98 return(revDomainArray);
101 - (NSArray *)flattenedDNSDomains
103 return([self.browseDomainD allKeys]);
106 - (NSArray *)subDomainsAtDomainPath:(NSArray *)domainPath
108 NSMutableDictionary * subs = [NSMutableDictionary dictionary];
109 for (NSDictionary * next in [self.browseDomainD allValues])
111 NSArray * bdomain = next[_CNSubDomainKey_reverseDomainPath];
112 if (bdomain.count > domainPath.count)
115 for (NSUInteger i = 0 ; i < domainPath.count ; i++)
117 if (![bdomain[i] isEqualToString: domainPath[i]]) { match = NO; break; }
121 NSString * key = bdomain[domainPath.count];
122 [subs setObject: @{ _CNSubDomainKey_subPath: key, _CNSubDomainKey_defaultFlag: next[_CNSubDomainKey_defaultFlag] } forKey: key];
126 return([subs allValues]);
129 - (void) reloadBrowser
131 if ([_delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
133 dispatch_async(self.callbackQueue, ^{
134 [_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
141 return(_browseDomainR != nil);
144 #pragma mark - Dispatch
146 static void finalizer(void * context)
148 _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
149 NSLog(@"finalizer: %@", self);
150 (void)CFBridgingRelease((__bridge void *)self);
153 #pragma mark - Commands
155 #pragma mark - Static Callbacks
157 void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
158 const char *replyDomain, void *context)
161 (void)interfaceIndex;
164 if (!*replyDomain) return;
166 _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
167 NSString *key = [NSString stringWithUTF8String: replyDomain];
169 if (self.ignoreLocal && [key isEqualToString: @"local."]) return;
170 if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."]) return;
172 if (!(flags & kDNSServiceFlagsAdd))
174 [self.browseDomainD removeObjectForKey:key];
178 NSArray * pathArray = DNSDomainToDomainPath(key);
179 [self.browseDomainD setObject: @{ _CNSubDomainKey_reverseDomainPath: pathArray,
180 _CNSubDomainKey_defaultFlag: (flags & kDNSServiceFlagsDefault) ? @YES : @NO }
184 if (!(flags & kDNSServiceFlagsMoreComing))
186 [self reloadBrowser];