* Refactored MYPortMapper to use a new abstract base class MYDNSService; that way I can re-use it later for implementing Bonjour.
* Fixed issue #1: a memory leak in BLIPProperties, reported by codechemist.
5 // Created by Jens Alfke on 1/22/08.
6 // Copyright 2008 Jens Alfke. All rights reserved.
9 #import "MYBonjourService.h"
11 #import "ConcurrentOperation.h"
16 NSString* const kBonjourServiceResolvedAddressesNotification = @"BonjourServiceResolvedAddresses";
19 @interface MYBonjourService ()
20 @property (copy) NSSet* addresses;
23 @interface MYBonjourResolveOperation ()
24 @property (assign) MYBonjourService *service;
25 @property (retain) NSSet *addresses;
30 @implementation MYBonjourService
33 - (id) initWithNetService: (NSNetService*)netService
37 _netService = [netService retain];
38 _netService.delegate = self;
45 Log(@"DEALLOC %@",self);
46 _netService.delegate = nil;
47 [_netService release];
54 - (NSString*) description
56 return $sprintf(@"%@['%@'.%@%@]", self.class,self.name,_netService.type,_netService.domain);
60 - (NSComparisonResult) compare: (id)obj
62 return [self.name caseInsensitiveCompare: [obj name]];
66 - (NSNetService*) netService {return _netService;}
67 - (BOOL) isEqual: (id)obj {return [obj isKindOfClass: [MYBonjourService class]] && [_netService isEqual: [obj netService]];}
68 - (NSUInteger) hash {return _netService.hash;}
69 - (NSString*) name {return _netService.name;}
74 LogTo(Bonjour,@"Added %@",_netService);
79 LogTo(Bonjour,@"Removed %@",_netService);
80 [_netService stopMonitoring];
81 _netService.delegate = nil;
92 #pragma mark TXT RECORD:
95 - (NSDictionary*) txtRecord
97 [_netService startMonitoring];
101 - (void) txtRecordChanged
103 // no-op (this is here for subclassers to override)
106 - (NSString*) txtStringForKey: (NSString*)key
108 NSData *value = [self.txtRecord objectForKey: key];
111 if( ! [value isKindOfClass: [NSData class]] ) {
112 Warn(@"TXT dictionary has unexpected value type: %@",value.class);
115 NSString *str = [[NSString alloc] initWithData: value encoding: NSUTF8StringEncoding];
117 str = [[NSString alloc] initWithData: value encoding: NSWindowsCP1252StringEncoding];
118 return [str autorelease];
122 - (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)data
124 NSDictionary *txtDict = [NSNetService dictionaryFromTXTRecordData: data];
125 if( ! $equal(txtDict,_txtRecord) ) {
126 LogTo(Bonjour,@"%@ got TXT record (%u bytes)",self,data.length);
127 [self willChangeValueForKey: @"txtRecord"];
128 setObj(&_txtRecord,txtDict);
129 [self didChangeValueForKey: @"txtRecord"];
130 [self txtRecordChanged];
136 #pragma mark ADDRESS RESOLUTION:
139 #define kAddressResolveTimeout 10.0
140 #define kAddressExpirationInterval 60.0
141 #define kAddressErrorRetryInterval 5.0
146 if( _addresses && CFAbsoluteTimeGetCurrent() >= _addressesExpireAt ) {
147 setObj(&_addresses,nil); // eww, toss 'em and get new ones
154 - (MYBonjourResolveOperation*) resolve
157 LogTo(Bonjour,@"Resolving %@",self);
158 _resolveOp = [[MYBonjourResolveOperation alloc] init];
159 _resolveOp.service = self;
162 Assert(_netService.delegate=self);
163 [_netService resolveWithTimeout: kAddressResolveTimeout];
168 - (void) setAddresses: (NSSet*)addresses
170 setObj(&_addresses,addresses);
174 - (void) _finishedResolving: (NSSet*)addresses expireIn: (NSTimeInterval)expirationInterval
176 _addressesExpireAt = CFAbsoluteTimeGetCurrent() + expirationInterval;
177 self.addresses = addresses;
178 _resolveOp.addresses = addresses;
180 [_resolveOp release];
185 - (void)netServiceDidResolveAddress:(NSNetService *)sender
187 // Convert the raw sockaddrs into IPAddress objects:
188 NSMutableSet *addresses = [NSMutableSet setWithCapacity: 2];
189 for( NSData *rawAddr in _netService.addresses ) {
190 IPAddress *addr = [[IPAddress alloc] initWithSockAddr: rawAddr.bytes];
192 [addresses addObject: addr];
196 LogTo(Bonjour,@"Resolved %@: %@",self,addresses);
197 [self _finishedResolving: addresses expireIn: kAddressExpirationInterval];
200 - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
202 LogTo(Bonjour,@"Error resolving %@ -- %@",self,errorDict);
203 [self _finishedResolving: [NSArray array] expireIn: kAddressErrorRetryInterval];
206 - (void)netServiceDidStop:(NSNetService *)sender
208 LogTo(Bonjour,@"Resolve stopped for %@",self);
209 [self _finishedResolving: [NSArray array] expireIn: kAddressErrorRetryInterval];
218 @implementation MYBonjourResolveOperation
220 @synthesize service=_service, addresses=_addresses;
224 [_addresses release];
232 Copyright (c) 2008-2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
234 Redistribution and use in source and binary forms, with or without modification, are permitted
235 provided that the following conditions are met:
237 * Redistributions of source code must retain the above copyright notice, this list of conditions
238 and the following disclaimer.
239 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
240 and the following disclaimer in the documentation and/or other materials provided with the
243 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
244 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
245 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
246 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
247 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
248 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
249 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
250 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.