1.1 --- a/Bonjour/MYBonjourBrowser.m Wed Apr 22 16:45:39 2009 -0700
1.2 +++ b/Bonjour/MYBonjourBrowser.m Mon Apr 27 09:03:56 2009 -0700
1.3 @@ -8,13 +8,24 @@
1.4
1.5 #import "MYBonjourBrowser.h"
1.6 #import "MYBonjourService.h"
1.7 +#import "ExceptionUtils.h"
1.8 #import "Test.h"
1.9 #import "Logging.h"
1.10 +#import <dns_sd.h>
1.11
1.12
1.13 +static void browseCallback (DNSServiceRef sdRef,
1.14 + DNSServiceFlags flags,
1.15 + uint32_t interfaceIndex,
1.16 + DNSServiceErrorType errorCode,
1.17 + const char *serviceName,
1.18 + const char *regtype,
1.19 + const char *replyDomain,
1.20 + void *context);
1.21 +
1.22 @interface MYBonjourBrowser ()
1.23 @property BOOL browsing;
1.24 -@property (retain) NSError* error;
1.25 +- (void) _updateServiceList;
1.26 @end
1.27
1.28
1.29 @@ -26,9 +37,8 @@
1.30 Assert(serviceType);
1.31 self = [super init];
1.32 if (self != nil) {
1.33 + self.continuous = YES;
1.34 _serviceType = [serviceType copy];
1.35 - _browser = [[NSNetServiceBrowser alloc] init];
1.36 - _browser.delegate = self;
1.37 _services = [[NSMutableSet alloc] init];
1.38 _addServices = [[NSMutableSet alloc] init];
1.39 _rmvServices = [[NSMutableSet alloc] init];
1.40 @@ -41,11 +51,7 @@
1.41 - (void) dealloc
1.42 {
1.43 LogTo(Bonjour,@"DEALLOC BonjourBrowser");
1.44 - [_browser stop];
1.45 - _browser.delegate = nil;
1.46 - [_browser release];
1.47 [_serviceType release];
1.48 - [_error release];
1.49 [_services release];
1.50 [_addServices release];
1.51 [_rmvServices release];
1.52 @@ -53,40 +59,64 @@
1.53 }
1.54
1.55
1.56 -@synthesize browsing=_browsing, error=_error, services=_services, serviceClass=_serviceClass;
1.57 +@synthesize browsing=_browsing, services=_services, serviceClass=_serviceClass;
1.58
1.59
1.60 -- (void) start
1.61 +- (NSString*) description
1.62 {
1.63 - [_browser searchForServicesOfType: _serviceType inDomain: @"local."];
1.64 + return $sprintf(@"%@[%@]", self.class,_serviceType);
1.65 }
1.66
1.67 -- (void) stop
1.68 -{
1.69 - [_browser stop];
1.70 +
1.71 +- (DNSServiceRef) createServiceRef {
1.72 + DNSServiceRef serviceRef = NULL;
1.73 + self.error = DNSServiceBrowse(&serviceRef, 0, 0,
1.74 + _serviceType.UTF8String, NULL,
1.75 + &browseCallback, self);
1.76 + return serviceRef;
1.77 }
1.78
1.79
1.80 -- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)netServiceBrowser
1.81 -{
1.82 - LogTo(Bonjour,@"%@ started browsing",self);
1.83 - self.browsing = YES;
1.84 +- (void) priv_gotError: (DNSServiceErrorType)errorCode {
1.85 + LogTo(Bonjour,@"%@ got error %i", self,errorCode);
1.86 + self.error = errorCode;
1.87 }
1.88
1.89 -- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)netServiceBrowser
1.90 +- (void) priv_gotServiceName: (NSString*)serviceName
1.91 + type: (NSString*)regtype
1.92 + domain: (NSString*)domain
1.93 + interface: (uint32_t)interfaceIndex
1.94 + flags: (DNSServiceFlags)flags
1.95 {
1.96 - LogTo(Bonjour,@"%@ stopped browsing",self);
1.97 - self.browsing = NO;
1.98 -}
1.99 -
1.100 -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
1.101 - didNotSearch:(NSDictionary *)errorDict
1.102 -{
1.103 - NSString *domain = [errorDict objectForKey: NSNetServicesErrorDomain];
1.104 - int err = [[errorDict objectForKey: NSNetServicesErrorCode] intValue];
1.105 - self.error = [NSError errorWithDomain: domain code: err userInfo: nil];
1.106 - LogTo(Bonjour,@"%@ got error: ",self,self.error);
1.107 - self.browsing = NO;
1.108 + // Create (or reuse existing) MYBonjourService object:
1.109 + MYBonjourService *service = [[_serviceClass alloc] initWithName: serviceName
1.110 + type: regtype
1.111 + domain: domain
1.112 + interface: interfaceIndex];
1.113 + MYBonjourService *existingService = [_services member: service];
1.114 + if( existingService ) {
1.115 + [service release];
1.116 + service = [existingService retain];
1.117 + }
1.118 +
1.119 + // Add it to the add/remove sets:
1.120 + NSMutableSet *addTo, *removeFrom;
1.121 + if (flags & kDNSServiceFlagsAdd) {
1.122 + addTo = _addServices;
1.123 + removeFrom = _rmvServices;
1.124 + } else {
1.125 + addTo = _rmvServices;
1.126 + removeFrom = _addServices;
1.127 + }
1.128 + if( [removeFrom containsObject: service] )
1.129 + [removeFrom removeObject: service];
1.130 + else
1.131 + [addTo addObject: service];
1.132 + [service release];
1.133 +
1.134 + // After a round of updates is done, do the update:
1.135 + if( ! (flags & kDNSServiceFlagsMoreComing) )
1.136 + [self _updateServiceList];
1.137 }
1.138
1.139
1.140 @@ -117,42 +147,26 @@
1.141 }
1.142
1.143
1.144 -- (void) _handleService: (NSNetService*)netService
1.145 - addTo: (NSMutableSet*)addTo
1.146 - removeFrom: (NSMutableSet*)removeFrom
1.147 - moreComing: (BOOL)moreComing
1.148 +static void browseCallback (DNSServiceRef sdRef,
1.149 + DNSServiceFlags flags,
1.150 + uint32_t interfaceIndex,
1.151 + DNSServiceErrorType errorCode,
1.152 + const char *serviceName,
1.153 + const char *regtype,
1.154 + const char *replyDomain,
1.155 + void *context)
1.156 {
1.157 - // Wrap the NSNetService in a BonjourService, using an existing instance if possible:
1.158 - MYBonjourService *service = [[_serviceClass alloc] initWithNetService: netService];
1.159 - MYBonjourService *existingService = [_services member: service];
1.160 - if( existingService ) {
1.161 - [service release];
1.162 - service = [existingService retain];
1.163 - }
1.164 -
1.165 - if( [removeFrom containsObject: service] )
1.166 - [removeFrom removeObject: service];
1.167 - else
1.168 - [addTo addObject: service];
1.169 - [service release];
1.170 - if( ! moreComing )
1.171 - [self _updateServiceList];
1.172 -}
1.173 -
1.174 -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
1.175 - didFindService:(NSNetService *)netService
1.176 - moreComing:(BOOL)moreComing
1.177 -{
1.178 - //LogTo(Bonjour,@"Add service %@",netService);
1.179 - [self _handleService: netService addTo: _addServices removeFrom: _rmvServices moreComing: moreComing];
1.180 -}
1.181 -
1.182 -- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser
1.183 - didRemoveService:(NSNetService *)netService
1.184 - moreComing:(BOOL)moreComing
1.185 -{
1.186 - //LogTo(Bonjour,@"Remove service %@",netService);
1.187 - [self _handleService: netService addTo: _rmvServices removeFrom: _addServices moreComing: moreComing];
1.188 + @try{
1.189 + //LogTo(Bonjour,@"browseCallback (error=%i, name='%s')", errorCode,serviceName);
1.190 + if (errorCode)
1.191 + [(MYBonjourBrowser*)context priv_gotError: errorCode];
1.192 + else
1.193 + [(MYBonjourBrowser*)context priv_gotServiceName: [NSString stringWithUTF8String: serviceName]
1.194 + type: [NSString stringWithUTF8String: regtype]
1.195 + domain: [NSString stringWithUTF8String: replyDomain]
1.196 + interface: interfaceIndex
1.197 + flags: flags];
1.198 + }catchAndReport(@"Bonjour");
1.199 }
1.200
1.201
1.202 @@ -163,6 +177,11 @@
1.203 #pragma mark -
1.204 #pragma mark TESTING:
1.205
1.206 +#if DEBUG
1.207 +
1.208 +#import "MYBonjourQuery.h"
1.209 +#import "MYAddressLookup.h"
1.210 +
1.211 @interface BonjourTester : NSObject
1.212 {
1.213 MYBonjourBrowser *_browser;
1.214 @@ -175,7 +194,7 @@
1.215 {
1.216 self = [super init];
1.217 if (self != nil) {
1.218 - _browser = [[MYBonjourBrowser alloc] initWithServiceType: @"_http._tcp"];
1.219 + _browser = [[MYBonjourBrowser alloc] initWithServiceType: @"_presence._tcp"];
1.220 [_browser addObserver: self forKeyPath: @"services" options: NSKeyValueObservingOptionNew context: NULL];
1.221 [_browser addObserver: self forKeyPath: @"browsing" options: NSKeyValueObservingOptionNew context: NULL];
1.222 [_browser start];
1.223 @@ -199,7 +218,11 @@
1.224 if( [[change objectForKey: NSKeyValueChangeKindKey] intValue]==NSKeyValueChangeInsertion ) {
1.225 NSSet *newServices = [change objectForKey: NSKeyValueChangeNewKey];
1.226 for( MYBonjourService *service in newServices ) {
1.227 - LogTo(Bonjour,@" --> %@ : TXT=%@", service,service.txtRecord);
1.228 + NSString *hostname = service.hostname; // block till it's resolved
1.229 + Log(@"##### %@ : at %@:%hu, TXT=%@",
1.230 + service, hostname, service.port, service.txtRecord);
1.231 + service.addressLookup.continuous = YES;
1.232 + [service queryForRecord: kDNSServiceType_NULL];
1.233 }
1.234 }
1.235 }
1.236 @@ -208,12 +231,15 @@
1.237 @end
1.238
1.239 TestCase(Bonjour) {
1.240 + EnableLogTo(Bonjour,YES);
1.241 + EnableLogTo(DNS,YES);
1.242 [NSRunLoop currentRunLoop]; // create runloop
1.243 BonjourTester *tester = [[BonjourTester alloc] init];
1.244 - [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 15]];
1.245 + [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1500]];
1.246 [tester release];
1.247 }
1.248
1.249 +#endif
1.250
1.251
1.252 /*