~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/NSNetServices.m

  • Committer: Bazaar Package Importer
  • Author(s): Hubert Chathi
  • Date: 2007-10-03 17:16:39 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20071003171639-rtyga33jz04drwe3
Tags: 1.14.0-2
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Implementation for NSNetServices for GNUstep
 
2
   Copyright (C) 2006 Free Software Foundation, Inc.
 
3
 
 
4
   Written by:  Chris B. Vetter
 
5
   Date: 2006
 
6
   
 
7
   This file is part of the GNUstep Base Library.
 
8
 
 
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.
 
13
   
 
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.
 
18
   
 
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,
 
22
   Boston, MA 02111 USA.
 
23
   */ 
 
24
 
 
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"
 
35
#endif
 
36
 
 
37
#import <dns_sd.h>              // Apple's DNS Service Discovery
 
38
 
 
39
#import <sys/types.h>
 
40
#import <sys/socket.h>          // AF_INET / AF_INET6
 
41
 
 
42
#import <netinet/in.h>          // struct sockaddr_in / sockaddr_in6
 
43
#import <arpa/inet.h>           // inet_pton(3)
 
44
 
 
45
//
 
46
// Define
 
47
//
 
48
 
 
49
#if ! defined(INET6_ADDRSTRLEN)
 
50
#  define INET6_ADDRSTRLEN      46
 
51
#endif
 
52
 
 
53
// trigger runloop timer every INTERVAL seconds
 
54
#define INTERVAL                0.3
 
55
#define SHORTTIMEOUT            0.25
 
56
 
 
57
// debugging stuff and laziness on my part
 
58
#if defined(VERBOSE)
 
59
#  define INTERNALTRACE NSDebugLLog(@"Trace", @"%s", __PRETTY_FUNCTION__)
 
60
#  define LOG(f, args...)       NSDebugLLog(@"NSNetServices", f, ##args)
 
61
#else
 
62
#  define INTERNALTRACE
 
63
#  define LOG(f, args...)
 
64
#endif /* VERBOSE */
 
65
 
 
66
#if ! defined(VERSION)
 
67
#  define VERSION (((GNUSTEP_BASE_MAJOR_VERSION * 100)                  \
 
68
                  + GNUSTEP_BASE_MINOR_VERSION) * 100)                  \
 
69
                  + GNUSTEP_BASE_SUBMINOR_VERSION
 
70
#endif
 
71
 
 
72
#define SETVERSION(aClass)                                              \
 
73
        do {                                                            \
 
74
          if (self == [aClass class]) { [self setVersion: VERSION]; }   \
 
75
          else { [self doesNotRecognizeSelector: _cmd]; }               \
 
76
        } while(0);
 
77
 
 
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)
 
84
#else
 
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 */
 
90
#endif
 
91
 
 
92
//
 
93
// Typedef
 
94
//
 
95
 
 
96
typedef struct _Browser         // The actual NSNetServiceBrowser
 
97
{
 
98
  THE_LOCK;
 
99
  
 
100
  NSRunLoop             *runloop;
 
101
  NSString              *runloopmode;
 
102
  NSTimer               *timer;                 // to control the runloop
 
103
  
 
104
  NSMutableDictionary   *services;
 
105
    // List of found services.
 
106
    // Key is <_name_type_domain> and value is an initialized NSNetService.
 
107
  
 
108
  int                    interfaceIndex;
 
109
} Browser;
 
110
 
 
111
typedef struct _Service         // The actual NSNetService
 
112
{
 
113
  THE_LOCK;
 
114
  
 
115
  NSRunLoop             *runloop;
 
116
  NSString              *runloopmode;
 
117
  NSTimer               *timer,                 // to control the runloop
 
118
                        *timeout;               // to time-out the resolve
 
119
  
 
120
  NSMutableDictionary   *info;
 
121
    // The service's information, keys are
 
122
    // - Domain (string)
 
123
    // - Name (string)
 
124
    // - Type (string)
 
125
    // - Host (string)
 
126
    // - Addresses (mutable array)
 
127
    // - TXT (data)
 
128
  
 
129
  NSMutableArray        *foundAddresses;        // array of char*
 
130
  
 
131
  int                    interfaceIndex,        // should also be in 'info'
 
132
                         port;                  // ditto
 
133
  
 
134
  id                     monitor;               // NSNetServiceMonitor
 
135
  
 
136
  BOOL                   isPublishing,          // true if publishing service
 
137
                         isMonitoring;          // true if monitoring
 
138
} Service;
 
139
 
 
140
typedef struct _Monitor         // The actual NSNetServiceMonitor
 
141
{
 
142
  THE_LOCK;
 
143
  
 
144
  NSRunLoop             *runloop;
 
145
  NSString              *runloopmode;
 
146
  NSTimer               *timer;                 // to control the runloop
 
147
} Monitor;
 
148
 
 
149
//
 
150
// Public
 
151
//
 
152
 
 
153
/**
 
154
 * This key identifies the most recent error.
 
155
 */
 
156
NSString * const NSNetServicesErrorCode = @"NSNetServicesErrorCode";
 
157
 
 
158
/**
 
159
 * This key identifies the originator of the error.
 
160
 */
 
161
NSString * const NSNetServicesErrorDomain = @"NSNetServicesErrorDomain";
 
162
 
 
163
//
 
164
// Private
 
165
//
 
166
 
 
167
//
 
168
// Private Interface
 
169
//
 
170
 
 
171
@interface NSNetServiceMonitor : NSObject
 
172
{
 
173
  @private
 
174
  void          * _netServiceMonitor;
 
175
  id              _delegate;
 
176
  void          * _reserved;
 
177
}
 
178
 
 
179
- (id) initWithDelegate: (id) delegate;
 
180
 
 
181
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
 
182
                   forMode: (NSString *) mode;
 
183
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
 
184
                   forMode: (NSString *) mode;
 
185
 
 
186
- (void) start;
 
187
- (void) stop;
 
188
 
 
189
@end
 
190
 
 
191
//
 
192
// Prototype
 
193
//
 
194
 
 
195
static NSDictionary *CreateError(id sender, int errorCode);
 
196
 
 
197
static int ConvertError(int errorCode);
 
198
 
 
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,
 
206
                      void                      *context);
 
207
 
 
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,
 
216
                  void                          *context);
 
217
 
 
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,
 
226
                   uint16_t                      port,
 
227
                   uint16_t                      txtLen,
 
228
                   const char                   *txtRecord,
 
229
                   void                         *context);
 
230
 
 
231
static void DNSSD_API
 
232
  RegistrationCallback(DNSServiceRef             sdRef,
 
233
                       DNSServiceFlags           flags,
 
234
                       DNSServiceErrorType       errorCode,
 
235
                       const char               *name,
 
236
                       const char               *regtype,
 
237
                       const char               *domain,
 
238
                       void                     *context);
 
239
 
 
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,
 
247
                uint16_t                         rrtype,
 
248
                uint16_t                         rrclass,
 
249
                uint16_t                         rdlen,
 
250
                const void                      *rdata,
 
251
                uint32_t                         ttl,
 
252
                void                            *context);
 
253
 
 
254
/***************************************************************************
 
255
**
 
256
** Implementation
 
257
**
 
258
*/
 
259
 
 
260
@implementation NSNetServiceBrowser
 
261
 
 
262
/**
 
263
 * <em>Description forthcoming</em>
 
264
 *
 
265
 *
 
266
 */
 
267
 
 
268
+ (void) initialize
 
269
{
 
270
  INTERNALTRACE;
 
271
  
 
272
  SETVERSION(NSNetServiceBrowser);
 
273
  {
 
274
#ifndef _REENTRANT
 
275
    LOG(@"%@ may NOT be thread-safe!", [self class]);
 
276
#endif
 
277
  }
 
278
}
 
279
 
 
280
/***************************************************************************
 
281
**
 
282
** Private Methods
 
283
**
 
284
*/
 
285
 
 
286
/**
 
287
 * <em>Description forthcoming</em>
 
288
 *
 
289
 *
 
290
 */
 
291
 
 
292
- (void) cleanup
 
293
{
 
294
  Browser       *browser;
 
295
  
 
296
  INTERNALTRACE;
 
297
  
 
298
  browser = (Browser *) _reserved;
 
299
  
 
300
  LOCK(browser);
 
301
  {
 
302
    if (browser->runloop)
 
303
      {
 
304
        [self removeFromRunLoop: browser->runloop
 
305
                        forMode: browser->runloopmode];
 
306
      }
 
307
    
 
308
    if (browser->timer)
 
309
      {
 
310
        [browser->timer invalidate];
 
311
        DESTROY(browser->timer);
 
312
      }
 
313
    
 
314
    if (_netServiceBrowser)
 
315
      {
 
316
        DNSServiceRefDeallocate(_netServiceBrowser);
 
317
        _netServiceBrowser = NULL;
 
318
      }
 
319
    
 
320
    [browser->services removeAllObjects];
 
321
  }
 
322
  UNLOCK(browser);
 
323
}
 
324
 
 
325
/**
 
326
 * <em>Description forthcoming</em>
 
327
 *
 
328
 *
 
329
 */
 
330
 
 
331
- (void) executeWithError: (DNSServiceErrorType) err
 
332
{
 
333
  Browser       *browser;
 
334
  
 
335
  INTERNALTRACE;
 
336
  
 
337
  browser = (Browser *) _reserved;
 
338
  
 
339
  LOCK(browser);
 
340
  {
 
341
    if (kDNSServiceErr_NoError == err)
 
342
      {
 
343
        [self netServiceBrowserWillSearch: self];
 
344
        
 
345
        if (! browser->runloop)
 
346
          {
 
347
            [self scheduleInRunLoop: [NSRunLoop currentRunLoop]
 
348
                            forMode: NSDefaultRunLoopMode];
 
349
          }
 
350
        
 
351
        [browser->runloop addTimer: browser->timer
 
352
                           forMode: browser->runloopmode];
 
353
        
 
354
        [browser->timer fire];
 
355
      }
 
356
    else // notify the delegate of the error
 
357
      {
 
358
        [self netServiceBrowser: self
 
359
                   didNotSearch: CreateError(self, err)];
 
360
      }
 
361
  }
 
362
  UNLOCK(browser);
 
363
}
 
364
 
 
365
/**
 
366
 * <em>Description forthcoming</em>
 
367
 *
 
368
 *
 
369
 */
 
370
 
 
371
- (void) searchForDomain: (int) aFlag
 
372
{
 
373
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
374
  Browser               *browser;
 
375
  
 
376
  INTERNALTRACE;
 
377
  
 
378
  browser = (Browser *) _reserved;
 
379
  
 
380
  LOCK(browser);
 
381
  {
 
382
    do
 
383
      {
 
384
        if (! _delegate)
 
385
          {
 
386
            err = NSNetServicesInvalidError;
 
387
            break;
 
388
          }
 
389
        
 
390
        if (browser->timer)
 
391
          {
 
392
            err = NSNetServicesActivityInProgress;
 
393
            break;
 
394
          }
 
395
        
 
396
        err = DNSServiceEnumerateDomains((DNSServiceRef *)&_netServiceBrowser,
 
397
          aFlag,
 
398
          browser->interfaceIndex,
 
399
          EnumerationCallback,
 
400
          self);
 
401
      }
 
402
    while(0);
 
403
  }
 
404
  UNLOCK(browser);
 
405
  
 
406
  [self executeWithError: err];
 
407
}
 
408
 
 
409
/**
 
410
 * <em>Description forthcoming</em>
 
411
 *
 
412
 *
 
413
 */
 
414
 
 
415
- (void) enumCallback: (DNSServiceRef) sdRef
 
416
                flags: (DNSServiceFlags) flags
 
417
            interface: (uint32_t) interfaceIndex
 
418
                error: (DNSServiceErrorType) errorCode
 
419
               domain: (const char *) replyDomain
 
420
{
 
421
  Browser       *browser;
 
422
  
 
423
  INTERNALTRACE;
 
424
  
 
425
  browser = (Browser *) _reserved;
 
426
  
 
427
  LOCK(browser);
 
428
  
 
429
  if (_netServiceBrowser)
 
430
    {
 
431
      if (errorCode)
 
432
        {
 
433
          [self cleanup];
 
434
          
 
435
          [self netServiceBrowser: self
 
436
                     didNotSearch: CreateError(self, errorCode)];
 
437
        }
 
438
      else
 
439
        {  
 
440
          BOOL  more = NO;
 
441
          
 
442
          if (replyDomain)
 
443
            {
 
444
              NSString  *domain;
 
445
 
 
446
              more = flags & kDNSServiceFlagsMoreComing;
 
447
              
 
448
              browser->interfaceIndex = interfaceIndex;
 
449
              
 
450
              domain = [NSString stringWithUTF8String: replyDomain];
 
451
 
 
452
              if (flags & kDNSServiceFlagsAdd)
 
453
                {
 
454
                  LOG(@"Found domain <%s>", replyDomain);
 
455
                  
 
456
                  [self netServiceBrowser: self
 
457
                            didFindDomain: domain
 
458
                               moreComing: more];
 
459
                }
 
460
              else // kDNSServiceFlagsRemove
 
461
                {
 
462
                  LOG(@"Removed domain <%s>", replyDomain);
 
463
                  
 
464
                  [self netServiceBrowser: self
 
465
                          didRemoveDomain: domain
 
466
                               moreComing: more];
 
467
                }
 
468
            }
 
469
        }
 
470
    }
 
471
  UNLOCK(browser);
 
472
}
 
