]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.m
mDNSResponder-1310.80.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / DomainBrowser / Shared / _CNDomainBrowser.m
1 /*
2 *
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18 #import "_CNDomainBrowser.h"
19 #import "CNDomainBrowserPathUtils.h"
20 #include <dns_sd.h>
21
22 const NSString * _CNSubDomainKey_defaultFlag = @"defaultFlag";
23 const NSString * _CNSubDomainKey_subPath = @"subPath";
24 const NSString * _CNSubDomainKey_reverseDomainPath = @"reverseDomainPath";
25
26 @interface _CNDomainBrowser ()
27
28 @property (assign) DNSServiceRef browseDomainR;
29 @property (strong) NSMutableDictionary * browseDomainD;
30
31 @property (weak) id<_CNDomainBrowserDelegate> delegate;
32
33 @end
34
35 @implementation _CNDomainBrowser
36
37 static void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
38
39 - (instancetype)initWithDelegate:(id<_CNDomainBrowserDelegate>)delegate
40 {
41 if (self = [super init])
42 {
43 _delegate = delegate;
44 [self _commonInit];
45 }
46 return(self);
47 }
48
49 - (void)_commonInit
50 {
51 self.browseDomainD = [NSMutableDictionary dictionary];
52 self.callbackQueue = dispatch_get_main_queue();
53 }
54
55 - (void)dealloc
56 {
57 [self stopBrowser];
58 }
59
60 - (void)startBrowser
61 {
62 if (!_browseDomainR)
63 {
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);
68
69 DNSServiceRef ref;
70 DNSServiceErrorType error;
71 if ((error = DNSServiceEnumerateDomains(&ref, self->_browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self)) != 0)
72 NSLog(@"DNSServiceEnumerateDomains failed err: %ld", error);
73 else
74 {
75 self->_browseDomainR = ref;
76 (void)DNSServiceSetDispatchQueue(self->_browseDomainR, queue);
77 }
78 });
79 }
80 }
81
82 - (void)stopBrowser
83 {
84 if (_browseDomainR)
85 {
86 DNSServiceRefDeallocate(_browseDomainR);
87 _browseDomainR = nil;
88 }
89 }
90
91 - (BOOL)foundInstanceInMoreThanLocalDomain
92 {
93 BOOL result = YES;
94
95 if( self.browseDomainD.count )
96 {
97 for( NSDictionary *next in [self.browseDomainD allValues] )
98 {
99 if( [next[_CNSubDomainKey_reverseDomainPath][0] isEqual: @"local"] ) continue;
100 else
101 {
102 result = YES;
103 break;
104 }
105 }
106 }
107
108 return( result );
109 }
110
111 - (NSArray *)defaultDomainPath
112 {
113 NSArray * revDomainArray = nil;
114
115 NSArray *defaults = [[self.browseDomainD allValues] filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @"(%K == %@)", _CNSubDomainKey_defaultFlag, @YES]];
116 if (defaults.count) revDomainArray = defaults[0][_CNSubDomainKey_reverseDomainPath];
117 if (!revDomainArray) revDomainArray = [NSArray arrayWithObject: @"local"]; // If no defaults found
118
119 return(revDomainArray);
120 }
121
122 - (NSArray *)flattenedDNSDomains
123 {
124 return([self.browseDomainD allKeys]);
125 }
126
127 - (NSArray *)subDomainsAtDomainPath:(NSArray *)domainPath
128 {
129 NSMutableDictionary * subs = [NSMutableDictionary dictionary];
130 for (NSDictionary * next in [self.browseDomainD allValues])
131 {
132 NSArray * bdomain = next[_CNSubDomainKey_reverseDomainPath];
133 if (bdomain.count > domainPath.count)
134 {
135 BOOL match = YES;
136 for (NSUInteger i = 0 ; i < domainPath.count ; i++)
137 {
138 if (![bdomain[i] isEqualToString: domainPath[i]]) { match = NO; break; }
139 }
140 if (match)
141 {
142 NSString * key = bdomain[domainPath.count];
143 [subs setObject: @{ _CNSubDomainKey_subPath: key, _CNSubDomainKey_defaultFlag: next[_CNSubDomainKey_defaultFlag] } forKey: key];
144 }
145 }
146 }
147 return([subs allValues]);
148 }
149
150 - (void) reloadBrowser
151 {
152 if ([_delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
153 {
154 dispatch_async(self.callbackQueue, ^{
155 [self->_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
156 });
157 }
158 }
159
160 - (BOOL)isBrowsing
161 {
162 return(_browseDomainR != nil);
163 }
164
165 #pragma mark - Dispatch
166
167 static void finalizer(void * context)
168 {
169 _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
170 // NSLog(@"finalizer: %@", self);
171 (void)CFBridgingRelease((__bridge void *)self);
172 }
173
174 #pragma mark - Commands
175
176 #pragma mark - Static Callbacks
177
178 static void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
179 const char *replyDomain, void *context)
180 {
181 (void)sdRef;
182 (void)interfaceIndex;
183 (void)errorCode;
184
185 if (!*replyDomain) return;
186
187 _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
188 NSString *key = [NSString stringWithUTF8String: replyDomain];
189
190 if (self.ignoreLocal && [key isEqualToString: @"local."]) goto exit;
191 if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."]) goto exit;
192
193 if (!(flags & kDNSServiceFlagsAdd))
194 {
195 [self.browseDomainD removeObjectForKey:key];
196 }
197 else
198 {
199 NSArray * pathArray = DNSDomainToDomainPath(key);
200 [self.browseDomainD setObject: @{ _CNSubDomainKey_reverseDomainPath: pathArray,
201 _CNSubDomainKey_defaultFlag: (flags & kDNSServiceFlagsDefault) ? @YES : @NO }
202 forKey: key];
203 }
204
205 exit:
206 if (!(flags & kDNSServiceFlagsMoreComing))
207 {
208 [self reloadBrowser];
209 }
210 }
211
212 @end