1
/* Implementation for NSNetServices for GNUstep
2
Copyright (C) 2006 Free Software Foundation, Inc.
4
Written by: Chris B. Vetter
7
This file is part of the GNUstep Base Library.
9
This library is free software; you can redistribute it and/or
10
modify it under the terms of the GNU Library General Public
11
License as published by the Free Software Foundation; either
12
version 2 of the License, or (at your option) any later version.
14
This library is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
Library General Public License for more details.
19
You should have received a copy of the GNU Library General Public
20
License along with this library; if not, write to the Free
21
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25
#import "Foundation/NSNetServices.h"
26
#import "Foundation/NSData.h"
27
#import "Foundation/NSDebug.h"
28
#import "Foundation/NSNull.h"
29
#import "Foundation/NSRunLoop.h"
30
#import "Foundation/NSStream.h"
31
#import "Foundation/NSTimer.h"
32
#import "Foundation/NSValue.h"
33
#if defined(_REENTRANT)
34
#import "GNUstepBase/GSLock.h"
37
#import <dns_sd.h> // Apple's DNS Service Discovery
40
#import <sys/socket.h> // AF_INET / AF_INET6
42
#import <netinet/in.h> // struct sockaddr_in / sockaddr_in6
43
#import <arpa/inet.h> // inet_pton(3)
49
#if ! defined(INET6_ADDRSTRLEN)
50
# define INET6_ADDRSTRLEN 46
53
// trigger runloop timer every INTERVAL seconds
55
#define SHORTTIMEOUT 0.25
57
// debugging stuff and laziness on my part
59
# define INTERNALTRACE NSDebugLLog(@"Trace", @"%s", __PRETTY_FUNCTION__)
60
# define LOG(f, args...) NSDebugLLog(@"NSNetServices", f, ##args)
62
# define INTERNALTRACE
63
# define LOG(f, args...)
66
#if ! defined(VERSION)
67
# define VERSION (((GNUSTEP_BASE_MAJOR_VERSION * 100) \
68
+ GNUSTEP_BASE_MINOR_VERSION) * 100) \
69
+ GNUSTEP_BASE_SUBMINOR_VERSION
72
#define SETVERSION(aClass) \
74
if (self == [aClass class]) { [self setVersion: VERSION]; } \
75
else { [self doesNotRecognizeSelector: _cmd]; } \
78
#if defined(_REENTRANT)
79
# define THE_LOCK GSLazyRecursiveLock *lock
80
# define CREATELOCK(x) x->lock = [GSLazyRecursiveLock new]
81
# define LOCK(x) [x->lock lock]
82
# define UNLOCK(x) [x->lock unlock]
83
# define DESTROYLOCK(x) DESTROY(x->lock)
85
# define THE_LOCK /* nothing */
86
# define CREATELOCK(x) /* nothing */
87
# define LOCK(x) /* nothing */
88
# define UNLOCK(x) /* nothing */
89
# define DESTROYLOCK(x) /* nothing */
96
typedef struct _Browser // The actual NSNetServiceBrowser
101
NSString *runloopmode;
102
NSTimer *timer; // to control the runloop
104
NSMutableDictionary *services;
105
// List of found services.
106
// Key is <_name_type_domain> and value is an initialized NSNetService.
111
typedef struct _Service // The actual NSNetService
116
NSString *runloopmode;
117
NSTimer *timer, // to control the runloop
118
*timeout; // to time-out the resolve
120
NSMutableDictionary *info;
121
// The service's information, keys are
126
// - Addresses (mutable array)
129
NSMutableArray *foundAddresses; // array of char*
131
int interfaceIndex, // should also be in 'info'
134
id monitor; // NSNetServiceMonitor
136
BOOL isPublishing, // true if publishing service
137
isMonitoring; // true if monitoring
140
typedef struct _Monitor // The actual NSNetServiceMonitor
145
NSString *runloopmode;
146
NSTimer *timer; // to control the runloop
154
* This key identifies the most recent error.
156
NSString * const NSNetServicesErrorCode = @"NSNetServicesErrorCode";
159
* This key identifies the originator of the error.
161
NSString * const NSNetServicesErrorDomain = @"NSNetServicesErrorDomain";
171
@interface NSNetServiceMonitor : NSObject
174
void * _netServiceMonitor;
179
- (id) initWithDelegate: (id) delegate;
181
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
182
forMode: (NSString *) mode;
183
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
184
forMode: (NSString *) mode;
195
static NSDictionary *CreateError(id sender, int errorCode);
197
static int ConvertError(int errorCode);
199
static void DNSSD_API
200
// used by NSNetServiceBrowser
201
EnumerationCallback(DNSServiceRef sdRef,
202
DNSServiceFlags flags,
203
uint32_t interfaceIndex,
204
DNSServiceErrorType errorCode,
205
const char *replyDomain,
208
static void DNSSD_API
209
BrowserCallback(DNSServiceRef sdRef,
210
DNSServiceFlags flags,
211
uint32_t interfaceIndex,
212
DNSServiceErrorType errorCode,
213
const char *replyName,
214
const char *replyType,
215
const char *replyDomain,
218
static void DNSSD_API
219
// used by NSNetService
220
ResolverCallback(DNSServiceRef sdRef,
221
DNSServiceFlags flags,
222
uint32_t interfaceIndex,
223
DNSServiceErrorType errorCode,
224
const char *fullname,
225
const char *hosttarget,
228
const char *txtRecord,
231
static void DNSSD_API
232
RegistrationCallback(DNSServiceRef sdRef,
233
DNSServiceFlags flags,
234
DNSServiceErrorType errorCode,
240
static void DNSSD_API
241
// used by NSNetService and NSNetServiceMonitor
242
QueryCallback(DNSServiceRef sdRef,
243
DNSServiceFlags flags,
244
uint32_t interfaceIndex,
245
DNSServiceErrorType errorCode,
246
const char *fullname,
254
/***************************************************************************
260
@implementation NSNetServiceBrowser
263
* <em>Description forthcoming</em>
272
SETVERSION(NSNetServiceBrowser);
275
LOG(@"%@ may NOT be thread-safe!", [self class]);
280
/***************************************************************************
287
* <em>Description forthcoming</em>
298
browser = (Browser *) _reserved;
302
if (browser->runloop)
304
[self removeFromRunLoop: browser->runloop
305
forMode: browser->runloopmode];
310
[browser->timer invalidate];
311
DESTROY(browser->timer);
314
if (_netServiceBrowser)
316
DNSServiceRefDeallocate(_netServiceBrowser);
317
_netServiceBrowser = NULL;
320
[browser->services removeAllObjects];
326
* <em>Description forthcoming</em>
331
- (void) executeWithError: (DNSServiceErrorType) err
337
browser = (Browser *) _reserved;
341
if (kDNSServiceErr_NoError == err)
343
[self netServiceBrowserWillSearch: self];
345
if (! browser->runloop)
347
[self scheduleInRunLoop: [NSRunLoop currentRunLoop]
348
forMode: NSDefaultRunLoopMode];
351
[browser->runloop addTimer: browser->timer
352
forMode: browser->runloopmode];
354
[browser->timer fire];
356
else // notify the delegate of the error
358
[self netServiceBrowser: self
359
didNotSearch: CreateError(self, err)];
366
* <em>Description forthcoming</em>
371
- (void) searchForDomain: (int) aFlag
373
DNSServiceErrorType err = kDNSServiceErr_NoError;
378
browser = (Browser *) _reserved;
386
err = NSNetServicesInvalidError;
392
err = NSNetServicesActivityInProgress;
396
err = DNSServiceEnumerateDomains((DNSServiceRef *)&_netServiceBrowser,
398
browser->interfaceIndex,
406
[self executeWithError: err];
410
* <em>Description forthcoming</em>
415
- (void) enumCallback: (DNSServiceRef) sdRef
416
flags: (DNSServiceFlags) flags
417
interface: (uint32_t) interfaceIndex
418
error: (DNSServiceErrorType) errorCode
419
domain: (const char *) replyDomain
425
browser = (Browser *) _reserved;
429
if (_netServiceBrowser)
435
[self netServiceBrowser: self
436
didNotSearch: CreateError(self, errorCode)];
446
more = flags & kDNSServiceFlagsMoreComing;
448
browser->interfaceIndex = interfaceIndex;
450
domain = [NSString stringWithUTF8String: replyDomain];
452
if (flags & kDNSServiceFlagsAdd)
454
LOG(@"Found domain <%s>", replyDomain);
456
[self netServiceBrowser: self
457
didFindDomain: domain
460
else // kDNSServiceFlagsRemove
462
LOG(@"Removed domain <%s>", replyDomain);
464
[self netServiceBrowser: self
465
didRemoveDomain: domain
475
* <em>Description forthcoming</em>
480
- (void) browseCallback: (DNSServiceRef) sdRef
481
flags: (DNSServiceFlags) flags
482
interface: (uint32_t) interfaceIndex
483
error: (DNSServiceErrorType) errorCode
484
name: (const char *) replyName
485
type: (const char *) replyType
486
domain: (const char *) replyDomain
492
browser = (Browser *) _reserved;
496
if (_netServiceBrowser)
502
[self netServiceBrowser: self
503
didNotSearch: CreateError(self, errorCode)];
507
NSNetService *service = nil;
508
NSString *domain = nil;
509
NSString *type = nil;
510
NSString *name = nil;
512
BOOL more = (flags & kDNSServiceFlagsMoreComing);
514
browser->interfaceIndex = interfaceIndex;
516
if (nil == browser->services)
519
= [[NSMutableDictionary alloc] initWithCapacity: 1];
522
domain = [NSString stringWithUTF8String: replyDomain];
523
type = [NSString stringWithUTF8String: replyType];
524
name = [NSString stringWithUTF8String: replyName];
526
key = [NSString stringWithFormat: @"%@%@%@", name, type, domain];
528
if (flags & kDNSServiceFlagsAdd)
530
service = [[NSNetService alloc] initWithDomain: domain
536
LOG(@"Found service <%s>", replyName);
538
[self netServiceBrowser: self
539
didFindService: service
542
[browser->services setObject: service
545
[service autorelease];
549
LOG(@"WARNING: Could not create an NSNetService for <%s>",
553
else // kDNSServiceFlagsRemove
555
service = [browser->services objectForKey: key];
559
LOG(@"Removed service <%@>", [service name]);
561
[self netServiceBrowser: self
562
didRemoveService: service
567
LOG(@"WARNING: Could not find <%@> in list", key);
576
* <em>Description forthcoming</em>
581
- (void) loop: (id) sender
584
struct timeval tout = { 0 };
586
DNSServiceErrorType err = kDNSServiceErr_NoError;
588
sock = DNSServiceRefSockFD(_netServiceBrowser);
595
if (1 == select(sock + 1, &set, (fd_set *) NULL, (fd_set *) NULL, &tout))
597
err = DNSServiceProcessResult(_netServiceBrowser);
601
if (kDNSServiceErr_NoError != err)
603
[self netServiceBrowser: self
604
didNotSearch: CreateError(self, err)];
609
* Removes the receiver from the specified runloop.
613
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
614
forMode: (NSString *) mode
620
browser = (Browser *) _reserved;
626
[browser->timer setFireDate: [NSDate date]];
627
[browser->timer invalidate];
628
browser->timer = nil;
631
// Do not release the runloop!
632
browser->runloop = nil;
634
DESTROY(browser->runloopmode);
640
* Adds the receiver to the specified runloop.
645
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
646
forMode: (NSString *) mode
652
browser = (Browser *) _reserved;
658
[browser->timer setFireDate: [NSDate date]];
659
[browser->timer invalidate];
660
browser->timer = nil;
663
browser->timer = [NSTimer timerWithTimeInterval: INTERVAL
665
selector: @selector(loop:)
669
browser->runloop = aRunLoop;
670
browser->runloopmode = mode;
672
[browser->timer retain];
678
* Search for all visible domains. This method is deprecated.
683
- (void) searchForAllDomains
685
DNSServiceFlags flags = 0;
689
flags = kDNSServiceFlagsBrowseDomains|kDNSServiceFlagsRegistrationDomains;
690
[self searchForDomain: flags];
694
* Search for all browsable domains.
699
- (void) searchForBrowsableDomains
703
[self searchForDomain: kDNSServiceFlagsBrowseDomains];
707
* Search for all registration domains. These domains can be used to register
712
- (void) searchForRegistrationDomains
716
[self searchForDomain: kDNSServiceFlagsRegistrationDomains];
720
* Search for a particular service within a given domain.
725
- (void) searchForServicesOfType: (NSString *) serviceType
726
inDomain: (NSString *) domainName
729
DNSServiceErrorType err = kDNSServiceErr_NoError;
730
DNSServiceFlags flags = 0;
734
browser = (Browser *) _reserved;
742
err = NSNetServicesInvalidError;
748
err = NSNetServicesActivityInProgress;
752
err = DNSServiceBrowse((DNSServiceRef *) &_netServiceBrowser,
754
browser->interfaceIndex,
755
[serviceType UTF8String],
756
[domainName UTF8String],
764
[self executeWithError: err];
768
* Halts all currently running searches.
779
browser = (Browser *) _reserved;
785
[self netServiceBrowserDidStopSearch: self];
791
* Returns the receiver's delegate.
800
return [[_delegate retain] autorelease];
804
* Sets the receiver's delegate.
809
- (void) setDelegate: (id) delegate
813
ASSIGN(_delegate, delegate);
817
* <em>Description forthcoming</em>
822
- (void) netServiceBrowserWillSearch: (NSNetServiceBrowser *) aBrowser
826
if ([_delegate respondsToSelector: @selector(netServiceBrowserWillSearch:)])
828
[_delegate netServiceBrowserWillSearch: aBrowser];
833
* <em>Description forthcoming</em>
838
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
839
didNotSearch: (NSDictionary *) errorDict
843
if ([_delegate respondsToSelector:
844
@selector(netServiceBrowser:didNotSearch:)])
846
[_delegate netServiceBrowser: aBrowser
847
didNotSearch: errorDict];
852
* <em>Description forthcoming</em>
857
- (void) netServiceBrowserDidStopSearch: (NSNetServiceBrowser *) aBrowser
861
if ([_delegate respondsToSelector:
862
@selector(netServiceBrowserDidStopSearch:)])
864
[_delegate netServiceBrowserDidStopSearch: aBrowser];
869
* <em>Description forthcoming</em>
874
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
875
didFindDomain: (NSString *) domainString
876
moreComing: (BOOL) moreComing
880
if ([_delegate respondsToSelector:
881
@selector(netServiceBrowser:didFindDomain:moreComing:)])
883
[_delegate netServiceBrowser: aBrowser
884
didFindDomain: domainString
885
moreComing: moreComing];
890
* <em>Description forthcoming</em>
895
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
896
didRemoveDomain: (NSString *) domainString
897
moreComing: (BOOL) moreComing
901
if ([_delegate respondsToSelector:
902
@selector(netServiceBrowser:didRemoveDomain:moreComing:)])
904
[_delegate netServiceBrowser: aBrowser
905
didRemoveDomain: domainString
906
moreComing: moreComing];
911
* <em>Description forthcoming</em>
916
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
917
didFindService: (NSNetService *) aService
918
moreComing: (BOOL) moreComing
922
if ([_delegate respondsToSelector:
923
@selector(netServiceBrowser:didFindService:moreComing:)])
925
[_delegate netServiceBrowser: aBrowser
926
didFindService: aService
927
moreComing: moreComing];
932
* <em>Description forthcoming</em>
937
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
938
didRemoveService: (NSNetService *) aService
939
moreComing: (BOOL) moreComing
943
if ([_delegate respondsToSelector:
944
@selector(netServiceBrowser:didRemoveService:moreComing:)])
946
[_delegate netServiceBrowser: aBrowser
947
didRemoveService: aService
948
moreComing: moreComing];
953
* Initializes the receiver.
962
if ((self = [super init]))
966
browser = malloc(sizeof (struct _Browser));
967
memset(browser, 0, sizeof browser);
971
browser->runloop = nil;
972
browser->runloopmode = nil;
973
browser->timer = nil;
975
browser->services = [[NSMutableDictionary alloc] initWithCapacity: 1];
977
browser->interfaceIndex = 0;
979
_netServiceBrowser = NULL;
987
* <em>Description forthcoming</em>
998
browser = (Browser *) _reserved;
1004
DESTROY(browser->services);
1010
DESTROYLOCK(browser);
1019
@implementation NSNetService
1022
* <em>Description forthcoming</em>
1031
SETVERSION(NSNetService);
1034
LOG(@"%@ may NOT be thread-safe!", [self class]);
1040
* <em>Description forthcoming</em>
1045
- (void) executeWithError: (DNSServiceErrorType) err
1051
service = (Service *) _reserved;
1055
if (kDNSServiceErr_NoError == err)
1057
if (YES == service->isPublishing)
1059
[self netServiceWillPublish: self];
1063
[self netServiceWillResolve: self];
1066
if (! service->runloop)
1068
[self scheduleInRunLoop: [NSRunLoop currentRunLoop]
1069
forMode: NSDefaultRunLoopMode];
1072
[service->runloop addTimer: service->timer
1073
forMode: service->runloopmode];
1075
[service->timer fire];
1077
else // notify the delegate of the error
1079
if (YES == service->isPublishing)
1081
[self netService: self
1082
didNotPublish: CreateError(self, err)];
1086
[self netService: self
1087
didNotResolve: CreateError(self, err)];
1095
* <em>Description forthcoming</em>
1106
service = (Service *) _reserved;
1110
if (service->runloop)
1112
[self removeFromRunLoop: service->runloop
1113
forMode: service->runloopmode];
1118
[service->timer invalidate];
1119
DESTROY(service->timer);
1124
DNSServiceRefDeallocate(_netService);
1128
[service->info removeAllObjects];
1129
[service->foundAddresses removeAllObjects];
1135
* <em>Description forthcoming</em>
1140
- (void) stopResolving: (id) sender
1146
service = (Service *) _reserved;
1150
[service->timeout invalidate];
1151
[service->timer invalidate];
1153
[self netService: self
1154
didNotResolve: CreateError(self, NSNetServicesTimeoutError)];
1160
* <em>Description forthcoming</em>
1165
- (void) resolverCallback: (DNSServiceRef) sdRef
1166
flags: (DNSServiceFlags) flags
1167
interface: (uint32_t) interfaceIndex
1168
error: (DNSServiceErrorType) errorCode
1169
fullname: (const char *) fullname
1170
target: (const char *) hosttarget
1171
port: (uint16_t) port
1172
length: (uint16_t) txtLen
1173
record: (const char *) txtRecord
1179
service = (Service *) _reserved;
1189
[self netService: self
1190
didNotResolve: CreateError(self, errorCode)];
1195
NSString *target = nil;
1197
// Add the TXT record
1199
? [[NSData alloc] initWithBytes: txtRecord length: txtLen]
1204
? [[NSString alloc] initWithUTF8String: hosttarget]
1208
service->port = ntohs(port);
1210
// Remove the old TXT entry
1211
[service->info removeObjectForKey: @"TXT"];
1215
[service->info setObject: txt forKey: @"TXT"];
1219
// Remove the old host entry
1220
[service->info removeObjectForKey: @"Host"];
1222
// Add the host if there is one
1225
[service->info setObject: target forKey: @"Host"];
1229
/* Add the interface so all subsequent
1230
* queries are on the same interface
1232
service->interfaceIndex = interfaceIndex;
1234
service->timer = nil;
1236
// Prepare query for A and/or AAAA record
1237
errorCode = DNSServiceQueryRecord((DNSServiceRef *) &_netService,
1241
kDNSServiceType_ANY,
1242
kDNSServiceClass_IN,
1246
// No error? Then create a new timer
1247
if (kDNSServiceErr_NoError == errorCode)
1249
service->timer = [NSTimer timerWithTimeInterval: INTERVAL
1251
selector: @selector(loop:)
1254
[service->timer fire];
1262
* <em>Description forthcoming</em>
1267
- (BOOL) addAddress: (char *) addressString
1274
service = (Service *) _reserved;
1276
if (nil == service->foundAddresses)
1278
service->foundAddresses = [[NSMutableArray alloc] init];
1281
string = [NSString stringWithCString: addressString];
1282
if ([service->foundAddresses containsObject: string])
1284
// duplicate, didn't add it
1288
[service->foundAddresses addObject: string];
1295
* <em>Description forthcoming</em>
1300
- (void) addAddress: (const void *) rdata
1301
length: (uint16_t) rdlen
1302
type: (uint16_t) rrtype
1303
interface: (uint32_t) interfaceIndex
1309
service = (Service *) _reserved;
1314
NSMutableArray *addresses = nil;
1315
struct sockaddr *address = { 0 };
1317
const unsigned char *rd = rdata;
1318
char rdb[INET6_ADDRSTRLEN];
1320
memset(rdb, 0, sizeof rdb);
1322
addresses = [service->info objectForKey: @"Addresses"];
1324
if (nil == addresses)
1326
addresses = [[NSMutableArray alloc] initWithCapacity: 1];
1331
case kDNSServiceType_A: // AF_INET
1333
struct sockaddr_in ip4;
1336
sprintf(rdb, "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
1337
LOG(@"Found IPv4 <%s> on port %d", rdb, service->port);
1339
length = sizeof (struct sockaddr_in);
1340
memset(&ip4, 0, length);
1342
inet_pton(AF_INET, rdb, &ip4.sin_addr);
1343
ip4.sin_family = AF_INET;
1344
ip4.sin_port = htons(service->port);
1346
address = (struct sockaddr *) &ip4;
1350
#if defined(AF_INET6)
1351
case kDNSServiceType_AAAA: // AF_INET6
1352
case kDNSServiceType_A6: // deprecates AAAA
1354
struct sockaddr_in6 ip6;
1357
sprintf(rdb, "%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x",
1358
rd[0], rd[1], rd[2], rd[3],
1359
rd[4], rd[5], rd[6], rd[7],
1360
rd[8], rd[9], rd[10], rd[11],
1361
rd[12], rd[13], rd[14], rd[15]);
1362
LOG(@"Found IPv6 <%s> on port %d", rdb, service->port);
1364
length = sizeof (struct sockaddr_in6);
1365
memset(&ip6, 0, length);
1367
inet_pton(AF_INET6, rdb, &ip6.sin6_addr);
1368
#if defined(HAVE_SA_LEN)
1369
ip6.sin6_len = sizeof ip6;
1371
ip6.sin6_family = AF_INET6;
1372
ip6.sin6_port = htons(service->port);
1373
ip6.sin6_flowinfo = 0;
1374
ip6.sin6_scope_id = interfaceIndex;
1376
address = (struct sockaddr *) &ip6;
1379
#endif /* AF_INET6 */
1382
LOG(@"Unkown type of length <%d>", rdlen);
1386
// check for duplicate entries
1387
if ([self addAddress: rdb])
1390
data = [NSData dataWithBytes: address
1393
[addresses addObject: data];
1394
[service->info setObject: [addresses retain]
1395
forKey: @"Addresses"];
1397
// notify the delegate
1398
[self netServiceDidResolveAddress: self];
1400
[addresses release];
1402
// got it, so invalidate the timeout
1403
[service->timeout invalidate];
1404
service->timeout = nil;
1411
* <em>Description forthcoming</em>
1416
- (void) queryCallback: (DNSServiceRef) sdRef
1417
flags: (DNSServiceFlags) flags
1418
interface: (uint32_t) interfaceIndex
1419
error: (DNSServiceErrorType) errorCode
1420
fullname: (const char *) fullname
1421
type: (uint16_t) rrtype
1422
class: (uint16_t) rrclass
1423
length: (uint16_t) rdlen
1424
data: (const void *) rdata
1431
service = (Service *) _reserved;
1441
[self netService: self
1442
didNotResolve: CreateError(self, errorCode)];
1451
case kDNSServiceType_A: // 1 -- AF_INET
1452
[self addAddress: rdata
1455
interface: interfaceIndex];
1458
case kDNSServiceType_NS:
1459
case kDNSServiceType_MD:
1460
case kDNSServiceType_MF:
1461
case kDNSServiceType_CNAME: // 5
1462
case kDNSServiceType_SOA:
1463
case kDNSServiceType_MB:
1464
case kDNSServiceType_MG:
1465
case kDNSServiceType_MR:
1466
case kDNSServiceType_NULL: // 10
1467
case kDNSServiceType_WKS:
1468
case kDNSServiceType_PTR:
1469
case kDNSServiceType_HINFO:
1470
case kDNSServiceType_MINFO:
1471
case kDNSServiceType_MX: // 15
1472
// not handled (yet)
1475
case kDNSServiceType_TXT:
1480
data = [NSData dataWithBytes: rdata
1483
[service->info removeObjectForKey: @"TXT"];
1484
[service->info setObject: data
1487
[self netService: self
1488
didUpdateTXTRecordData: data];
1493
case kDNSServiceType_RP:
1494
case kDNSServiceType_AFSDB:
1495
case kDNSServiceType_X25:
1496
case kDNSServiceType_ISDN: // 20
1497
case kDNSServiceType_RT:
1498
case kDNSServiceType_NSAP:
1499
case kDNSServiceType_NSAP_PTR:
1500
case kDNSServiceType_SIG:
1501
case kDNSServiceType_KEY: // 25
1502
case kDNSServiceType_PX:
1503
case kDNSServiceType_GPOS:
1504
// not handled (yet)
1507
case kDNSServiceType_AAAA: // 28 -- AF_INET6
1508
[self addAddress: rdata
1511
interface: interfaceIndex];
1514
case kDNSServiceType_LOC:
1515
case kDNSServiceType_NXT: // 30
1516
case kDNSServiceType_EID:
1517
case kDNSServiceType_NIMLOC:
1518
case kDNSServiceType_SRV:
1519
case kDNSServiceType_ATMA:
1520
case kDNSServiceType_NAPTR: // 35
1521
case kDNSServiceType_KX:
1522
case kDNSServiceType_CERT:
1523
// not handled (yet)
1526
case kDNSServiceType_A6: // 38 -- AF_INET6, deprecates AAAA
1527
[self addAddress: rdata
1530
interface: interfaceIndex];
1533
case kDNSServiceType_DNAME:
1534
case kDNSServiceType_SINK: // 40
1535
case kDNSServiceType_OPT:
1536
// not handled (yet)
1539
case kDNSServiceType_TKEY: // 249
1540
case kDNSServiceType_TSIG: // 250
1541
case kDNSServiceType_IXFR:
1542
case kDNSServiceType_AXFR:
1543
case kDNSServiceType_MAILB:
1544
case kDNSServiceType_MAILA:
1545
// not handled (yet)
1548
case kDNSServiceType_ANY:
1549
LOG(@"Oops, got the wildcard match...");
1553
LOG(@"Don't know how to handle rrtype <%d>", rrtype);
1561
* <em>Description forthcoming</em>
1566
- (void) registerCallback: (DNSServiceRef) sdRef
1567
flags: (DNSServiceFlags) flags
1568
error: (DNSServiceErrorType) errorCode
1569
name: (const char *) name
1570
type: (const char *) regtype
1571
domain: (const char *) domain
1577
service = (Service *) _reserved;
1587
[self netService: self
1588
didNotPublish: CreateError(self, errorCode)];
1592
[self netServiceDidPublish: self];
1599
* <em>Description forthcoming</em>
1604
- (void) loop: (id) sender
1607
struct timeval tout = { 0 };
1609
DNSServiceErrorType err = kDNSServiceErr_NoError;
1611
sock = DNSServiceRefSockFD(_netService);
1618
if (1 == select(sock + 1, &set, (fd_set *) NULL, (fd_set *) NULL, &tout))
1620
err = DNSServiceProcessResult(_netService);
1624
if (kDNSServiceErr_NoError != err)
1628
service = (Service *) _reserved;
1630
if (YES == service->isPublishing)
1632
[self netService: self
1633
didNotPublish: CreateError(self, err)];
1637
[self netService: self
1638
didNotResolve: CreateError(self, err)];
1644
* Converts txtDictionary into a TXT data.
1649
+ (NSData *) dataFromTXTRecordDictionary: (NSDictionary *) txtDictionary
1651
NSMutableData *result = nil;
1652
NSArray *keys = nil;
1653
NSArray *values = nil;
1658
count = [txtDictionary count];
1662
keys = [txtDictionary allKeys];
1663
values = [txtDictionary allValues];
1671
TXTRecordCreate(&txt, 0, NULL);
1673
for(; i < count; i++)
1677
DNSServiceErrorType err = kDNSServiceErr_Unknown;
1679
if (! [[keys objectAtIndex: i] isKindOfClass: [NSString class]])
1681
LOG(@"%@ is not a string", [keys objectAtIndex: i]);
1685
length = [[keys objectAtIndex: i] length];
1686
[[keys objectAtIndex: i] getCString: key
1687
maxLength: sizeof key];
1690
if (! length || (used >= sizeof key))
1692
LOG(@"incorrect length %d - %d - %d",
1693
length, used, sizeof key);
1699
if ([[values objectAtIndex: i] isKindOfClass: [NSString class]])
1703
length = [[values objectAtIndex: i] length];
1704
[[values objectAtIndex: i] getCString: value
1705
maxLength: sizeof value];
1706
used = strlen(value);
1708
if (used >= sizeof value)
1710
LOG(@"incorrect length %d - %d - %d",
1711
length, used, sizeof value);
1715
err = TXTRecordSetValue(&txt,
1720
else if ([[values objectAtIndex: i] isKindOfClass: [NSData class]]
1721
&& [[values objectAtIndex: i] length] < 256
1722
&& [[values objectAtIndex: i] length] >= 0)
1724
err = TXTRecordSetValue(&txt,
1726
[[values objectAtIndex: i] length],
1727
[[values objectAtIndex: i] bytes]);
1729
else if ([values objectAtIndex: i] == [NSNull null])
1731
err = TXTRecordSetValue(&txt,
1738
LOG(@"unknown value type");
1742
if (err != kDNSServiceErr_NoError)
1744
LOG(@"error creating data type");
1751
result = [NSData dataWithBytes: TXTRecordGetBytesPtr(&txt)
1752
length: TXTRecordGetLength(&txt)];
1755
TXTRecordDeallocate(&txt);
1759
LOG(@"No keys or values");
1762
// both are autorelease'd
1768
LOG(@"Dictionary seems empty");
1774
* Converts the TXT data txtData into a dictionary.
1779
+ (NSDictionary *) dictionaryFromTXTRecordData: (NSData *) txtData
1781
NSMutableDictionary *result = nil;
1783
const void *txt = 0;
1787
len = [txtData length];
1788
txt = [txtData bytes];
1791
// A TXT record cannot exceed 65535 bytes, see Chapter 6.1 of
1792
// http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
1794
if ((len > 0) && (len < 65536))
1799
// get number of keys
1800
count = TXTRecordGetCount(len, txt);
1801
result = [NSMutableDictionary dictionaryWithCapacity: 1];
1805
// go through all keys
1806
for(; i < count; i++)
1810
const void *value = NULL;
1811
DNSServiceErrorType err = kDNSServiceErr_NoError;
1813
err = TXTRecordGetItemAtIndex(len, txt, i,
1817
// only if we can get the key and value...
1818
if (kDNSServiceErr_NoError == err)
1821
NSString *str = nil;
1823
str = [NSString stringWithUTF8String: key];
1827
data = [NSData dataWithBytes: value
1831
if (data && str && [str length]
1832
&& ! [result objectForKey: str])
1834
/* only add if key and value were created
1835
* and key doesn't exist yet
1837
[result setValue: data
1842
/* I'm not exactly sure what to do if there
1843
* is a key WITHOUT a value
1844
* Theoretically '<6>foobar' should be identical
1845
* to '<7>foobar=' i.e. the value would be [NSNull null]
1847
[result setValue: [NSNull null]
1851
// both are autorelease'd
1857
LOG(@"Couldn't get TXTRecord item");
1863
LOG(@"Couldn't create dictionary");
1868
LOG(@"TXT record has incorrect length: <%d>", len);
1874
* Initializes the receiver for service resolution. Use this method to create
1875
* an object if you intend to -resolve a service.
1879
- (id) initWithDomain: (NSString *) domain
1880
type: (NSString *) type
1881
name: (NSString *) name
1885
return [self initWithDomain: domain
1888
port: -1]; // -1 to indicate resolution, not publish
1892
* Initializes the receiver for service publication. Use this method to create
1893
* an object if you intend to -publish a service.
1897
- (id) initWithDomain: (NSString *) domain
1898
type: (NSString *) type
1899
name: (NSString *) name
1904
if ((self = [super init]))
1908
service = malloc(sizeof (struct _Service));
1909
memset(service, 0, sizeof service);
1911
CREATELOCK(service);
1913
service->runloop = nil;
1914
service->runloopmode = nil;
1915
service->timer = nil;
1916
service->timeout = nil;
1918
service->info = [[NSMutableDictionary alloc] initWithCapacity: 1];
1919
[service->info setObject: [domain retain]
1921
[service->info setObject: [name retain]
1923
[service->info setObject: [type retain]
1926
service->foundAddresses = nil;
1928
service->interfaceIndex = 0;
1929
service->port = htons(port);
1931
service->monitor = nil;
1933
service->isPublishing = (-1 == port) ? NO : YES;
1934
service->isMonitoring = NO;
1938
_reserved = service;
1947
* Removes the service from the specified run loop.
1952
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
1953
forMode: (NSString *) mode
1959
service = (Service *) _reserved;
1965
[service->timer setFireDate: [NSDate date]];
1966
[service->timer invalidate];
1968
// Do not release the timer!
1969
service->timer = nil;
1972
// Do not release the runloop!
1973
service->runloop = nil;
1975
DESTROY(service->runloopmode);
1981
* Adds the service to the specified run loop.
1986
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
1987
forMode: (NSString *) mode
1993
service = (Service *) _reserved;
1999
[service->timer setFireDate: [NSDate date]];
2000
[service->timer invalidate];
2001
service->timer = nil;
2004
service->timer = [NSTimer timerWithTimeInterval: INTERVAL
2006
selector: @selector(loop:)
2010
service->runloop = aRunLoop;
2011
service->runloopmode = mode;
2013
[service->timer retain];
2019
* Attempts to publish a service on the network.
2027
DNSServiceErrorType err = kDNSServiceErr_NoError;
2028
DNSServiceFlags flags = 0;
2032
service = (Service *) _reserved;
2038
// cannot -publish on a service that's init'd for resolving
2039
if (NO == service->isPublishing)
2041
err = NSNetServicesBadArgumentError;
2047
err = NSNetServicesInvalidError;
2053
err = NSNetServicesActivityInProgress;
2057
if (service->timeout)
2059
[service->timeout setFireDate: [NSDate date]];
2060
[service->timeout invalidate];
2061
service->timeout = nil;
2064
err = DNSServiceRegister((DNSServiceRef *) &_netService,
2065
flags, service->interfaceIndex,
2066
[[service->info objectForKey: @"Name"] UTF8String],
2067
[[service->info objectForKey: @"Type"] UTF8String],
2068
[[service->info objectForKey: @"Domain"] UTF8String],
2069
NULL, service->port, 0, NULL,
2070
RegistrationCallback, self);
2076
[self executeWithError: err];
2080
* This method is deprecated. Use -resolveWithTimeout: instead.
2089
[self resolveWithTimeout: 5];
2093
* Starts a service resolution for a limited duration.
2098
- (void) resolveWithTimeout: (NSTimeInterval) timeout
2101
DNSServiceErrorType err = kDNSServiceErr_NoError;
2102
DNSServiceFlags flags = 0;
2106
service = (Service *) _reserved;
2112
// cannot -resolve on a service that's init'd for publishing
2113
if (YES == service->isPublishing)
2115
err = NSNetServicesBadArgumentError;
2121
err = NSNetServicesInvalidError;
2127
err = NSNetServicesActivityInProgress;
2131
if (service->timeout)
2133
[service->timeout setFireDate: [NSDate date]];
2134
[service->timeout invalidate];
2135
service->timeout = nil;
2138
service->timeout = [NSTimer alloc];
2142
date = [NSDate dateWithTimeIntervalSinceNow: timeout + SHORTTIMEOUT];
2144
[service->timeout initWithFireDate: date
2147
selector: @selector(stopResolving:)
2152
err = DNSServiceResolve((DNSServiceRef *) &_netService,
2154
service->interfaceIndex,
2155
[[service->info objectForKey: @"Name"] UTF8String],
2156
[[service->info objectForKey: @"Type"] UTF8String],
2157
[[service->info objectForKey: @"Domain"] UTF8String],
2165
[self executeWithError: err];
2169
* Stops the current attempt to publish or resolve a service.
2180
service = (Service *) _reserved;
2186
[self netServiceDidStop: self];
2192
* Starts monitoring of TXT record updates.
2197
- (void) startMonitoring
2203
service = (Service *) _reserved;
2207
// Obviously this will only work on a resolver
2208
if (! service->isPublishing)
2210
if (! service->isMonitoring)
2213
= [[NSNetServiceMonitor alloc] initWithDelegate: self];
2215
[service->monitor scheduleInRunLoop: service->runloop
2216
forMode: service->runloopmode];
2217
[service->monitor start];
2219
service->isMonitoring = YES;
2227
* Stops monitoring of TXT record updates.
2232
- (void) stopMonitoring
2238
service = (Service *) _reserved;
2242
if (! service->isPublishing)
2244
if (service->isMonitoring)
2246
[service->monitor stop];
2248
// Probably don't need it anymore, so release it
2249
DESTROY(service->monitor);
2250
service->isMonitoring = NO;
2258
* Returns the receiver's delegate.
2267
return [[_delegate retain] autorelease];
2271
* Sets the receiver's delegate.
2276
- (void) setDelegate: (id) delegate
2280
ASSIGN(_delegate, delegate);
2284
* Returns an array of NSData objects that each contain the socket address of
2289
- (NSArray *) addresses
2293
return [((Service*)_reserved)->info objectForKey: @"Addresses"];
2297
* Returns the domain name of the service.
2302
- (NSString *) domain
2306
return [((Service*)_reserved)->info objectForKey: @"Domain"];
2310
* Returns the host name of the computer publishing the service.
2315
- (NSString *) hostName
2319
return [((Service*)_reserved)->info objectForKey: @"Host"];
2323
* Returns the name of the service.
2332
return [((Service*)_reserved)->info objectForKey: @"Name"];
2336
* Returns the type of the service.
2345
return [((Service*)_reserved)->info objectForKey: @"Type"];
2349
* This method is deprecated. Use -TXTRecordData instead.
2354
- (NSString *) protocolSpecificInformation
2356
NSMutableArray *array = nil;
2361
service = (Service *) _reserved;
2364
// I must admit, the following may not be entirely correct...
2368
NSDictionary *dictionary = nil;
2370
dictionary = [NSNetService dictionaryFromTXTRecordData:
2371
[self TXTRecordData]];
2375
NSEnumerator *keys = nil;
2376
NSString *key = nil;
2378
array = [NSMutableArray arrayWithCapacity: [dictionary count]];
2379
keys = [dictionary keyEnumerator];
2381
while((key = [keys nextObject]))
2383
NSData *value = nil;
2385
value = [dictionary objectForKey: key];
2387
if (value != (NSData *) [NSNull null])
2392
// FIXME ... should this be UTF8?
2393
str = [[NSString alloc]
2394
initWithBytes: [value bytes]
2395
length: [value length]
2396
encoding: NSUTF8StringEncoding];
2397
pair = [NSString stringWithFormat: @"%@=%@", key, str];
2400
[array addObject: pair];
2402
else if ([key length])
2404
[array addObject: [NSString stringWithFormat: @"%@", key]];
2411
return ([array count] ? [array componentsJoinedByString: @"\001"]
2412
: (NSString *) nil);
2416
* This method is deprecated. Use -setTXTRecordData: instead.
2421
- (void) setProtocolSpecificInformation: (NSString *) specificInformation
2427
service = (Service *) _reserved;
2430
// Again, the following may not be entirely correct...
2434
NSArray *array = nil;
2436
array = [specificInformation componentsSeparatedByString: @"\001"];
2440
NSMutableDictionary *dictionary = nil;
2441
NSEnumerator *enumerator = nil;
2442
NSString *item = nil;
2445
= [NSMutableDictionary dictionaryWithCapacity: [array count]];
2446
enumerator = [array objectEnumerator];
2448
while((item = [enumerator nextObject]))
2450
NSArray *parts = nil;
2453
parts = [item componentsSeparatedByString:@"="];
2455
value = [[parts objectAtIndex: 1]
2456
dataUsingEncoding: NSUTF8StringEncoding];
2457
[dictionary setObject: value
2458
forKey: [parts objectAtIndex: 0]];
2461
[self setTXTRecordData:
2462
[NSNetService dataFromTXTRecordDictionary: dictionary]];
2469
* Returns the TXT record.
2474
- (NSData *) TXTRecordData
2478
return [((Service*)_reserved)->info objectForKey: @"TXT"];
2482
* Sets the TXT record.
2487
- (BOOL) setTXTRecordData: (NSData *) recordData
2494
service = (Service *) _reserved;
2498
// Not allowed on a resolver...
2499
if (service->isPublishing)
2502
err = kDNSServiceErr_NoError;
2504
// Set the value, or remove it if empty
2507
[service->info setObject: recordData
2512
[service->info removeObjectForKey: @"TXT"];
2518
// Now update the record so others can pick it up
2519
err = DNSServiceUpdateRecord(_netService,
2522
recordData ? [recordData length] : 0,
2523
recordData ? [recordData bytes] : NULL,
2537
* Retrieves the input and output stream for the receiver.
2542
- (BOOL) getInputStream: (NSInputStream **) inputStream
2543
outputStream: (NSOutputStream **) outputStream
2549
service = (Service *) _reserved;
2553
[NSStream getStreamsToHost: [service->info objectForKey: @"Host"]
2554
port: ntohs(service->port)
2555
inputStream: inputStream
2556
outputStream: outputStream];
2560
return inputStream && outputStream;
2564
* <em>Description forthcoming</em>
2569
- (void) netServiceWillPublish: (NSNetService *) sender
2573
if ([_delegate respondsToSelector: @selector(netServiceWillPublish:)])
2575
[_delegate netServiceWillPublish: sender];
2580
* <em>Description forthcoming</em>
2585
- (void) netServiceDidPublish: (NSNetService *) sender
2589
if ([_delegate respondsToSelector: @selector(netServiceDidPublish:)])
2591
[_delegate netServiceDidPublish: sender];
2596
* <em>Description forthcoming</em>
2601
- (void) netService: (NSNetService *) sender
2602
didNotPublish: (NSDictionary *) errorDict
2606
if ([_delegate respondsToSelector: @selector(netService:didNotPublish:)])
2608
[_delegate netService: sender
2609
didNotPublish: errorDict];
2614
* <em>Description forthcoming</em>
2619
- (void) netServiceWillResolve: (NSNetService *) sender
2623
if ([_delegate respondsToSelector: @selector(netServiceWillResolve:)])
2625
[_delegate netServiceWillResolve: sender];
2630
* <em>Description forthcoming</em>
2635
- (void) netServiceDidResolveAddress: (NSNetService *) sender
2639
if ([_delegate respondsToSelector: @selector(netServiceDidResolveAddress:)])
2641
[_delegate netServiceDidResolveAddress: sender];
2646
* <em>Description forthcoming</em>
2651
- (void) netService: (NSNetService *) sender
2652
didNotResolve: (NSDictionary *) errorDict
2656
if ([_delegate respondsToSelector: @selector(netService:didNotResolve:)])
2658
[_delegate netService: sender
2659
didNotResolve: errorDict];
2664
* <em>Description forthcoming</em>
2669
- (void) netServiceDidStop: (NSNetService *) sender
2673
if ([_delegate respondsToSelector: @selector(netServiceDidStop:)])
2675
[_delegate netServiceDidStop: sender];
2680
* <em>Description forthcoming</em>
2685
- (void) netService: (NSNetService *) sender
2686
didUpdateTXTRecordData: (NSData *) data
2690
if ([_delegate respondsToSelector:
2691
@selector(netService:didUpdateTXTRecordData:)])
2693
[_delegate netService: sender
2694
didUpdateTXTRecordData: data];
2699
* <em>Description forthcoming</em>
2704
- (void) netService: (NSNetService *) sender
2705
didNotMonitor: (NSDictionary *) errorDict
2709
// This method is kind of a misnomer. It's called whenever NSNetMonitor
2710
// encounters an error while monitoring.
2711
// All we do is stop monitoring -- which we COULD do from NSNetMonitor
2712
// directly, but this seems to be much cleaner.
2714
[self stopMonitoring];
2718
* <em>Description forthcoming</em>
2730
* <em>Description forthcoming</em>
2741
service = (Service *) _reserved;
2745
[self stopMonitoring];
2748
DESTROY(service->info);
2749
DESTROY(service->foundAddresses);
2754
DESTROYLOCK(service);
2763
@implementation NSNetServiceMonitor
2766
* <em>Description forthcoming</em>
2775
SETVERSION(NSNetServiceMonitor);
2779
* <em>Description forthcoming</em>
2784
- (void) loop: (id) sender
2787
struct timeval tout = { 0 };
2789
DNSServiceErrorType err = kDNSServiceErr_NoError;
2791
sock = DNSServiceRefSockFD(_netServiceMonitor);
2798
if (1 == select(sock + 1, &set, (fd_set *) NULL, (fd_set *) NULL, &tout))
2800
err = DNSServiceProcessResult(_netServiceMonitor);
2804
if (kDNSServiceErr_NoError != err)
2806
LOG(@"Error <%d> while monitoring", err);
2808
[_delegate netService: _delegate
2809
didNotMonitor: CreateError(self, err)];
2814
* <em>Description forthcoming</em>
2819
- (void) queryCallback: (DNSServiceRef) sdRef
2820
flags: (DNSServiceFlags) flags
2821
interface: (uint32_t) interfaceIndex
2822
error: (DNSServiceErrorType) errorCode
2823
fullname: (const char *) fullname
2824
type: (uint16_t) rrtype
2825
class: (uint16_t) rrclass
2826
length: (uint16_t) rdlen
2827
data: (const void *) rdata
2834
monitor = (Monitor *) _reserved;
2840
// we are 'monitoring' kDNSServiceType_TXT
2841
// this is already handled by the delegate's method of the same name
2842
// so we simply pass this through
2843
[_delegate queryCallback: sdRef
2845
interface: interfaceIndex
2858
* <em>Description forthcoming</em>
2863
- (id) initWithDelegate: (id) delegate
2867
if ((self = [super init]) != nil)
2871
monitor = malloc(sizeof (struct _Monitor));
2872
memset(monitor, 0, sizeof monitor);
2874
CREATELOCK(monitor);
2876
monitor->runloop = nil;
2877
monitor->runloopmode = nil;
2878
monitor->timer = nil;
2880
_netServiceMonitor = NULL;
2881
_delegate = [delegate retain];
2882
_reserved = monitor;
2888
* <em>Description forthcoming</em>
2893
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
2894
forMode: (NSString *) mode
2900
monitor = (Monitor *) _reserved;
2906
[monitor->timer setFireDate: [NSDate date]];
2907
[monitor->timer invalidate];
2908
monitor->timer = nil;
2911
// Do not release the runloop!
2912
monitor->runloop = nil;
2914
// [monitor->runloopmode release];
2915
monitor->runloopmode = nil;
2921
* <em>Description forthcoming</em>
2926
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
2927
forMode: (NSString *) mode
2933
monitor = (Monitor *) _reserved;
2939
[monitor->timer setFireDate: [NSDate date]];
2940
[monitor->timer invalidate];
2941
monitor->timer = nil;
2944
monitor->runloop = aRunLoop;
2945
monitor->runloopmode = mode;
2951
* <em>Description forthcoming</em>
2962
monitor = (Monitor *) _reserved;
2966
DNSServiceErrorType err = kDNSServiceErr_NoError;
2967
DNSServiceFlags flags = kDNSServiceFlagsLongLivedQuery;
2968
NSString *fullname = nil;
2974
err = NSNetServicesInvalidError;
2980
err = NSNetServicesActivityInProgress;
2984
fullname = [NSString stringWithFormat: @"%@.%@%@",
2985
[_delegate name], [_delegate type], [_delegate domain]];
2987
err = DNSServiceQueryRecord((DNSServiceRef *) &_netServiceMonitor,
2990
[fullname UTF8String],
2991
kDNSServiceType_TXT,
2992
kDNSServiceClass_IN,
2996
if (kDNSServiceErr_NoError == err)
2998
monitor->timer = [NSTimer timerWithTimeInterval: INTERVAL
3000
selector: @selector(loop:)
3004
[monitor->runloop addTimer: monitor->timer
3005
forMode: monitor->runloopmode];
3007
[monitor->timer fire];
3016
* <em>Description forthcoming</em>
3027
monitor = (Monitor *) _reserved;
3031
if (monitor->runloop)
3033
[self removeFromRunLoop: monitor->runloop
3034
forMode: monitor->runloopmode];
3039
[monitor->timer invalidate];
3040
monitor->timer = nil;
3043
if (_netServiceMonitor)
3045
DNSServiceRefDeallocate(_netServiceMonitor);
3046
_netServiceMonitor = NULL;
3053
* <em>Description forthcoming</em>
3065
* <em>Description forthcoming</em>
3076
monitor = (Monitor *) _reserved;
3086
DESTROYLOCK(monitor);
3096
* <em>Description forthcoming</em>
3101
static NSDictionary *
3102
CreateError(id sender, int errorCode)
3104
NSMutableDictionary *dictionary = nil;
3109
dictionary = [NSMutableDictionary dictionary];
3110
error = ConvertError(errorCode);
3112
LOG(@"%@ says error <%d> - <%d>", [sender description], errorCode, error);
3114
[dictionary setObject: [NSNumber numberWithInt: error]
3115
forKey: NSNetServicesErrorCode];
3116
[dictionary setObject: sender
3117
forKey: NSNetServicesErrorDomain];
3119
return dictionary; // autorelease'd
3123
* <em>Description forthcoming</em>
3129
ConvertError(int errorCode)
3135
case kDNSServiceErr_Unknown:
3136
return NSNetServicesUnknownError;
3138
case kDNSServiceErr_NoSuchName:
3139
return NSNetServicesNotFoundError;
3141
case kDNSServiceErr_NoMemory:
3142
return NSNetServicesUnknownError;
3144
case kDNSServiceErr_BadParam:
3145
case kDNSServiceErr_BadReference:
3146
case kDNSServiceErr_BadState:
3147
case kDNSServiceErr_BadFlags:
3148
return NSNetServicesBadArgumentError;
3150
case kDNSServiceErr_Unsupported:
3151
return NSNetServicesUnknownError;
3153
case kDNSServiceErr_NotInitialized:
3154
return NSNetServicesInvalidError;
3156
case kDNSServiceErr_AlreadyRegistered:
3157
case kDNSServiceErr_NameConflict:
3158
return NSNetServicesCollisionError;
3160
case kDNSServiceErr_Invalid:
3161
return NSNetServicesInvalidError;
3163
case kDNSServiceErr_Firewall:
3164
return NSNetServicesUnknownError;
3166
case kDNSServiceErr_Incompatible:
3167
// The client library is incompatible with the daemon
3168
return NSNetServicesInvalidError;
3170
case kDNSServiceErr_BadInterfaceIndex:
3171
case kDNSServiceErr_Refused:
3172
return NSNetServicesUnknownError;
3174
case kDNSServiceErr_NoSuchRecord:
3175
case kDNSServiceErr_NoAuth:
3176
case kDNSServiceErr_NoSuchKey:
3177
return NSNetServicesNotFoundError;
3179
case kDNSServiceErr_NATTraversal:
3180
case kDNSServiceErr_DoubleNAT:
3181
case kDNSServiceErr_BadTime:
3182
return NSNetServicesUnknownError;
3189
* <em>Description forthcoming</em>
3195
EnumerationCallback(DNSServiceRef sdRef,
3196
DNSServiceFlags flags,
3197
uint32_t interfaceIndex,
3198
DNSServiceErrorType errorCode,
3199
const char *replyDomain,
3202
// NSNetServiceBrowser
3203
[(id) context enumCallback: sdRef
3205
interface: interfaceIndex
3207
domain: replyDomain];
3211
* <em>Description forthcoming</em>
3217
BrowserCallback(DNSServiceRef sdRef,
3218
DNSServiceFlags flags,
3219
uint32_t interfaceIndex,
3220
DNSServiceErrorType errorCode,
3221
const char *replyName,
3222
const char *replyType,
3223
const char *replyDomain,
3226
// NSNetServiceBrowser
3227
[(id) context browseCallback: sdRef
3229
interface: interfaceIndex
3233
domain: replyDomain];
3237
* <em>Description forthcoming</em>
3243
ResolverCallback(DNSServiceRef sdRef,
3244
DNSServiceFlags flags,
3245
uint32_t interfaceIndex,
3246
DNSServiceErrorType errorCode,
3247
const char *fullname,
3248
const char *hosttarget,
3251
const char *txtRecord,
3255
[(id) context resolverCallback: sdRef
3257
interface: interfaceIndex
3267
* <em>Description forthcoming</em>
3273
RegistrationCallback(DNSServiceRef sdRef,
3274
DNSServiceFlags flags,
3275
DNSServiceErrorType errorCode,
3277
const char *regtype,
3282
[(id) context registerCallback: sdRef
3291
* <em>Description forthcoming</em>
3297
QueryCallback(DNSServiceRef sdRef,
3298
DNSServiceFlags flags,
3299
uint32_t interfaceIndex,
3300
DNSServiceErrorType errorCode,
3301
const char *fullname,
3309
// NSNetService, NSNetServiceMonitor
3310
[(id) context queryCallback: sdRef
3312
interface: interfaceIndex