473
 
 
474
/**
 
475
 * <em>Description forthcoming</em>
 
476
 *
 
477
 *
 
478
 */
 
479
 
 
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
 
487
{
 
488
  Browser       *browser;
 
489
  
 
490
  INTERNALTRACE;
 
491
  
 
492
  browser = (Browser *) _reserved;
 
493
  
 
494
  LOCK(browser);
 
495
  
 
496
  if (_netServiceBrowser)
 
497
    {
 
498
      if (errorCode)
 
499
        {
 
500
          [self cleanup];
 
501
                
 
502
          [self netServiceBrowser: self
 
503
                     didNotSearch: CreateError(self, errorCode)];
 
504
        }
 
505
      else
 
506
        {
 
507
          NSNetService  *service = nil;
 
508
          NSString      *domain = nil;
 
509
          NSString      *type = nil;
 
510
          NSString      *name = nil;
 
511
          NSString      *key = nil;
 
512
          BOOL          more = (flags & kDNSServiceFlagsMoreComing);
 
513
          
 
514
          browser->interfaceIndex = interfaceIndex;
 
515
          
 
516
          if (nil == browser->services)
 
517
            {
 
518
              browser->services
 
519
                = [[NSMutableDictionary alloc] initWithCapacity: 1];
 
520
            }
 
521
        
 
522
          domain = [NSString stringWithUTF8String: replyDomain];
 
523
          type = [NSString stringWithUTF8String: replyType];
 
524
          name = [NSString stringWithUTF8String: replyName];
 
525
          
 
526
          key = [NSString stringWithFormat: @"%@%@%@", name, type, domain];
 
527
          
 
528
          if (flags & kDNSServiceFlagsAdd)
 
529
            {
 
530
              service = [[NSNetService alloc] initWithDomain: domain
 
531
                                                        type: type
 
532
                                                        name: name];
 
533
              
 
534
              if (service)
 
535
                {
 
536
                  LOG(@"Found service <%s>", replyName);
 
537
                  
 
538
                  [self netServiceBrowser: self
 
539
                           didFindService: service
 
540
                               moreComing: more];
 
541
                  
 
542
                  [browser->services setObject: service
 
543
                                        forKey: key];
 
544
                  
 
545
                  [service autorelease];
 
546
                }
 
547
              else
 
548
                {
 
549
                  LOG(@"WARNING: Could not create an NSNetService for <%s>",
 
550
                    replyName);
 
551
                }
 
552
            }
 
553
          else // kDNSServiceFlagsRemove
 
554
            {
 
555
              service = [browser->services objectForKey: key];
 
556
              
 
557
              if (service)
 
558
                {
 
559
                  LOG(@"Removed service <%@>", [service name]);
 
560
                  
 
561
                  [self netServiceBrowser: self
 
562
                         didRemoveService: service
 
563
                               moreComing: more];
 
564
                }
 
565
              else
 
566
                {
 
567
                  LOG(@"WARNING: Could not find <%@> in list", key);
 
568
                }
 
569
            }
 
570
        }
 
571
    }
 
572
  UNLOCK(browser);
 
573
}
 
574
 
 
575
/**
 
576
 * <em>Description forthcoming</em>
 
577
 *
 
578
 *
 
579
 */
 
580
 
 
581
- (void) loop: (id) sender
 
582
{
 
583
  int                   sock = 0;
 
584
  struct timeval        tout = { 0 };
 
585
  fd_set                set;
 
586
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
587
  
 
588
  sock = DNSServiceRefSockFD(_netServiceBrowser);
 
589
  
 
590
  if (-1 != sock)
 
591
    {
 
592
      FD_ZERO(&set);
 
593
      FD_SET(sock, &set);
 
594
      
 
595
      if (1 == select(sock + 1, &set, (fd_set *) NULL, (fd_set *) NULL, &tout))
 
596
        {
 
597
          err = DNSServiceProcessResult(_netServiceBrowser);
 
598
        }
 
599
    }
 
600
  
 
601
  if (kDNSServiceErr_NoError != err)
 
602
    {
 
603
      [self netServiceBrowser: self
 
604
                 didNotSearch: CreateError(self, err)];
 
605
    }
 
606
}
 
607
 
 
608
/**
 
609
 * Removes the receiver from the specified runloop.
 
610
 *
 
611
 *
 
612
 */
 
613
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
 
614
                   forMode: (NSString *) mode
 
615
{
 
616
  Browser       *browser;
 
617
  
 
618
  INTERNALTRACE;
 
619
  
 
620
  browser = (Browser *) _reserved;
 
621
  
 
622
  LOCK(browser);
 
623
  {
 
624
    if (browser->timer)
 
625
      {
 
626
        [browser->timer setFireDate: [NSDate date]];
 
627
        [browser->timer invalidate];
 
628
        browser->timer = nil;
 
629
      }
 
630
    
 
631
    // Do not release the runloop!
 
632
    browser->runloop = nil;
 
633
    
 
634
    DESTROY(browser->runloopmode);
 
635
  }
 
636
  UNLOCK(browser);
 
637
}
 
638
 
 
639
/**
 
640
 * Adds the receiver to the specified runloop.
 
641
 *
 
642
 *
 
643
 */
 
644
 
 
645
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
 
646
                   forMode: (NSString *) mode
 
647
{
 
648
  Browser       *browser;
 
649
  
 
650
  INTERNALTRACE;
 
651
  
 
652
  browser = (Browser *) _reserved;
 
653
  
 
654
  LOCK(browser);
 
655
  {
 
656
    if (browser->timer)
 
657
      {
 
658
        [browser->timer setFireDate: [NSDate date]];
 
659
        [browser->timer invalidate];
 
660
        browser->timer = nil;
 
661
      }
 
662
    
 
663
    browser->timer = [NSTimer timerWithTimeInterval: INTERVAL
 
664
                                             target: self
 
665
                                           selector: @selector(loop:)
 
666
                                           userInfo: nil
 
667
                                            repeats: YES];
 
668
    
 
669
    browser->runloop = aRunLoop;
 
670
    browser->runloopmode = mode;
 
671
    
 
672
    [browser->timer retain];
 
673
  }
 
674
  UNLOCK(browser);
 
675
}
 
676
 
 
677
/**
 
678
 * Search for all visible domains. This method is deprecated.
 
679
 *
 
680
 *
 
681
 */
 
682
 
 
683
- (void) searchForAllDomains
 
684
{
 
685
  DNSServiceFlags       flags = 0;
 
686
  
 
687
  INTERNALTRACE;
 
688
  
 
689
  flags = kDNSServiceFlagsBrowseDomains|kDNSServiceFlagsRegistrationDomains;
 
690
  [self searchForDomain: flags];
 
691
}
 
692
 
 
693
/**
 
694
 * Search for all browsable domains.
 
695
 *
 
696
 *
 
697
 */
 
698
 
 
699
- (void) searchForBrowsableDomains
 
700
{
 
701
  INTERNALTRACE;
 
702
  
 
703
  [self searchForDomain: kDNSServiceFlagsBrowseDomains];
 
704
}
 
705
 
 
706
/**
 
707
 * Search for all registration domains. These domains can be used to register
 
708
 * a service.
 
709
 *
 
710
 */
 
711
 
 
712
- (void) searchForRegistrationDomains
 
713
{
 
714
  INTERNALTRACE;
 
715
  
 
716
  [self searchForDomain: kDNSServiceFlagsRegistrationDomains];
 
717
}
 
718
 
 
719
/**
 
720
 * Search for a particular service within a given domain.
 
721
 *
 
722
 *
 
723
 */
 
724
 
 
725
- (void) searchForServicesOfType: (NSString *) serviceType
 
726
                        inDomain: (NSString *) domainName
 
727
{
 
728
  Browser               *browser;
 
729
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
730
  DNSServiceFlags       flags = 0;
 
731
  
 
732
  INTERNALTRACE;
 
733
  
 
734
  browser = (Browser *) _reserved;
 
735
  
 
736
  LOCK(browser);
 
737
  {
 
738
    do
 
739
      {
 
740
        if (! _delegate)
 
741
          {
 
742
            err = NSNetServicesInvalidError;
 
743
            break;
 
744
          }
 
745
        
 
746
        if (browser->timer)
 
747
          {
 
748
            err = NSNetServicesActivityInProgress;
 
749
            break;
 
750
          }
 
751
        
 
752
        err = DNSServiceBrowse((DNSServiceRef *) &_netServiceBrowser,
 
753
          flags,
 
754
          browser->interfaceIndex,
 
755
          [serviceType UTF8String],
 
756
          [domainName UTF8String],
 
757
          BrowserCallback,
 
758
          self);
 
759
      }
 
760
    while(0);
 
761
  }
 
762
  UNLOCK(browser);
 
763
  
 
764
  [self executeWithError: err];
 
765
}
 
766
 
 
767
/**
 
768
 * Halts all currently running searches.
 
769
 *
 
770
 *
 
771
 */
 
772
 
 
773
- (void) stop
 
774
{
 
775
  Browser       *browser;
 
776
  
 
777
  INTERNALTRACE;
 
778
  
 
779
  browser = (Browser *) _reserved;
 
780
  
 
781
  LOCK(browser);
 
782
  {
 
783
    [self cleanup];
 
784
    
 
785
    [self netServiceBrowserDidStopSearch: self];
 
786
  }
 
787
  UNLOCK(browser);
 
788
}
 
789
 
 
790
/**
 
791
 * Returns the receiver's delegate.
 
792
 *
 
793
 *
 
794
 */
 
795
 
 
796
- (id) delegate
 
797
{
 
798
  INTERNALTRACE;
 
799
  
 
800
  return [[_delegate retain] autorelease];
 
801
}
 
802
 
 
803
/**
 
804
 * Sets the receiver's delegate.
 
805
 *
 
806
 *
 
807
 */
 
808
 
 
809
- (void) setDelegate: (id) delegate
 
810
{
 
811
  INTERNALTRACE;
 
812
  
 
813
  ASSIGN(_delegate, delegate);
 
814
}
 
815
 
 
816
/**
 
817
 * <em>Description forthcoming</em>
 
818
 *
 
819
 *
 
820
 */
 
821
 
 
822
- (void) netServiceBrowserWillSearch: (NSNetServiceBrowser *) aBrowser
 
823
{
 
824
  INTERNALTRACE;
 
825
  
 
826
  if ([_delegate respondsToSelector: @selector(netServiceBrowserWillSearch:)])
 
827
    {
 
828
      [_delegate netServiceBrowserWillSearch: aBrowser];
 
829
    }
 
830
}
 
831
 
 
832
/**
 
833
 * <em>Description forthcoming</em>
 
834
 *
 
835
 *
 
836
 */
 
837
 
 
838
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
 
839
              didNotSearch: (NSDictionary *) errorDict
 
840
{
 
841
  INTERNALTRACE;
 
842
  
 
843
  if ([_delegate respondsToSelector:
 
844
    @selector(netServiceBrowser:didNotSearch:)])
 
845
    {
 
846
      [_delegate netServiceBrowser: aBrowser
 
847
                      didNotSearch: errorDict];
 
848
    }
 
849
}
 
850
 
 
851
/**
 
852
 * <em>Description forthcoming</em>
 
853
 *
 
854
 *
 
855
 */
 
856
 
 
857
- (void) netServiceBrowserDidStopSearch: (NSNetServiceBrowser *) aBrowser
 
858
{
 
859
  INTERNALTRACE;
 
860
  
 
861
  if ([_delegate respondsToSelector:
 
862
    @selector(netServiceBrowserDidStopSearch:)])
 
863
    {
 
864
      [_delegate netServiceBrowserDidStopSearch: aBrowser];
 
865
    }
 
866
}
 
867
 
 
868
/**
 
869
 * <em>Description forthcoming</em>
 
870
 *
 
871
 *
 
872
 */
 
873
 
 
874
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
 
875
             didFindDomain: (NSString *) domainString
 
876
                moreComing: (BOOL) moreComing
 
877
{
 
878
  INTERNALTRACE;
 
879
  
 
880
  if ([_delegate respondsToSelector:
 
881
    @selector(netServiceBrowser:didFindDomain:moreComing:)])
 
882
    {
 
883
      [_delegate netServiceBrowser: aBrowser
 
884
                     didFindDomain: domainString
 
885
                        moreComing: moreComing];
 
886
    }
 
887
}
 
888
 
 
889
/**
 
890
 * <em>Description forthcoming</em>
 
891
 *
 
892
 *
 
893
 */
 
894
 
 
895
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
 
896
           didRemoveDomain: (NSString *) domainString
 
897
                moreComing: (BOOL) moreComing
 
898
{
 
899
  INTERNALTRACE;
 
900
  
 
901
  if ([_delegate respondsToSelector:
 
902
    @selector(netServiceBrowser:didRemoveDomain:moreComing:)])
 
903
    {
 
904
      [_delegate netServiceBrowser: aBrowser
 
905
                   didRemoveDomain: domainString
 
906
                        moreComing: moreComing];
 
907
    }
 
908
}
 
909
 
 
910
/**
 
911
 * <em>Description forthcoming</em>
 
912
 *
 
913
 *
 
914
 */
 
915
 
 
916
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
 
917
            didFindService: (NSNetService *) aService
 
918
                moreComing: (BOOL) moreComing
 
919
{
 
920
  INTERNALTRACE;
 
921
  
 
922
  if ([_delegate respondsToSelector:
 
923
    @selector(netServiceBrowser:didFindService:moreComing:)])
 
924
    {
 
925
      [_delegate netServiceBrowser: aBrowser
 
926
                    didFindService: aService
 
927
                        moreComing: moreComing];
 
928
    }
 
929
}
 
930
 
 
931
/**
 
932
 * <em>Description forthcoming</em>
 
933
 *
 
934
 *
 
935
 */
 
936
 
 
937
- (void) netServiceBrowser: (NSNetServiceBrowser *) aBrowser
 
938
          didRemoveService: (NSNetService *) aService
 
939
                moreComing: (BOOL) moreComing
 
940
{
 
941
  INTERNALTRACE;
 
942
  
 
943
  if ([_delegate respondsToSelector:
 
944
    @selector(netServiceBrowser:didRemoveService:moreComing:)])
 
945
    {
 
946
      [_delegate netServiceBrowser: aBrowser
 
947
                  didRemoveService: aService
 
948
                        moreComing: moreComing];
 
949
    }
 
950
}
 
951
 
 
952
/** <init />
 
953
 * Initializes the receiver.
 
954
 *
 
955
 *
 
956
 */
 
957
 
 
958
- (id) init
 
959
{
 
960
  INTERNALTRACE;
 
961
  
 
962
  if ((self = [super init]))
 
963
    {
 
964
      Browser   *browser;
 
965
      
 
966
      browser = malloc(sizeof (struct _Browser));
 
967
      memset(browser, 0, sizeof browser);
 
968
      
 
969
      CREATELOCK(browser);
 
970
      
 
971
      browser->runloop = nil;
 
972
      browser->runloopmode = nil;
 
973
      browser->timer = nil;
 
974
      
 
975
      browser->services = [[NSMutableDictionary alloc] initWithCapacity: 1];
 
976
      
 
977
      browser->interfaceIndex = 0;
 
978
      
 
979
      _netServiceBrowser = NULL;
 
980
      _delegate = nil;
 
981
      _reserved = browser;
 
982
    }
 
983
  return self;
 
984
}
 
985
 
 
986
/**
 
987
 * <em>Description forthcoming</em>
 
988
 *
 
989
 *
 
990
 */
 
991
 
 
992
- (void) dealloc
 
993
{
 
994
  Browser       *browser;
 
995
  
 
996
  INTERNALTRACE;
 
997
  
 
998
  browser = (Browser *) _reserved;
 
999
  {
 
1000
    LOCK(browser);
 
1001
    {
 
1002
      [self cleanup];
 
1003
      
 
1004
      DESTROY(browser->services);
 
1005
      
 
1006
      _delegate = nil;
 
1007
    }
 
1008
    UNLOCK(browser);
 
1009
    
 
1010
    DESTROYLOCK(browser);
 
1011
    
 
1012
    free(browser);
 
1013
  }
 
1014
  [super dealloc];
 
1015
}
 
1016
 
 
1017
@end
 
1018
 
 
1019
@implementation NSNetService
 
1020
 
 
1021
/**
 
1022
 * <em>Description forthcoming</em>
 
1023
 *
 
1024
 *
 
1025
 */
 
1026
 
 
1027
+ (void) initialize
 
1028
{
 
1029
  INTERNALTRACE;
 
1030
  
 
1031
  SETVERSION(NSNetService);
 
1032
  {
 
1033
#ifndef _REENTRANT
 
1034
    LOG(@"%@ may NOT be thread-safe!", [self class]);
 
1035
#endif
 
1036
  }
 
1037
}
 
1038
 
 
1039
/**
 
1040
 * <em>Description forthcoming</em>
 
1041
 *
 
1042
 *
 
1043
 */
 
1044
 
 
1045
- (void) executeWithError: (DNSServiceErrorType) err
 
1046
{
 
1047
  Service       *service;
 
1048
  
 
1049
  INTERNALTRACE;
 
1050
  
 
1051
  service = (Service *) _reserved;
 
1052
  
 
1053
  LOCK(service);
 
1054
  {
 
1055
    if (kDNSServiceErr_NoError == err)
 
1056
      {
 
1057
        if (YES == service->isPublishing)
 
1058
          {
 
1059
            [self netServiceWillPublish: self];
 
1060
          }
 
1061
        else
 
1062
          {
 
1063
            [self netServiceWillResolve: self];
 
1064
          }
 
1065
        
 
1066
        if (! service->runloop)
 
1067
          {
 
1068
            [self scheduleInRunLoop: [NSRunLoop currentRunLoop]
 
1069
                            forMode: NSDefaultRunLoopMode];
 
1070
          }
 
1071
        
 
1072
        [service->runloop addTimer: service->timer
 
1073
                           forMode: service->runloopmode];
 
1074
        
 
1075
        [service->timer fire];
 
1076
      }
 
1077
    else // notify the delegate of the error
 
1078
      {
 
1079
        if (YES == service->isPublishing)
 
1080
          {
 
1081
            [self netService: self
 
1082
               didNotPublish: CreateError(self, err)];
 
1083
          }
 
1084
        else
 
1085
          {
 
1086
            [self netService: self
 
1087
               didNotResolve: CreateError(self, err)];
 
1088
          }
 
1089
      }
 
1090
  }
 
1091
  UNLOCK(service);
 
1092
}
 
1093
 
 
1094
/**
 
1095
 * <em>Description forthcoming</em>
 
1096
 *
 
1097
 *
 
1098
 */
 
1099
 
 
1100
- (void) cleanup
 
1101
{
 
1102
  Service       *service;
 
1103
  
 
1104
  INTERNALTRACE;
 
1105
  
 
1106
  service = (Service *) _reserved;
 
1107
  
 
1108
  LOCK(service);
 
1109
  {
 
1110
    if (service->runloop)
 
1111
      {
 
1112
        [self removeFromRunLoop: service->runloop
 
1113
                        forMode: service->runloopmode];
 
1114
      }
 
1115
    
 
1116
    if (service->timer)
 
1117
      {
 
1118
        [service->timer invalidate];
 
1119
        DESTROY(service->timer);
 
1120
      }
 
1121
    
 
1122
    if (_netService)
 
1123
      {
 
1124
        DNSServiceRefDeallocate(_netService);
 
1125
        _netService = NULL;
 
1126
      }
 
1127
    
 
1128
    [service->info removeAllObjects];
 
1129
    [service->foundAddresses removeAllObjects];
 
1130
  }
 
1131
  UNLOCK(service);
 
1132
}
 
1133
 
 
1134
/**
 
1135
 * <em>Description forthcoming</em>
 
1136
 *
 
1137
 *
 
1138
 */
 
1139
 
 
1140
- (void) stopResolving: (id) sender
 
1141
{
 
1142
  Service       *service;
 
1143
  
 
1144
  INTERNALTRACE;
 
1145
  
 
1146
  service = (Service *) _reserved;
 
1147
  
 
1148
  LOCK(service);
 
1149
  {
 
1150
    [service->timeout invalidate];
 
1151
    [service->timer invalidate];
 
1152
    
 
1153
    [self netService: self
 
1154
       didNotResolve: CreateError(self, NSNetServicesTimeoutError)];
 
1155
  }
 
1156
  UNLOCK(service);
 
1157
}
 
1158
 
 
1159
/**
 
1160
 * <em>Description forthcoming</em>
 
1161
 *
 
1162
 *
 
1163
 */
 
1164
 
 
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
 
1174
{
 
1175
  Service       *service;
 
1176
  
 
1177
  INTERNALTRACE;
 
1178
  
 
1179
  service = (Service *) _reserved;
 
1180
  
 
1181
  LOCK(service);
 
1182
  
 
1183
  if (_netService)
 
1184
    {
 
1185
      if (errorCode)
 
1186
        {
 
1187
          [self cleanup];
 
1188
          
 
1189
          [self netService: self
 
1190
             didNotResolve: CreateError(self, errorCode)];
 
1191
        }
 
1192
      else
 
1193
        {
 
1194
          NSData        *txt = nil;
 
1195
          NSString      *target = nil;
 
1196
          
 
1197
          // Add the TXT record
 
1198
          txt = txtRecord
 
1199
            ? [[NSData alloc] initWithBytes: txtRecord length: txtLen]
 
1200
            : nil;
 
1201
          
 
1202
          // Get the host
 
1203
          target = hosttarget
 
1204
            ? [[NSString alloc] initWithUTF8String: hosttarget]
 
1205
            : nil;
 
1206
          
 
1207
          // Add the port
 
1208
          service->port = ntohs(port);
 
1209
          
 
1210
          // Remove the old TXT entry
 
1211
          [service->info removeObjectForKey: @"TXT"];
 
1212
          
 
1213
          if (txt)
 
1214
            {
 
1215
              [service->info setObject: txt forKey: @"TXT"];
 
1216
              [txt release];
 
1217
            }
 
1218
          
 
1219
          // Remove the old host entry
 
1220
          [service->info removeObjectForKey: @"Host"];
 
1221
          
 
1222
          // Add the host if there is one
 
1223
          if (target)
 
1224
            {
 
1225
              [service->info setObject: target forKey: @"Host"];
 
1226
              [target release];
 
1227
            }
 
1228
          
 
1229
          /* Add the interface so all subsequent
 
1230
           * queries are on the same interface
 
1231
           */
 
1232
          service->interfaceIndex = interfaceIndex;
 
1233
          
 
1234
          service->timer = nil;
 
1235
          
 
1236
          // Prepare query for A and/or AAAA record
 
1237
          errorCode = DNSServiceQueryRecord((DNSServiceRef *) &_netService,
 
1238
            flags,
 
1239
            interfaceIndex,
 
1240
            hosttarget,
 
1241
            kDNSServiceType_ANY,
 
1242
            kDNSServiceClass_IN,
 
1243
            QueryCallback,
 
1244
            self);
 
1245
          
 
1246
          // No error? Then create a new timer
 
1247
          if (kDNSServiceErr_NoError == errorCode)
 
1248
            {
 
1249
              service->timer = [NSTimer timerWithTimeInterval: INTERVAL
 
1250
                                                       target: self
 
1251
                                                     selector: @selector(loop:)
 
1252
                                                     userInfo: nil
 
1253
                                                      repeats: YES];
 
1254
              [service->timer fire];
 
1255
            }
 
1256
        }
 
1257
    }
 
1258
  UNLOCK(service);
 
1259
}
 
1260
 
 
1261
/**
 
1262
 * <em>Description forthcoming</em>
 
1263
 *
 
1264
 *
 
1265
 */
 
1266
 
 
1267
- (BOOL) addAddress: (char *) addressString
 
1268
{
 
1269
  Service       *service;
 
1270
  NSString      *string;
 
1271
  
 
1272
  INTERNALTRACE;
 
1273
  
 
1274
  service = (Service *) _reserved;
 
1275
  
 
1276
  if (nil == service->foundAddresses)
 
1277
    {
 
1278
      service->foundAddresses = [[NSMutableArray alloc] init];
 
1279
    }
 
1280
  
 
1281
  string = [NSString stringWithCString: addressString];
 
1282
  if ([service->foundAddresses containsObject: string])
 
1283
    {
 
1284
      // duplicate, didn't add it
 
1285
      return NO;
 
1286
    }
 
1287
  
 
1288
  [service->foundAddresses addObject: string];
 
1289
 
 
1290
  return YES;
 
1291
}
 
1292
 
 
1293
 
 
1294
/**
 
1295
 * <em>Description forthcoming</em>
 
1296
 *
 
1297
 *
 
1298
 */
 
1299
 
 
1300
- (void) addAddress: (const void *) rdata
 
1301
             length: (uint16_t) rdlen
 
1302
               type: (uint16_t) rrtype
 
1303
          interface: (uint32_t) interfaceIndex
 
1304
{
 
1305
  Service       *service;
 
1306
  
 
1307
  INTERNALTRACE;
 
1308
  
 
1309
  service = (Service *) _reserved;
 
1310
  
 
1311
  LOCK(service);
 
1312
  {
 
1313
    NSData              *data = nil;
 
1314
    NSMutableArray      *addresses = nil;
 
1315
    struct sockaddr     *address = { 0 };
 
1316
    size_t              length = 0;
 
1317
    const unsigned char *rd = rdata;
 
1318
    char                rdb[INET6_ADDRSTRLEN];
 
1319
    
 
1320
    memset(rdb, 0, sizeof rdb);
 
1321
    
 
1322
    addresses = [service->info objectForKey: @"Addresses"];
 
1323
    
 
1324
    if (nil == addresses)
 
1325
      {
 
1326
        addresses = [[NSMutableArray alloc] initWithCapacity: 1];
 
1327
      }
 
1328
    
 
1329
    switch(rrtype)
 
1330
      {
 
1331
        case kDNSServiceType_A:         // AF_INET
 
1332
          {
 
1333
            struct sockaddr_in  ip4;
 
1334
            
 
1335
            // oogly
 
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);
 
1338
            
 
1339
            length = sizeof (struct sockaddr_in);
 
1340
            memset(&ip4, 0, length);
 
1341
            
 
1342
            inet_pton(AF_INET, rdb, &ip4.sin_addr);
 
1343
            ip4.sin_family = AF_INET;
 
1344
            ip4.sin_port = htons(service->port);
 
1345
            
 
1346
            address = (struct sockaddr *) &ip4;
 
1347
          }
 
1348
          break;
 
1349
        
 
1350
  #if defined(AF_INET6)
 
1351
        case kDNSServiceType_AAAA:      // AF_INET6
 
1352
        case kDNSServiceType_A6:                // deprecates AAAA
 
1353
          {
 
1354
            struct sockaddr_in6 ip6;
 
1355
            
 
1356
            // Even more oogly
 
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);
 
1363
            
 
1364
            length = sizeof (struct sockaddr_in6);
 
1365
            memset(&ip6, 0, length);
 
1366
            
 
1367
            inet_pton(AF_INET6, rdb, &ip6.sin6_addr);
 
1368
#if defined(HAVE_SA_LEN)
 
1369
            ip6.sin6_len = sizeof ip6;
 
1370
#endif
 
1371
            ip6.sin6_family = AF_INET6;
 
1372
            ip6.sin6_port = htons(service->port);
 
1373
            ip6.sin6_flowinfo = 0;
 
1374
            ip6.sin6_scope_id = interfaceIndex;
 
1375
            
 
1376
            address = (struct sockaddr *) &ip6;
 
1377
          }
 
1378
          break;
 
1379
#endif /* AF_INET6 */      
 
1380
        
 
1381
        default:
 
1382
          LOG(@"Unkown type of length <%d>", rdlen);
 
1383
          break;
 
1384
      }
 
1385
    
 
1386
    // check for duplicate entries
 
1387
    if ([self addAddress: rdb])
 
1388
      {
 
1389
        // add it
 
1390
        data = [NSData dataWithBytes: address
 
1391
                              length: length];
 
1392
        
 
1393
        [addresses addObject: data];
 
1394
        [service->info setObject: [addresses retain]
 
1395
                          forKey: @"Addresses"];
 
1396
        
 
1397
        // notify the delegate
 
1398
        [self netServiceDidResolveAddress: self];
 
1399
        
 
1400
        [addresses release];
 
1401
        
 
1402
        // got it, so invalidate the timeout
 
1403
        [service->timeout invalidate];
 
1404
        service->timeout = nil;
 
1405
      }
 
1406
  }
 
1407
  UNLOCK(service);
 
1408
}
 
1409
 
 
1410
/**
 
1411
 * <em>Description forthcoming</em>
 
1412
 *
 
1413
 *
 
1414
 */
 
1415
 
 
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
 
1425
                   ttl: (uint32_t) ttl
 
1426
{
 
1427
  Service       *service;
 
1428
  
 
1429
  INTERNALTRACE;
 
1430
  
 
1431
  service = (Service *) _reserved;
 
1432
  
 
1433
  LOCK(service);
 
1434
  
 
1435
  if (_netService)
 
1436
    {
 
1437
      if (errorCode)
 
1438
        {
 
1439
          [self cleanup];
 
1440
          
 
1441
          [self netService: self
 
1442
             didNotResolve: CreateError(self, errorCode)];
 
1443
          
 
1444
          UNLOCK(service);
 
1445
          
 
1446
          return;
 
1447
        }
 
1448
      
 
1449
      switch(rrtype)
 
1450
        {
 
1451
          case kDNSServiceType_A:               // 1 -- AF_INET
 
1452
            [self addAddress: rdata
 
1453
                      length: rdlen
 
1454
                        type: rrtype
 
1455
                   interface: interfaceIndex];
 
1456
            break;
 
1457
          
 
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)
 
1473
            break;
 
1474
          
 
1475
          case kDNSServiceType_TXT:
 
1476
            {
 
1477
              NSData
 
1478
                *data = nil;
 
1479
              
 
1480
              data = [NSData dataWithBytes: rdata
 
1481
                                    length: rdlen];
 
1482
              
 
1483
              [service->info removeObjectForKey: @"TXT"];
 
1484
              [service->info setObject: data
 
1485
                                forKey: @"TXT"];
 
1486
              
 
1487
              [self        netService: self
 
1488
               didUpdateTXTRecordData: data];
 
1489
            
 
1490
            }
 
1491
            break;
 
1492
          
 
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)
 
1505
            break;
 
1506
          
 
1507
          case kDNSServiceType_AAAA:    // 28 -- AF_INET6
 
1508
            [self addAddress: rdata
 
1509
                      length: rdlen
 
1510
                        type: rrtype
 
1511
                   interface: interfaceIndex];
 
1512
            break;
 
1513
          
 
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)
 
1524
            break;
 
1525
          
 
1526
          case kDNSServiceType_A6:      // 38 -- AF_INET6, deprecates AAAA
 
1527
            [self addAddress: rdata
 
1528
                      length: rdlen
 
1529
                        type: rrtype
 
1530
                   interface: interfaceIndex];
 
1531
            break;
 
1532
          
 
1533
          case kDNSServiceType_DNAME:
 
1534
          case kDNSServiceType_SINK:    // 40
 
1535
          case kDNSServiceType_OPT:
 
1536
            // not handled (yet)
 
1537
            break;
 
1538
          
 
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)
 
1546
            break;
 
1547
          
 
1548
          case kDNSServiceType_ANY:
 
1549
            LOG(@"Oops, got the wildcard match...");
 
1550
            break;
 
1551
          
 
1552
          default:
 
1553
            LOG(@"Don't know how to handle rrtype <%d>", rrtype);
 
1554
            break;
 
1555
        }
 
1556
    }
 
1557
  UNLOCK(service);
 
1558
}
 
1559
 
 
1560
/**
 
1561
 * <em>Description forthcoming</em>
 
1562
 *
 
1563
 *
 
1564
 */
 
1565
 
 
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
 
1572
{
 
1573
  Service       *service;
 
1574
  
 
1575
  INTERNALTRACE;
 
1576
  
 
1577
  service = (Service *) _reserved;
 
1578
  
 
1579
  LOCK(service);
 
1580
  
 
1581
  if (_netService)
 
1582
    {
 
1583
      if (errorCode)
 
1584
        {
 
1585
          [self cleanup];
 
1586
          
 
1587
          [self netService: self
 
1588
             didNotPublish: CreateError(self, errorCode)];
 
1589
        }
 
1590
      else
 
1591
        {
 
1592
          [self netServiceDidPublish: self];
 
1593
        }
 
1594
    }
 
1595
  UNLOCK(service);
 
1596
}
 
1597
 
 
1598
/**
 
1599
 * <em>Description forthcoming</em>
 
1600
 *
 
1601
 *
 
1602
 */
 
1603
 
 
1604
- (void) loop: (id) sender
 
1605
{
 
1606
  int                   sock = 0;
 
1607
  struct timeval        tout = { 0 };
 
1608
  fd_set                set;
 
1609
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
1610
  
 
1611
  sock = DNSServiceRefSockFD(_netService);
 
1612
  
 
1613
  if (-1 != sock)
 
1614
    {
 
1615
      FD_ZERO(&set);
 
1616
      FD_SET(sock, &set);
 
1617
      
 
1618
      if (1 == select(sock + 1, &set, (fd_set *) NULL, (fd_set *) NULL, &tout))
 
1619
        {
 
1620
          err = DNSServiceProcessResult(_netService);
 
1621
        }
 
1622
    }
 
1623
  
 
1624
  if (kDNSServiceErr_NoError != err)
 
1625
    {
 
1626
      Service   *service;
 
1627
      
 
1628
      service = (Service *) _reserved;
 
1629
      
 
1630
      if (YES == service->isPublishing)
 
1631
        {
 
1632
          [self netService: self
 
1633
             didNotPublish: CreateError(self, err)];
 
1634
        }
 
1635
      else
 
1636
        {
 
1637
          [self netService: self
 
1638
             didNotResolve: CreateError(self, err)];
 
1639
        }
 
1640
    }
 
1641
}
 
1642
 
 
1643
/**
 
1644
 * Converts txtDictionary into a TXT data.
 
1645
 *
 
1646
 *
 
1647
 */
 
1648
 
 
1649
+ (NSData *) dataFromTXTRecordDictionary: (NSDictionary *) txtDictionary
 
1650
{
 
1651
  NSMutableData *result = nil;
 
1652
  NSArray       *keys = nil;
 
1653
  NSArray       *values = nil;
 
1654
  int           count = 0;
 
1655
  
 
1656
  INTERNALTRACE;
 
1657
  
 
1658
  count = [txtDictionary count];
 
1659
  
 
1660
  if (count)
 
1661
    {
 
1662
      keys = [txtDictionary allKeys];
 
1663
      values = [txtDictionary allValues];
 
1664
      
 
1665
      if (keys && values)
 
1666
        {
 
1667
          TXTRecordRef  txt;
 
1668
          int           i = 0;
 
1669
          char          key[256];
 
1670
          
 
1671
          TXTRecordCreate(&txt, 0, NULL);
 
1672
          
 
1673
          for(; i < count; i++)
 
1674
            {
 
1675
              int                       length = 0;
 
1676
              int                       used = 0;
 
1677
              DNSServiceErrorType err = kDNSServiceErr_Unknown;
 
1678
              
 
1679
              if (! [[keys objectAtIndex: i] isKindOfClass: [NSString class]])
 
1680
                {
 
1681
                  LOG(@"%@ is not a string", [keys objectAtIndex: i]);
 
1682
                  break;
 
1683
                }
 
1684
              
 
1685
              length = [[keys objectAtIndex: i] length];
 
1686
              [[keys objectAtIndex: i] getCString: key
 
1687
                                        maxLength: sizeof key];
 
1688
              used = strlen(key);
 
1689
              
 
1690
              if (! length || (used >= sizeof key))
 
1691
                {
 
1692
                  LOG(@"incorrect length %d - %d - %d",
 
1693
                    length, used, sizeof key);
 
1694
                  break;
 
1695
                }
 
1696
              
 
1697
              strcat(key, "\0");
 
1698
              
 
1699
              if ([[values objectAtIndex: i] isKindOfClass: [NSString class]])
 
1700
                {
 
1701
                  char  value[256];
 
1702
                  
 
1703
                  length = [[values objectAtIndex: i] length];
 
1704
                  [[values objectAtIndex: i] getCString: value
 
1705
                                              maxLength: sizeof value];
 
1706
                  used = strlen(value);
 
1707
                  
 
1708
                  if (used >= sizeof value)
 
1709
                    {
 
1710
                      LOG(@"incorrect length %d - %d - %d",
 
1711
                        length, used, sizeof value);
 
1712
                      break;
 
1713
                    }
 
1714
                  
 
1715
                  err = TXTRecordSetValue(&txt,
 
1716
                    (const char *) key,
 
1717
                    used,
 
1718
                    value);
 
1719
                }
 
1720
              else if ([[values objectAtIndex: i] isKindOfClass: [NSData class]]
 
1721
                && [[values objectAtIndex: i] length] < 256
 
1722
                && [[values objectAtIndex: i] length] >= 0)
 
1723
                {
 
1724
                  err = TXTRecordSetValue(&txt,
 
1725
                    (const char *) key,
 
1726
                    [[values objectAtIndex: i] length],
 
1727
                    [[values objectAtIndex: i] bytes]);
 
1728
                }
 
1729
              else if ([values objectAtIndex: i] == [NSNull null])
 
1730
                {
 
1731
                  err = TXTRecordSetValue(&txt,
 
1732
                    (const char *) key,
 
1733
                    0,
 
1734
                    NULL);
 
1735
                }
 
1736
              else
 
1737
                {
 
1738
                  LOG(@"unknown value type");
 
1739
                  break;
 
1740
                }
 
1741
              
 
1742
              if (err != kDNSServiceErr_NoError)
 
1743
                {
 
1744
                  LOG(@"error creating data type");
 
1745
                  break;
 
1746
                }
 
1747
            }
 
1748
          
 
1749
          if (i == count)
 
1750
            {
 
1751
              result = [NSData dataWithBytes: TXTRecordGetBytesPtr(&txt)
 
1752
                                      length: TXTRecordGetLength(&txt)];
 
1753
            }
 
1754
          
 
1755
          TXTRecordDeallocate(&txt);
 
1756
        }
 
1757
      else
 
1758
        {
 
1759
          LOG(@"No keys or values");
 
1760
        }
 
1761
      
 
1762
      // both are autorelease'd
 
1763
      keys = nil;
 
1764
      values = nil;
 
1765
    }
 
1766
  else
 
1767
    {
 
1768
      LOG(@"Dictionary seems empty");
 
1769
    }
 
1770
  return result;
 
1771
}
 
1772
 
 
1773
/**
 
1774
 * Converts the TXT data txtData into a dictionary.
 
1775
 *
 
1776
 *
 
1777
 */
 
1778
 
 
1779
+ (NSDictionary *) dictionaryFromTXTRecordData: (NSData *) txtData
 
1780
{
 
1781
  NSMutableDictionary   *result = nil;
 
1782
  int                   len = 0;
 
1783
  const void            *txt = 0;
 
1784
  
 
1785
  INTERNALTRACE;
 
1786
  
 
1787
  len = [txtData length];
 
1788
  txt = [txtData bytes];
 
1789
  
 
1790
  //
 
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
 
1793
  //
 
1794
  if ((len > 0) && (len < 65536))
 
1795
    {
 
1796
      uint16_t  i = 0;
 
1797
      uint16_t  count = 0;
 
1798
      
 
1799
      // get number of keys
 
1800
      count = TXTRecordGetCount(len, txt);
 
1801
      result = [NSMutableDictionary dictionaryWithCapacity: 1];
 
1802
      
 
1803
      if (result)
 
1804
        {
 
1805
          // go through all keys
 
1806
          for(; i < count; i++)
 
1807
            {
 
1808
              char                      key[256];
 
1809
              uint8_t                   valLen = 0;
 
1810
              const void                *value = NULL;
 
1811
              DNSServiceErrorType       err = kDNSServiceErr_NoError;
 
1812
              
 
1813
              err = TXTRecordGetItemAtIndex(len, txt, i,
 
1814
                sizeof key, key,
 
1815
                &valLen, &value);
 
1816
              
 
1817
              // only if we can get the key and value...
 
1818
              if (kDNSServiceErr_NoError == err)
 
1819
                {
 
1820
                  NSData        *data = nil;
 
1821
                  NSString      *str = nil;
 
1822
                  
 
1823
                  str = [NSString stringWithUTF8String: key];
 
1824
                  
 
1825
                  if (value)
 
1826
                    {
 
1827
                      data = [NSData dataWithBytes: value
 
1828
                                            length: valLen];
 
1829
                    }
 
1830
                  
 
1831
                  if (data && str && [str length]
 
1832
                    && ! [result objectForKey: str])
 
1833
                    {
 
1834
                      /* only add if key and value were created
 
1835
                       * and key doesn't exist yet
 
1836
                       */
 
1837
                      [result setValue: data
 
1838
                                forKey: str];
 
1839
                    }
 
1840
                  else
 
1841
                    {
 
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]
 
1846
                       */
 
1847
                      [result setValue: [NSNull null]
 
1848
                                forKey: str];
 
1849
                    }
 
1850
                  
 
1851
                  // both are autorelease'd
 
1852
                  data = nil;
 
1853
                  str = nil;
 
1854
                }
 
1855
              else
 
1856
                {
 
1857
                  LOG(@"Couldn't get TXTRecord item");
 
1858
                }
 
1859
            }
 
1860
        }
 
1861
      else
 
1862
        {
 
1863
          LOG(@"Couldn't create dictionary");
 
1864
        }
 
1865
    }
 
1866
  else
 
1867
    {
 
1868
      LOG(@"TXT record has incorrect length: <%d>", len);
 
1869
    }
 
1870
  return result;
 
1871
}
 
1872
 
 
1873
/**
 
1874
 * Initializes the receiver for service resolution. Use this method to create
 
1875
 * an object if you intend to -resolve a service.
 
1876
 *
 
1877
 */
 
1878
 
 
1879
- (id) initWithDomain: (NSString *) domain
 
1880
                 type: (NSString *) type
 
1881
                 name: (NSString *) name
 
1882
{
 
1883
  INTERNALTRACE;
 
1884
  
 
1885
  return [self initWithDomain: domain
 
1886
                         type: type
 
1887
                         name: name
 
1888
                         port: -1]; // -1 to indicate resolution, not publish
 
1889
}
 
1890
 
 
1891
/** <init />
 
1892
 * Initializes the receiver for service publication. Use this method to create
 
1893
 * an object if you intend to -publish a service.
 
1894
 *
 
1895
 */
 
1896
 
 
1897
- (id) initWithDomain: (NSString *) domain
 
1898
                 type: (NSString *) type
 
1899
                 name: (NSString *) name
 
1900
                 port: (int) port
 
1901
{
 
1902
  INTERNALTRACE;
 
1903
  
 
1904
  if ((self = [super init]))
 
1905
    {
 
1906
      Service   *service;
 
1907
      
 
1908
      service = malloc(sizeof (struct _Service));
 
1909
      memset(service, 0, sizeof service);
 
1910
      
 
1911
      CREATELOCK(service);
 
1912
      
 
1913
      service->runloop = nil;
 
1914
      service->runloopmode = nil;
 
1915
      service->timer = nil;
 
1916
      service->timeout = nil;
 
1917
      
 
1918
      service->info = [[NSMutableDictionary alloc] initWithCapacity: 1];
 
1919
      [service->info setObject: [domain retain]
 
1920
                        forKey: @"Domain"];
 
1921
      [service->info setObject: [name retain]
 
1922
                        forKey: @"Name"];
 
1923
      [service->info setObject: [type retain]
 
1924
                        forKey: @"Type"];
 
1925
      
 
1926
      service->foundAddresses = nil;
 
1927
      
 
1928
      service->interfaceIndex = 0;
 
1929
      service->port = htons(port);
 
1930
      
 
1931
      service->monitor = nil;
 
1932
      
 
1933
      service->isPublishing = (-1 == port) ? NO : YES;
 
1934
      service->isMonitoring = NO;
 
1935
      
 
1936
      _netService = NULL;
 
1937
      _delegate = nil;
 
1938
      _reserved = service;
 
1939
      
 
1940
      return self;
 
1941
    }
 
1942
  
 
1943
  return nil;
 
1944
}
 
1945
 
 
1946
/**
 
1947
 * Removes the service from the specified run loop.
 
1948
 *
 
1949
 *
 
1950
 */
 
1951
 
 
1952
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
 
1953
                   forMode: (NSString *) mode
 
1954
{
 
1955
  Service       *service;
 
1956
  
 
1957
  INTERNALTRACE;
 
1958
  
 
1959
  service = (Service *) _reserved;
 
1960
  
 
1961
  LOCK(service);
 
1962
  {
 
1963
    if (service->timer)
 
1964
      {
 
1965
        [service->timer setFireDate: [NSDate date]];
 
1966
        [service->timer invalidate];
 
1967
        
 
1968
        // Do not release the timer!
 
1969
        service->timer = nil;
 
1970
      }
 
1971
    
 
1972
    // Do not release the runloop!
 
1973
    service->runloop = nil;
 
1974
    
 
1975
    DESTROY(service->runloopmode);
 
1976
  }
 
1977
  UNLOCK(service);
 
1978
}
 
1979
 
 
1980
/**
 
1981
 * Adds the service to the specified run loop.
 
1982
 *
 
1983
 *
 
1984
 */
 
1985
 
 
1986
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
 
1987
                   forMode: (NSString *) mode
 
1988
{
 
1989
  Service       *service;
 
1990
  
 
1991
  INTERNALTRACE;
 
1992
  
 
1993
  service = (Service *) _reserved;
 
1994
  
 
1995
  LOCK(service);
 
1996
  {
 
1997
    if (service->timer)
 
1998
      {
 
1999
        [service->timer setFireDate: [NSDate date]];
 
2000
        [service->timer invalidate];
 
2001
        service->timer = nil;
 
2002
      }
 
2003
    
 
2004
    service->timer = [NSTimer timerWithTimeInterval: INTERVAL
 
2005
                                             target: self
 
2006
                                           selector: @selector(loop:)
 
2007
                                           userInfo: nil
 
2008
                                            repeats: YES];
 
2009
    
 
2010
    service->runloop = aRunLoop;
 
2011
    service->runloopmode = mode;
 
2012
    
 
2013
    [service->timer retain];
 
2014
  }
 
2015
  UNLOCK(service);
 
2016
}
 
2017
 
 
2018
/**
 
2019
 * Attempts to publish a service on the network.
 
2020
 *
 
2021
 *
 
2022
 */
 
2023
 
 
2024
- (void) publish
 
2025
{
 
2026
  Service               *service;
 
2027
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
2028
  DNSServiceFlags       flags = 0;
 
2029
  
 
2030
  INTERNALTRACE;
 
2031
  
 
2032
  service = (Service *) _reserved;
 
2033
  
 
2034
  LOCK(service);
 
2035
  {
 
2036
    do
 
2037
      {
 
2038
        // cannot -publish on a service that's init'd for resolving
 
2039
        if (NO == service->isPublishing)
 
2040
          {
 
2041
            err = NSNetServicesBadArgumentError;
 
2042
            break;
 
2043
          }
 
2044
        
 
2045
        if (! _delegate)
 
2046
          {
 
2047
            err = NSNetServicesInvalidError;
 
2048
            break;
 
2049
          }
 
2050
        
 
2051
        if (service->timer)
 
2052
          {
 
2053
            err = NSNetServicesActivityInProgress;
 
2054
            break;
 
2055
          }
 
2056
        
 
2057
        if (service->timeout)
 
2058
          {
 
2059
            [service->timeout setFireDate: [NSDate date]];
 
2060
            [service->timeout invalidate];
 
2061
            service->timeout = nil;
 
2062
          }
 
2063
        
 
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);
 
2071
      }
 
2072
    while(0);
 
2073
  }
 
2074
  UNLOCK(service);
 
2075
  
 
2076
  [self executeWithError: err];
 
2077
}
 
2078
 
 
2079
/**
 
2080
 * This method is deprecated. Use -resolveWithTimeout: instead.
 
2081
 *
 
2082
 *
 
2083
 */
 
2084
 
 
2085
- (void) resolve
 
2086
{
 
2087
  INTERNALTRACE;
 
2088
  
 
2089
  [self resolveWithTimeout: 5];
 
2090
}
 
2091
 
 
2092
/**
 
2093
 * Starts a service resolution for a limited duration.
 
2094
 *
 
2095
 *
 
2096
 */
 
2097
 
 
2098
- (void) resolveWithTimeout: (NSTimeInterval) timeout
 
2099
{
 
2100
  Service               *service;
 
2101
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
2102
  DNSServiceFlags       flags = 0;
 
2103
  
 
2104
  INTERNALTRACE;
 
2105
  
 
2106
  service = (Service *) _reserved;
 
2107
  
 
2108
  LOCK(service);
 
2109
  {
 
2110
    do
 
2111
      {
 
2112
        // cannot -resolve on a service that's init'd for publishing
 
2113
        if (YES == service->isPublishing)
 
2114
          {
 
2115
            err = NSNetServicesBadArgumentError;
 
2116
            break;
 
2117
          }
 
2118
        
 
2119
        if (! _delegate)
 
2120
          {
 
2121
            err = NSNetServicesInvalidError;
 
2122
            break;
 
2123
          }
 
2124
        
 
2125
        if (service->timer)
 
2126
          {
 
2127
            err = NSNetServicesActivityInProgress;
 
2128
            break;
 
2129
          }
 
2130
        
 
2131
        if (service->timeout)
 
2132
          {
 
2133
            [service->timeout setFireDate: [NSDate date]];
 
2134
            [service->timeout invalidate];
 
2135
            service->timeout = nil;
 
2136
          }
 
2137
        
 
2138
        service->timeout = [NSTimer alloc];
 
2139
        {
 
2140
          NSDate        *date = nil;
 
2141
          
 
2142
          date = [NSDate dateWithTimeIntervalSinceNow: timeout + SHORTTIMEOUT];
 
2143
          
 
2144
          [service->timeout initWithFireDate: date
 
2145
                                    interval: INTERVAL
 
2146
                                      target: self
 
2147
                                    selector: @selector(stopResolving:)
 
2148
                                    userInfo: nil
 
2149
                                     repeats: NO];
 
2150
        }
 
2151
        
 
2152
        err = DNSServiceResolve((DNSServiceRef *) &_netService,
 
2153
          flags,
 
2154
          service->interfaceIndex,
 
2155
          [[service->info objectForKey: @"Name"] UTF8String],
 
2156
          [[service->info objectForKey: @"Type"] UTF8String],
 
2157
          [[service->info objectForKey: @"Domain"] UTF8String],
 
2158
          ResolverCallback,
 
2159
          self);
 
2160
      }
 
2161
    while(0);
 
2162
  }
 
2163
  UNLOCK(service);
 
2164
  
 
2165
  [self executeWithError: err];
 
2166
}
 
2167
 
 
2168
/**
 
2169
 * Stops the current attempt to publish or resolve a service.
 
2170
 *
 
2171
 *
 
2172
 */
 
2173
 
 
2174
- (void) stop
 
2175
{
 
2176
  Service       *service;
 
2177
  
 
2178
  INTERNALTRACE;
 
2179
  
 
2180
  service = (Service *) _reserved;
 
2181
  
 
2182
  LOCK(service);
 
2183
  {
 
2184
    [self cleanup];
 
2185
    
 
2186
    [self netServiceDidStop: self];
 
2187
  }
 
2188
  UNLOCK(service);
 
2189
}
 
2190
 
 
2191
/**
 
2192
 * Starts monitoring of TXT record updates.
 
2193
 *
 
2194
 *
 
2195
 */
 
2196
 
 
2197
- (void) startMonitoring
 
2198
{
 
2199
  Service       *service;
 
2200
  
 
2201
  INTERNALTRACE;
 
2202
  
 
2203
  service = (Service *) _reserved;
 
2204
  
 
2205
  LOCK(service);
 
2206
  {
 
2207
    // Obviously this will only work on a resolver
 
2208
    if (! service->isPublishing)
 
2209
      {
 
2210
        if (! service->isMonitoring)
 
2211
          {
 
2212
            service->monitor
 
2213
              = [[NSNetServiceMonitor alloc] initWithDelegate: self];
 
2214
            
 
2215
            [service->monitor scheduleInRunLoop: service->runloop
 
2216
                                        forMode: service->runloopmode];
 
2217
            [service->monitor start];
 
2218
            
 
2219
            service->isMonitoring = YES;
 
2220
          }
 
2221
      }
 
2222
  }
 
2223
  UNLOCK(service);
 
2224
}
 
2225
 
 
2226
/**
 
2227
 * Stops monitoring of TXT record updates.
 
2228
 *
 
2229
 *
 
2230
 */
 
2231
 
 
2232
- (void) stopMonitoring
 
2233
{
 
2234
  Service       *service;
 
2235
  
 
2236
  INTERNALTRACE;
 
2237
  
 
2238
  service = (Service *) _reserved;
 
2239
  
 
2240
  LOCK(service);
 
2241
  {
 
2242
    if (! service->isPublishing)
 
2243
      {
 
2244
        if (service->isMonitoring)
 
2245
          {
 
2246
            [service->monitor stop];
 
2247
            
 
2248
            // Probably don't need it anymore, so release it
 
2249
            DESTROY(service->monitor);
 
2250
            service->isMonitoring = NO;
 
2251
          }
 
2252
      }
 
2253
  }
 
2254
  UNLOCK(service);
 
2255
}
 
2256
 
 
2257
/**
 
2258
 * Returns the receiver's delegate.
 
2259
 *
 
2260
 *
 
2261
 */
 
2262
 
 
2263
- (id) delegate
 
2264
{
 
2265
  INTERNALTRACE;
 
2266
  
 
2267
  return [[_delegate retain] autorelease];
 
2268
}
 
2269
 
 
2270
/**
 
2271
 * Sets the receiver's delegate.
 
2272
 *
 
2273
 *
 
2274
 */
 
2275
 
 
2276
- (void) setDelegate: (id) delegate
 
2277
{
 
2278
  INTERNALTRACE;
 
2279
  
 
2280
  ASSIGN(_delegate, delegate);
 
2281
}
 
2282
 
 
2283
/**
 
2284
 * Returns an array of NSData objects that each contain the socket address of
 
2285
 * the service.
 
2286
 *
 
2287
 */
 
2288
 
 
2289
- (NSArray *) addresses
 
2290
{
 
2291
  INTERNALTRACE;
 
2292
  
 
2293
  return [((Service*)_reserved)->info objectForKey: @"Addresses"];
 
2294
}
 
2295
 
 
2296
/**
 
2297
 * Returns the domain name of the service.
 
2298
 *
 
2299
 *
 
2300
 */
 
2301
 
 
2302
- (NSString *) domain
 
2303
{
 
2304
  INTERNALTRACE;
 
2305
  
 
2306
  return [((Service*)_reserved)->info objectForKey: @"Domain"];
 
2307
}
 
2308
 
 
2309
/**
 
2310
 * Returns the host name of the computer publishing the service.
 
2311
 *
 
2312
 *
 
2313
 */
 
2314
 
 
2315
- (NSString *) hostName
 
2316
{
 
2317
  INTERNALTRACE;
 
2318
  
 
2319
  return [((Service*)_reserved)->info objectForKey: @"Host"];
 
2320
}
 
2321
 
 
2322
/**
 
2323
 * Returns the name of the service.
 
2324
 *
 
2325
 *
 
2326
 */
 
2327
 
 
2328
- (NSString *) name
 
2329
{
 
2330
  INTERNALTRACE;
 
2331
  
 
2332
  return [((Service*)_reserved)->info objectForKey: @"Name"];
 
2333
}
 
2334
 
 
2335
/**
 
2336
 * Returns the type of the service.
 
2337
 *
 
2338
 *
 
2339
 */
 
2340
 
 
2341
- (NSString *) type
 
2342
{
 
2343
  INTERNALTRACE;
 
2344
  
 
2345
  return [((Service*)_reserved)->info objectForKey: @"Type"];
 
2346
}
 
2347
 
 
2348
/**
 
2349
 * This method is deprecated. Use -TXTRecordData instead.
 
2350
 *
 
2351
 *
 
2352
 */
 
2353
 
 
2354
- (NSString *) protocolSpecificInformation
 
2355
{
 
2356
  NSMutableArray        *array = nil;
 
2357
  Service               *service;
 
2358
  
 
2359
  INTERNALTRACE;
 
2360
  
 
2361
  service = (Service *) _reserved;
 
2362
  
 
2363
  //
 
2364
  // I must admit, the following may not be entirely correct...
 
2365
  //
 
2366
  LOCK(service);
 
2367
  {
 
2368
    NSDictionary        *dictionary = nil;
 
2369
    
 
2370
    dictionary = [NSNetService dictionaryFromTXTRecordData:
 
2371
      [self TXTRecordData]];
 
2372
    
 
2373
    if (dictionary)
 
2374
      {
 
2375
        NSEnumerator    *keys = nil;
 
2376
        NSString        *key = nil;
 
2377
        
 
2378
        array = [NSMutableArray arrayWithCapacity: [dictionary count]];
 
2379
        keys = [dictionary keyEnumerator];
 
2380
        
 
2381
        while((key = [keys nextObject]))
 
2382
          {
 
2383
            NSData      *value = nil;
 
2384
            
 
2385
            value = [dictionary objectForKey: key];
 
2386
            
 
2387
            if (value != (NSData *) [NSNull null])
 
2388
              {
 
2389
                NSData          *str;
 
2390
                NSString        *pair;
 
2391
 
 
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];
 
2398
                RELEASE(str);
 
2399
 
 
2400
                [array addObject: pair];
 
2401
              }
 
2402
            else if ([key length])
 
2403
              {
 
2404
                [array addObject: [NSString stringWithFormat: @"%@", key]];
 
2405
              }
 
2406
          }
 
2407
      }
 
2408
  }
 
2409
  UNLOCK(service);
 
2410
  
 
2411
  return ([array count] ? [array componentsJoinedByString: @"\001"]
 
2412
    : (NSString *) nil);
 
2413
}
 
2414
 
 
2415
/**
 
2416
 * This method is deprecated. Use -setTXTRecordData: instead.
 
2417
 *
 
2418
 *
 
2419
 */
 
2420
 
 
2421
- (void) setProtocolSpecificInformation: (NSString *) specificInformation
 
2422
{
 
2423
  Service       *service;
 
2424
  
 
2425
  INTERNALTRACE;
 
2426
  
 
2427
  service = (Service *) _reserved;
 
2428
  
 
2429
  //
 
2430
  // Again, the following may not be entirely correct...
 
2431
  //
 
2432
  LOCK(service);
 
2433
  {
 
2434
    NSArray     *array = nil;
 
2435
    
 
2436
    array = [specificInformation componentsSeparatedByString: @"\001"];
 
2437
    
 
2438
    if (array)
 
2439
      {
 
2440
        NSMutableDictionary     *dictionary = nil;
 
2441
        NSEnumerator            *enumerator = nil;
 
2442
        NSString                *item = nil;
 
2443
        
 
2444
        dictionary
 
2445
          = [NSMutableDictionary dictionaryWithCapacity: [array count]];
 
2446
        enumerator = [array objectEnumerator];
 
2447
        
 
2448
        while((item = [enumerator nextObject]))
 
2449
          {
 
2450
            NSArray     *parts = nil;
 
2451
            NSData      *value;
 
2452
            
 
2453
            parts = [item componentsSeparatedByString:@"="];
 
2454
            
 
2455
            value = [[parts objectAtIndex: 1]
 
2456
              dataUsingEncoding: NSUTF8StringEncoding];
 
2457
            [dictionary setObject: value
 
2458
                           forKey: [parts objectAtIndex: 0]];
 
2459
          }
 
2460
        
 
2461
        [self setTXTRecordData:
 
2462
          [NSNetService dataFromTXTRecordDictionary: dictionary]];
 
2463
      }
 
2464
  }
 
2465
  UNLOCK(service);
 
2466
}
 
2467
 
 
2468
/**
 
2469
 * Returns the TXT record.
 
2470
 *
 
2471
 *
 
2472
 */
 
2473
 
 
2474
- (NSData *) TXTRecordData
 
2475
{
 
2476
  INTERNALTRACE;
 
2477
  
 
2478
  return [((Service*)_reserved)->info objectForKey: @"TXT"];
 
2479
}
 
2480
 
 
2481
/**
 
2482
 * Sets the TXT record.
 
2483
 *
 
2484
 *
 
2485
 */
 
2486
 
 
2487
- (BOOL) setTXTRecordData: (NSData *) recordData
 
2488
{
 
2489
  Service       *service;
 
2490
  BOOL          result = NO;
 
2491
  
 
2492
  INTERNALTRACE;
 
2493
  
 
2494
  service = (Service *) _reserved;
 
2495
  
 
2496
  LOCK(service);
 
2497
  {
 
2498
    // Not allowed on a resolver...
 
2499
    if (service->isPublishing)
 
2500
      {
 
2501
        DNSServiceErrorType
 
2502
          err = kDNSServiceErr_NoError;
 
2503
        
 
2504
        // Set the value, or remove it if empty
 
2505
        if (recordData)
 
2506
          {
 
2507
            [service->info setObject: recordData
 
2508
                              forKey: @"TXT"];
 
2509
          }
 
2510
        else
 
2511
          {
 
2512
            [service->info removeObjectForKey: @"TXT"];
 
2513
          }
 
2514
        
 
2515
        // Assume it worked
 
2516
        result = YES;
 
2517
        
 
2518
        // Now update the record so others can pick it up
 
2519
        err = DNSServiceUpdateRecord(_netService,
 
2520
          NULL,
 
2521
          0,
 
2522
          recordData ? [recordData length] : 0,
 
2523
          recordData ? [recordData bytes] : NULL,
 
2524
          0);
 
2525
        if (err)
 
2526
          {
 
2527
            result = NO;
 
2528
          }
 
2529
      }
 
2530
  }
 
2531
  UNLOCK(service);
 
2532
  
 
2533
  return result;
 
2534
}
 
2535
 
 
2536
/**
 
2537
 * Retrieves the input and output stream for the receiver.
 
2538
 *
 
2539
 *
 
2540
 */
 
2541
 
 
2542
- (BOOL) getInputStream: (NSInputStream **) inputStream
 
2543
           outputStream: (NSOutputStream **) outputStream
 
2544
{
 
2545
  Service       *service;
 
2546
  
 
2547
  INTERNALTRACE;
 
2548
  
 
2549
  service = (Service *) _reserved;
 
2550
  
 
2551
  LOCK(service);
 
2552
  {
 
2553
    [NSStream getStreamsToHost: [service->info objectForKey: @"Host"]
 
2554
                          port: ntohs(service->port)
 
2555
                   inputStream: inputStream
 
2556
                  outputStream: outputStream];
 
2557
  }
 
2558
  UNLOCK(service);
 
2559
  
 
2560
  return inputStream && outputStream;
 
2561
}
 
2562
 
 
2563
/**
 
2564
 * <em>Description forthcoming</em>
 
2565
 *
 
2566
 *
 
2567
 */
 
2568
 
 
2569
- (void) netServiceWillPublish: (NSNetService *) sender
 
2570
{
 
2571
  INTERNALTRACE;
 
2572
  
 
2573
  if ([_delegate respondsToSelector: @selector(netServiceWillPublish:)])
 
2574
    {
 
2575
      [_delegate netServiceWillPublish: sender];
 
2576
    }
 
2577
}
 
2578
 
 
2579
/**
 
2580
 * <em>Description forthcoming</em>
 
2581
 *
 
2582
 *
 
2583
 */
 
2584
 
 
2585
- (void) netServiceDidPublish: (NSNetService *) sender
 
2586
{
 
2587
  INTERNALTRACE;
 
2588
  
 
2589
  if ([_delegate respondsToSelector: @selector(netServiceDidPublish:)])
 
2590
    {
 
2591
      [_delegate netServiceDidPublish: sender];
 
2592
    }
 
2593
}
 
2594
 
 
2595
/**
 
2596
 * <em>Description forthcoming</em>
 
2597
 *
 
2598
 *
 
2599
 */
 
2600
 
 
2601
- (void) netService: (NSNetService *) sender
 
2602
      didNotPublish: (NSDictionary *) errorDict
 
2603
{
 
2604
  INTERNALTRACE;
 
2605
  
 
2606
  if ([_delegate respondsToSelector: @selector(netService:didNotPublish:)])
 
2607
    {
 
2608
      [_delegate netService: sender
 
2609
              didNotPublish: errorDict];
 
2610
    }
 
2611
}
 
2612
 
 
2613
/**
 
2614
 * <em>Description forthcoming</em>
 
2615
 *
 
2616
 *
 
2617
 */
 
2618
 
 
2619
- (void) netServiceWillResolve: (NSNetService *) sender
 
2620
{
 
2621
  INTERNALTRACE;
 
2622
  
 
2623
  if ([_delegate respondsToSelector: @selector(netServiceWillResolve:)])
 
2624
    {
 
2625
      [_delegate netServiceWillResolve: sender];
 
2626
    }
 
2627
}
 
2628
 
 
2629
/**
 
2630
 * <em>Description forthcoming</em>
 
2631
 *
 
2632
 *
 
2633
 */
 
2634
 
 
2635
- (void) netServiceDidResolveAddress: (NSNetService *) sender
 
2636
{
 
2637
  INTERNALTRACE;
 
2638
  
 
2639
  if ([_delegate respondsToSelector: @selector(netServiceDidResolveAddress:)])
 
2640
    {
 
2641
      [_delegate netServiceDidResolveAddress: sender];
 
2642
    }
 
2643
}
 
2644
 
 
2645
/**
 
2646
 * <em>Description forthcoming</em>
 
2647
 *
 
2648
 *
 
2649
 */
 
2650
 
 
2651
- (void) netService: (NSNetService *) sender
 
2652
      didNotResolve: (NSDictionary *) errorDict
 
2653
{
 
2654
  INTERNALTRACE;
 
2655
  
 
2656
  if ([_delegate respondsToSelector: @selector(netService:didNotResolve:)])
 
2657
    {
 
2658
      [_delegate netService: sender
 
2659
              didNotResolve: errorDict];
 
2660
    }
 
2661
}
 
2662
 
 
2663
/**
 
2664
 * <em>Description forthcoming</em>
 
2665
 *
 
2666
 *
 
2667
 */
 
2668
 
 
2669
- (void) netServiceDidStop: (NSNetService *) sender
 
2670
{
 
2671
  INTERNALTRACE;
 
2672
  
 
2673
  if ([_delegate respondsToSelector: @selector(netServiceDidStop:)])
 
2674
    {
 
2675
      [_delegate netServiceDidStop: sender];
 
2676
    }
 
2677
}
 
2678
 
 
2679
/**
 
2680
 * <em>Description forthcoming</em>
 
2681
 *
 
2682
 *
 
2683
 */
 
2684
 
 
2685
- (void)      netService: (NSNetService *) sender
 
2686
  didUpdateTXTRecordData: (NSData *) data
 
2687
{
 
2688
  INTERNALTRACE;
 
2689
  
 
2690
  if ([_delegate respondsToSelector:
 
2691
    @selector(netService:didUpdateTXTRecordData:)])
 
2692
    {
 
2693
      [_delegate   netService: sender
 
2694
       didUpdateTXTRecordData: data];
 
2695
    }
 
2696
}
 
2697
 
 
2698
/**
 
2699
 * <em>Description forthcoming</em>
 
2700
 *
 
2701
 *
 
2702
 */
 
2703
 
 
2704
- (void) netService: (NSNetService *) sender
 
2705
      didNotMonitor: (NSDictionary *) errorDict
 
2706
{
 
2707
  INTERNALTRACE;
 
2708
  
 
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.
 
2713
  
 
2714
  [self stopMonitoring];
 
2715
}
 
2716
 
 
2717
/**
 
2718
 * <em>Description forthcoming</em>
 
2719
 *
 
2720
 *
 
2721
 */
 
2722
 
 
2723
- (id) init
 
2724
{
 
2725
  DESTROY(self);
 
2726
  return self;
 
2727
}
 
2728
 
 
2729
/**
 
2730
 * <em>Description forthcoming</em>
 
2731
 *
 
2732
 *
 
2733
 */
 
2734
 
 
2735
- (void) dealloc
 
2736
{
 
2737
  Service       *service;
 
2738
  
 
2739
  INTERNALTRACE;
 
2740
  
 
2741
  service = (Service *) _reserved;
 
2742
  {
 
2743
    LOCK(service);
 
2744
    {
 
2745
      [self stopMonitoring];
 
2746
      [self cleanup];
 
2747
      
 
2748
      DESTROY(service->info);
 
2749
      DESTROY(service->foundAddresses);
 
2750
      DESTROY(_delegate);
 
2751
    }
 
2752
    UNLOCK(service);
 
2753
    
 
2754
    DESTROYLOCK(service);
 
2755
    
 
2756
    free(service);
 
2757
  }
 
2758
  [super dealloc];
 
2759
}
 
2760
 
 
2761
@end
 
2762
 
 
2763
@implementation NSNetServiceMonitor
 
2764
 
 
2765
/**
 
2766
 * <em>Description forthcoming</em>
 
2767
 *
 
2768
 *
 
2769
 */
 
2770
 
 
2771
+ (void) initialize
 
2772
{
 
2773
  INTERNALTRACE;
 
2774
  
 
2775
  SETVERSION(NSNetServiceMonitor);
 
2776
}
 
2777
 
 
2778
/**
 
2779
 * <em>Description forthcoming</em>
 
2780
 *
 
2781
 *
 
2782
 */
 
2783
 
 
2784
- (void) loop: (id) sender
 
2785
{
 
2786
  int                   sock = 0;
 
2787
  struct timeval        tout = { 0 };
 
2788
  fd_set                set;
 
2789
  DNSServiceErrorType   err = kDNSServiceErr_NoError;
 
2790
  
 
2791
  sock = DNSServiceRefSockFD(_netServiceMonitor);
 
2792
  
 
2793
  if (-1 != sock)
 
2794
    {
 
2795
      FD_ZERO(&set);
 
2796
      FD_SET(sock, &set);
 
2797
      
 
2798
      if (1 == select(sock + 1, &set, (fd_set *) NULL, (fd_set *) NULL, &tout))
 
2799
        {
 
2800
          err = DNSServiceProcessResult(_netServiceMonitor);
 
2801
        }
 
2802
    }
 
2803
  
 
2804
  if (kDNSServiceErr_NoError != err)
 
2805
    {
 
2806
      LOG(@"Error <%d> while monitoring", err);
 
2807
      
 
2808
      [_delegate netService: _delegate
 
2809
              didNotMonitor: CreateError(self, err)];
 
2810
    }
 
2811
}
 
2812
 
 
2813
/**
 
2814
 * <em>Description forthcoming</em>
 
2815
 *
 
2816
 *
 
2817
 */
 
2818
 
 
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
 
2828
                   ttl: (uint32_t) ttl
 
2829
{
 
2830
  Monitor       *monitor;
 
2831
  
 
2832
  INTERNALTRACE;
 
2833
  
 
2834
  monitor = (Monitor *) _reserved;
 
2835
  
 
2836
  LOCK(monitor);
 
2837
  
 
2838
  if (_delegate)
 
2839
    {
 
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
 
2844
                         flags: flags
 
2845
                     interface: interfaceIndex
 
2846
                         error: errorCode
 
2847
                      fullname: fullname
 
2848
                          type: rrtype
 
2849
                         class: rrclass
 
2850
                        length: rdlen
 
2851
                          data: rdata
 
2852
                           ttl: ttl];
 
2853
    }
 
2854
  UNLOCK(monitor);
 
2855
}
 
2856
 
 
2857
/**
 
2858
 * <em>Description forthcoming</em>
 
2859
 *
 
2860
 *
 
2861
 */
 
2862
 
 
2863
- (id) initWithDelegate: (id) delegate
 
2864
{
 
2865
  INTERNALTRACE;
 
2866
  
 
2867
  if ((self = [super init]) != nil)
 
2868
    {
 
2869
      Monitor   *monitor;
 
2870
      
 
2871
      monitor = malloc(sizeof (struct _Monitor));
 
2872
      memset(monitor, 0, sizeof monitor);
 
2873
      
 
2874
      CREATELOCK(monitor);
 
2875
      
 
2876
      monitor->runloop = nil;
 
2877
      monitor->runloopmode = nil;
 
2878
      monitor->timer = nil;
 
2879
      
 
2880
      _netServiceMonitor = NULL;
 
2881
      _delegate = [delegate retain];
 
2882
      _reserved = monitor;
 
2883
    }
 
2884
  return self;
 
2885
}
 
2886
 
 
2887
/**
 
2888
 * <em>Description forthcoming</em>
 
2889
 *
 
2890
 *
 
2891
 */
 
2892
 
 
2893
- (void) removeFromRunLoop: (NSRunLoop *) aRunLoop
 
2894
                   forMode: (NSString *) mode
 
2895
{
 
2896
  Monitor       *monitor;
 
2897
  
 
2898
  INTERNALTRACE;
 
2899
  
 
2900
  monitor = (Monitor *) _reserved;
 
2901
  
 
2902
  LOCK(monitor);
 
2903
  {
 
2904
    if (monitor->timer)
 
2905
      {
 
2906
        [monitor->timer setFireDate: [NSDate date]];
 
2907
        [monitor->timer invalidate];
 
2908
        monitor->timer = nil;
 
2909
      }
 
2910
    
 
2911
    // Do not release the runloop!
 
2912
    monitor->runloop = nil;
 
2913
    
 
2914
    // [monitor->runloopmode release];
 
2915
    monitor->runloopmode = nil;
 
2916
  }
 
2917
  UNLOCK(monitor);
 
2918
}
 
2919
 
 
2920
/**
 
2921
 * <em>Description forthcoming</em>
 
2922
 *
 
2923
 *
 
2924
 */
 
2925
 
 
2926
- (void) scheduleInRunLoop: (NSRunLoop *) aRunLoop
 
2927
                   forMode: (NSString *) mode
 
2928
{
 
2929
  Monitor       *monitor;
 
2930
  
 
2931
  INTERNALTRACE;
 
2932
  
 
2933
  monitor = (Monitor *) _reserved;
 
2934
  
 
2935
  LOCK(monitor);
 
2936
  {
 
2937
    if (monitor->timer)
 
2938
      {
 
2939
        [monitor->timer setFireDate: [NSDate date]];
 
2940
        [monitor->timer invalidate];
 
2941
        monitor->timer = nil;
 
2942
      }
 
2943
    
 
2944
    monitor->runloop = aRunLoop;
 
2945
    monitor->runloopmode = mode;
 
2946
  }
 
2947
  UNLOCK(monitor);
 
2948
}
 
2949
 
 
2950
/**
 
2951
 * <em>Description forthcoming</em>
 
2952
 *
 
2953
 *
 
2954
 */
 
2955
 
 
2956
- (void) start
 
2957
{
 
2958
  Monitor       *monitor;
 
2959
  
 
2960
  INTERNALTRACE;
 
2961
  
 
2962
  monitor = (Monitor *) _reserved;
 
2963
  
 
2964
  LOCK(monitor);
 
2965
  {
 
2966
    DNSServiceErrorType err = kDNSServiceErr_NoError;
 
2967
    DNSServiceFlags     flags = kDNSServiceFlagsLongLivedQuery;
 
2968
    NSString            *fullname = nil;
 
2969
    
 
2970
    do
 
2971
      {
 
2972
        if (! _delegate)
 
2973
          {
 
2974
            err = NSNetServicesInvalidError;
 
2975
            break;
 
2976
          }
 
2977
        
 
2978
        if (monitor->timer)
 
2979
          {
 
2980
            err = NSNetServicesActivityInProgress;
 
2981
            break;
 
2982
          }
 
2983
        
 
2984
        fullname = [NSString stringWithFormat: @"%@.%@%@",
 
2985
          [_delegate name], [_delegate type], [_delegate domain]];
 
2986
        
 
2987
        err = DNSServiceQueryRecord((DNSServiceRef *) &_netServiceMonitor,
 
2988
          flags,
 
2989
          0,
 
2990
          [fullname UTF8String],
 
2991
          kDNSServiceType_TXT,
 
2992
          kDNSServiceClass_IN,
 
2993
          QueryCallback,
 
2994
          self);
 
2995
        
 
2996
        if (kDNSServiceErr_NoError == err)
 
2997
          {
 
2998
            monitor->timer = [NSTimer timerWithTimeInterval: INTERVAL
 
2999
                                                     target: self
 
3000
                                                   selector: @selector(loop:)
 
3001
                                                   userInfo: nil
 
3002
                                                    repeats: YES];
 
3003
 
 
3004
            [monitor->runloop addTimer: monitor->timer
 
3005
                               forMode: monitor->runloopmode];
 
3006
            
 
3007
            [monitor->timer fire];
 
3008
          }
 
3009
      }
 
3010
    while(0);
 
3011
  }
 
3012
  UNLOCK(monitor);
 
3013
}
 
3014
 
 
3015
/**
 
3016
 * <em>Description forthcoming</em>
 
3017
 *
 
3018
 *
 
3019
 */
 
3020
 
 
3021
- (void) stop
 
3022
{
 
3023
  Monitor       *monitor;
 
3024
  
 
3025
  INTERNALTRACE;
 
3026
  
 
3027
  monitor = (Monitor *) _reserved;
 
3028
  
 
3029
  LOCK(monitor);
 
3030
  {
 
3031
    if (monitor->runloop)
 
3032
      {
 
3033
        [self removeFromRunLoop: monitor->runloop
 
3034
                        forMode: monitor->runloopmode];
 
3035
      }
 
3036
    
 
3037
    if (monitor->timer)
 
3038
      {
 
3039
        [monitor->timer invalidate];
 
3040
        monitor->timer = nil;
 
3041
      }
 
3042
    
 
3043
    if (_netServiceMonitor)
 
3044
      {
 
3045
        DNSServiceRefDeallocate(_netServiceMonitor);
 
3046
        _netServiceMonitor = NULL;
 
3047
      }
 
3048
  }
 
3049
  UNLOCK(monitor);
 
3050
}
 
3051
 
 
3052
/**
 
3053
 * <em>Description forthcoming</em>
 
3054
 *
 
3055
 *
 
3056
 */
 
3057
 
 
3058
- (id) init
 
3059
{
 
3060
  DESTROY(self);
 
3061
  return nil;
 
3062
}
 
3063
 
 
3064
/**
 
3065
 * <em>Description forthcoming</em>
 
3066
 *
 
3067
 *
 
3068
 */
 
3069
 
 
3070
- (void) dealloc
 
3071
{
 
3072
  Monitor       *monitor;
 
3073
  
 
3074
  INTERNALTRACE;
 
3075
  
 
3076
  monitor = (Monitor *) _reserved;
 
3077
  {
 
3078
    LOCK(monitor);
 
3079
    {
 
3080
      [self stop];
 
3081
      
 
3082
      _delegate = nil;
 
3083
    }
 
3084
    UNLOCK(monitor);
 
3085
    
 
3086
    DESTROYLOCK(monitor);
 
3087
    
 
3088
    free(monitor);
 
3089
  }
 
3090
  [super dealloc];
 
3091
}
 
3092
 
 
3093
@end
 
3094
 
 
3095
/**
 
3096
 * <em>Description forthcoming</em>
 
3097
 *
 
3098
 *
 
3099
 */
 
3100
 
 
3101
static NSDictionary *
 
3102
CreateError(id sender, int errorCode)
 
3103
{
 
3104
  NSMutableDictionary   *dictionary = nil;
 
3105
  int                   error = 0;
 
3106
  
 
3107
  INTERNALTRACE;
 
3108
  
 
3109
  dictionary = [NSMutableDictionary dictionary];
 
3110
  error = ConvertError(errorCode);
 
3111
  
 
3112
  LOG(@"%@ says error <%d> - <%d>", [sender description], errorCode, error);
 
3113
  
 
3114
  [dictionary setObject: [NSNumber numberWithInt: error]
 
3115
                 forKey: NSNetServicesErrorCode];
 
3116
  [dictionary setObject: sender
 
3117
                 forKey: NSNetServicesErrorDomain];
 
3118
  
 
3119
  return dictionary; // autorelease'd
 
3120
}
 
3121
 
 
3122
/**
 
3123
 * <em>Description forthcoming</em>
 
3124
 *
 
3125
 *
 
3126
 */
 
3127
 
 
3128
static int
 
3129
ConvertError(int errorCode)
 
3130
{
 
3131
  INTERNALTRACE;
 
3132
  
 
3133
  switch(errorCode)
 
3134
    {
 
3135
      case kDNSServiceErr_Unknown:
 
3136
        return NSNetServicesUnknownError;
 
3137
      
 
3138
      case kDNSServiceErr_NoSuchName:
 
3139
        return NSNetServicesNotFoundError;
 
3140
      
 
3141
      case kDNSServiceErr_NoMemory:
 
3142
        return NSNetServicesUnknownError;
 
3143
      
 
3144
      case kDNSServiceErr_BadParam:
 
3145
      case kDNSServiceErr_BadReference:
 
3146
      case kDNSServiceErr_BadState:
 
3147
      case kDNSServiceErr_BadFlags:
 
3148
        return NSNetServicesBadArgumentError;
 
3149
      
 
3150
      case kDNSServiceErr_Unsupported:
 
3151
        return NSNetServicesUnknownError;
 
3152
      
 
3153
      case kDNSServiceErr_NotInitialized:
 
3154
        return NSNetServicesInvalidError;
 
3155
      
 
3156
      case kDNSServiceErr_AlreadyRegistered:
 
3157
      case kDNSServiceErr_NameConflict:
 
3158
        return NSNetServicesCollisionError;
 
3159
      
 
3160
      case kDNSServiceErr_Invalid:
 
3161
        return NSNetServicesInvalidError;
 
3162
      
 
3163
      case kDNSServiceErr_Firewall:
 
3164
        return NSNetServicesUnknownError;
 
3165
      
 
3166
      case kDNSServiceErr_Incompatible:
 
3167
        // The client library is incompatible with the daemon
 
3168
        return NSNetServicesInvalidError;
 
3169
      
 
3170
      case kDNSServiceErr_BadInterfaceIndex:
 
3171
      case kDNSServiceErr_Refused:
 
3172
        return NSNetServicesUnknownError;
 
3173
      
 
3174
      case kDNSServiceErr_NoSuchRecord:
 
3175
      case kDNSServiceErr_NoAuth:
 
3176
      case kDNSServiceErr_NoSuchKey:
 
3177
        return NSNetServicesNotFoundError;
 
3178
      
 
3179
      case kDNSServiceErr_NATTraversal:
 
3180
      case kDNSServiceErr_DoubleNAT:
 
3181
      case kDNSServiceErr_BadTime:
 
3182
        return NSNetServicesUnknownError;
 
3183
    }
 
3184
  
 
3185
  return errorCode;
 
3186
}
 
3187
 
 
3188
/**
 
3189
 * <em>Description forthcoming</em>
 
3190
 *
 
3191
 *
 
3192
 */
 
3193
 
 
3194
static void
 
3195
EnumerationCallback(DNSServiceRef sdRef,
 
3196
                      DNSServiceFlags flags,
 
3197
                      uint32_t interfaceIndex,
 
3198
                      DNSServiceErrorType  errorCode,
 
3199
                      const char *replyDomain,
 
3200
                      void *context)
 
3201
{
 
3202
  // NSNetServiceBrowser
 
3203
  [(id) context enumCallback: sdRef
 
3204
                       flags: flags
 
3205
                   interface: interfaceIndex
 
3206
                       error: errorCode
 
3207
                      domain: replyDomain];
 
3208
}
 
3209
 
 
3210
/**
 
3211
 * <em>Description forthcoming</em>
 
3212
 *
 
3213
 *
 
3214
 */
 
3215
 
 
3216
static void
 
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,
 
3224
                  void *context)
 
3225
{
 
3226
  // NSNetServiceBrowser
 
3227
  [(id) context browseCallback: sdRef
 
3228
                         flags: flags
 
3229
                     interface: interfaceIndex
 
3230
                         error: errorCode
 
3231
                          name: replyName
 
3232
                          type: replyType
 
3233
                        domain: replyDomain];
 
3234
}
 
3235
 
 
3236
/**
 
3237
 * <em>Description forthcoming</em>
 
3238
 *
 
3239
 *
 
3240
 */
 
3241
 
 
3242
static void
 
3243
ResolverCallback(DNSServiceRef sdRef,
 
3244
                   DNSServiceFlags flags,
 
3245
                   uint32_t interfaceIndex,
 
3246
                   DNSServiceErrorType errorCode,
 
3247
                   const char *fullname,
 
3248
                   const char *hosttarget,
 
3249
                   uint16_t port,
 
3250
                   uint16_t txtLen,
 
3251
                   const char *txtRecord,
 
3252
                   void *context)
 
3253
{
 
3254
  // NSNetService
 
3255
  [(id) context resolverCallback: sdRef
 
3256
                           flags: flags
 
3257
                       interface: interfaceIndex
 
3258
                           error: errorCode
 
3259
                        fullname: fullname
 
3260
                          target: hosttarget
 
3261
                            port: port
 
3262
                          length: txtLen
 
3263
                          record: txtRecord];
 
3264
}
 
3265
 
 
3266
/**
 
3267
 * <em>Description forthcoming</em>
 
3268
 *
 
3269
 *
 
3270
 */
 
3271
 
 
3272
static void
 
3273
RegistrationCallback(DNSServiceRef sdRef,
 
3274
                       DNSServiceFlags flags,
 
3275
                       DNSServiceErrorType errorCode,
 
3276
                       const char *name,
 
3277
                       const char *regtype,
 
3278
                       const char *domain,
 
3279
                       void *context)
 
3280
{
 
3281
  // NSNetService
 
3282
  [(id) context registerCallback: sdRef
 
3283
                           flags: flags
 
3284
                           error: errorCode
 
3285
                            name: name
 
3286
                            type: regtype
 
3287
                          domain: domain];
 
3288
}
 
3289
 
 
3290
/**
 
3291
 * <em>Description forthcoming</em>
 
3292
 *
 
3293
 *
 
3294
 */
 
3295
 
 
3296
static void
 
3297
QueryCallback(DNSServiceRef sdRef,
 
3298
                DNSServiceFlags flags,
 
3299
                uint32_t interfaceIndex,
 
3300
                DNSServiceErrorType errorCode,
 
3301
                const char *fullname,
 
3302
                uint16_t rrtype,
 
3303
                uint16_t rrclass,
 
3304
                uint16_t rdlen,
 
3305
                const void *rdata,
 
3306
                uint32_t ttl,
 
3307
                void *context)
 
3308
{
 
3309
  // NSNetService, NSNetServiceMonitor
 
3310
  [(id) context queryCallback: sdRef
 
3311
                        flags: flags
 
3312
                    interface: interfaceIndex
 
3313
                        error: errorCode
 
3314
                     fullname: fullname
 
3315
                         type: rrtype
 
3316
                        class: rrclass
 
3317
                       length: rdlen
 
3318
                         data: rdata
 
3319
                          ttl: ttl];
 
3320
}
 
3321