]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/Java/DNSSD.java
mDNSResponder-87.tar.gz
[apple/mdnsresponder.git] / mDNSShared / Java / DNSSD.java
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: DNSSD.java,v $
26 Revision 1.4 2004/12/11 03:00:59 rpantos
27 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
28
29 Revision 1.3 2004/11/12 03:23:08 rpantos
30 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
31
32 Revision 1.2 2004/05/20 17:43:18 cheshire
33 Fix invalid UTF-8 characters in file
34
35 Revision 1.1 2004/04/30 16:32:34 rpantos
36 First checked in.
37
38
39 This file declares and implements DNSSD, the central Java factory class
40 for doing DNS Service Discovery. It includes the mostly-abstract public
41 interface, as well as the Apple* implementation subclasses.
42
43 To do:
44 - implement network interface mappings
45 - RegisterRecord
46 */
47
48
49 package com.apple.dnssd;
50
51
52 /**
53 DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
54
55 It is a factory class that is used to invoke registration and discovery-related
56 operations. Most operations are non-blocking; clients are called back through an interface
57 with the result of an operation. Callbacks are made from a separate worker thread.<P>
58
59 For example, in this program<P>
60 <PRE><CODE>
61 class MyClient implements BrowseListener {
62 void lookForWebServers() {
63 myBrowser = DNSSD.browse("_http_.tcp", this);
64 }
65
66 public void serviceFound(DNSSDService browser, int flags, int ifIndex,
67 String serviceName, String regType, String domain) {}
68 ...
69 }</CODE></PRE>
70 <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
71 default browse domain(s).
72 */
73
74 abstract public class DNSSD
75 {
76 /** Flag indicates to a {@link BrowseListener} that another result is
77 queued. Applications should not update their UI to display browse
78 results if the MORE_COMING flag is set; they will be called at least once
79 more with the flag clear.
80 */
81 public static final int MORE_COMING = ( 1 << 0 );
82
83 /** If flag is set in a {@link DomainListener} callback, indicates that the result is the default domain. */
84 public static final int DEFAULT = ( 1 << 2 );
85
86 /** If flag is set, a name conflict will trigger an exception when registering non-shared records.<P>
87 A name must be explicitly specified when registering a service if this bit is set
88 (i.e. the default name may not not be used).
89 */
90 public static final int NO_AUTO_RENAME = ( 1 << 3 );
91
92 /** If flag is set, allow multiple records with this name on the network (e.g. PTR records)
93 when registering individual records on a {@link DNSSDRegistration}.
94 */
95 public static final int SHARED = ( 1 << 4 );
96
97 /** If flag is set, records with this name must be unique on the network (e.g. SRV records). */
98 public static final int UNIQUE = ( 1 << 5 );
99
100 /** Set flag when calling enumerateDomains() to restrict results to domains recommended for browsing. */
101 public static final int BROWSE_DOMAINS = ( 1 << 6 );
102 /** Set flag when calling enumerateDomains() to restrict results to domains recommended for registration. */
103 public static final int REGISTRATION_DOMAINS = ( 1 << 7 );
104
105 /** Maximum length, in bytes, of a domain name represented as an escaped C-String. */
106 public static final int MAX_DOMAIN_NAME = 1005;
107
108 /** Pass for ifIndex to specify all available interfaces. */
109 public static final int ALL_INTERFACES = 0;
110
111 /** Pass for ifIndex to specify the localhost interface. */
112 public static final int LOCALHOST_ONLY = -1;
113
114 /** Browse for instances of a service.<P>
115
116 Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
117
118 @param flags
119 Currently ignored, reserved for future use.
120 <P>
121 @param ifIndex
122 If non-zero, specifies the interface on which to browse for services
123 (the index for a given interface is determined via the if_nametoindex()
124 family of calls.) Most applications will pass 0 to browse on all available
125 interfaces. Pass -1 to only browse for services provided on the local host.
126 <P>
127 @param regType
128 The registration type being browsed for followed by the protocol, separated by a
129 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
130 <P>
131 @param domain
132 If non-null, specifies the domain on which to browse for services.
133 Most applications will not specify a domain, instead browsing on the
134 default domain(s).
135 <P>
136 @param listener
137 This object will get called when instances of the service are discovered (or disappear).
138 <P>
139 @return A {@link DNSSDService} that represents the active browse operation.
140
141 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
142 @see RuntimePermission
143 */
144 public static DNSSDService browse( int flags, int ifIndex, String regType, String domain, BrowseListener listener)
145 throws DNSSDException
146 { return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); }
147
148 /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
149
150 @param regType
151 The registration type being browsed for followed by the protocol, separated by a
152 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
153 <P>
154 @param listener
155 This object will get called when instances of the service are discovered (or disappear).
156 <P>
157 @return A {@link DNSSDService} that represents the active browse operation.
158
159 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
160 @see RuntimePermission
161 */
162 public static DNSSDService browse( String regType, BrowseListener listener)
163 throws DNSSDException
164 { return browse( 0, 0, regType, "", listener); }
165
166 /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
167
168 Note: Applications should NOT use resolve() solely for txt record monitoring - use
169 queryRecord() instead, as it is more efficient for this task.<P>
170
171 Note: When the desired results have been returned, the client MUST terminate the resolve by
172 calling {@link DNSSDService#stop}.<P>
173
174 Note: resolve() behaves correctly for typical services that have a single SRV record and
175 a single TXT record (the TXT record may be empty.) To resolve non-standard services with
176 multiple SRV or TXT records, use queryRecord().<P>
177
178 @param flags
179 Currently ignored, reserved for future use.
180 <P>
181 @param ifIndex
182 The interface on which to resolve the service. The client should
183 pass the interface on which the serviceName was discovered (i.e.
184 the ifIndex passed to the serviceFound() callback)
185 or 0 to resolve the named service on all available interfaces.
186 <P>
187 @param serviceName
188 The servicename to be resolved.
189 <P>
190 @param regType
191 The registration type being resolved followed by the protocol, separated by a
192 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
193 <P>
194 @param domain
195 The domain on which the service is registered, i.e. the domain passed
196 to the serviceFound() callback.
197 <P>
198 @param listener
199 This object will get called when the service is resolved.
200 <P>
201 @return A {@link DNSSDService} that represents the active resolve operation.
202
203 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
204 @see RuntimePermission
205 */
206 public static DNSSDService resolve( int flags, int ifIndex, String serviceName, String regType,
207 String domain, ResolveListener listener)
208 throws DNSSDException
209 { return getInstance()._resolve( flags, ifIndex, serviceName, regType, domain, listener); }
210
211 /** Register a service, to be discovered via browse() and resolve() calls.<P>
212 @param flags
213 Possible values are: NO_AUTO_RENAME.
214 <P>
215 @param ifIndex
216 If non-zero, specifies the interface on which to register the service
217 (the index for a given interface is determined via the if_nametoindex()
218 family of calls.) Most applications will pass 0 to register on all
219 available interfaces. Pass -1 to register a service only on the local
220 machine (service will not be visible to remote hosts).
221 <P>
222 @param serviceName
223 If non-null, specifies the service name to be registered.
224 Applications need not specify a name, in which case the
225 computer name is used (this name is communicated to the client via
226 the serviceRegistered() callback).
227 <P>
228 @param regType
229 The registration type being registered followed by the protocol, separated by a
230 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
231 <P>
232 @param domain
233 If non-null, specifies the domain on which to advertise the service.
234 Most applications will not specify a domain, instead automatically
235 registering in the default domain(s).
236 <P>
237 @param host
238 If non-null, specifies the SRV target host name. Most applications
239 will not specify a host, instead automatically using the machine's
240 default host name(s). Note that specifying a non-null host does NOT
241 create an address record for that host - the application is responsible
242 for ensuring that the appropriate address record exists, or creating it
243 via {@link DNSSDRegistration#addRecord}.
244 <P>
245 @param port
246 The port on which the service accepts connections. Pass 0 for a
247 "placeholder" service (i.e. a service that will not be discovered by
248 browsing, but will cause a name conflict if another client tries to
249 register that same name.) Most clients will not use placeholder services.
250 <P>
251 @param txtRecord
252 The txt record rdata. May be null. Note that a non-null txtRecord
253 MUST be a properly formatted DNS TXT record, i.e. &lt;length byte&gt; &lt;data&gt;
254 &lt;length byte&gt; &lt;data&gt; ...
255 <P>
256 @param listener
257 This object will get called when the service is registered.
258 <P>
259 @return A {@link DNSSDRegistration} that controls the active registration.
260
261 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
262 @see RuntimePermission
263 */
264 public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType,
265 String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
266 throws DNSSDException
267 { return getInstance()._register( flags, ifIndex, serviceName, regType, domain, host, port, txtRecord, listener); }
268
269 /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
270 @param serviceName
271 If non-null, specifies the service name to be registered.
272 Applications need not specify a name, in which case the
273 computer name is used (this name is communicated to the client via
274 the serviceRegistered() callback).
275 <P>
276 @param regType
277 The registration type being registered followed by the protocol, separated by a
278 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
279 <P>
280 @param port
281 The port on which the service accepts connections. Pass 0 for a
282 "placeholder" service (i.e. a service that will not be discovered by
283 browsing, but will cause a name conflict if another client tries to
284 register that same name.) Most clients will not use placeholder services.
285 <P>
286 @param listener
287 This object will get called when the service is registered.
288 <P>
289 @return A {@link DNSSDRegistration} that controls the active registration.
290
291 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
292 @see RuntimePermission
293 */
294 public static DNSSDRegistration register( String serviceName, String regType, int port, RegisterListener listener)
295 throws DNSSDException
296 { return register( 0, 0, serviceName, regType, null, null, port, null, listener); }
297
298 /** Query for an arbitrary DNS record.<P>
299 @param flags
300 Possible values are: MORE_COMING.
301 <P>
302 @param ifIndex
303 If non-zero, specifies the interface on which to issue the query
304 (the index for a given interface is determined via the if_nametoindex()
305 family of calls.) Passing 0 causes the name to be queried for on all
306 interfaces. Passing -1 causes the name to be queried for only on the
307 local host.
308 <P>
309 @param serviceName
310 The full domain name of the resource record to be queried for.
311 <P>
312 @param rrtype
313 The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
314 as defined in nameser.h.
315 <P>
316 @param rrclass
317 The class of the resource record, as defined in nameser.h
318 (usually 1 for the Internet class).
319 <P>
320 @param listener
321 This object will get called when the query completes.
322 <P>
323 @return A {@link DNSSDService} that controls the active query.
324
325 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
326 @see RuntimePermission
327 */
328 public static DNSSDService queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
329 int rrclass, QueryListener listener)
330 throws DNSSDException
331 { return getInstance()._queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, listener); }
332
333 /** Asynchronously enumerate domains available for browsing and registration.<P>
334
335 Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
336
337 The enumeration MUST be cancelled by calling {@link DNSSDService#stop} when no more domains
338 are to be found.<P>
339 @param flags
340 Possible values are: BROWSE_DOMAINS, REGISTRATION_DOMAINS.
341 <P>
342 @param ifIndex
343 If non-zero, specifies the interface on which to look for domains.
344 (the index for a given interface is determined via the if_nametoindex()
345 family of calls.) Most applications will pass 0 to enumerate domains on
346 all interfaces.
347 <P>
348 @param listener
349 This object will get called when domains are found.
350 <P>
351 @return A {@link DNSSDService} that controls the active enumeration.
352
353 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
354 @see RuntimePermission
355 */
356 public static DNSSDService enumerateDomains( int flags, int ifIndex, DomainListener listener)
357 throws DNSSDException
358 { return getInstance()._enumerateDomains( flags, ifIndex, listener); }
359
360 /** Concatenate a three-part domain name (as provided to the listeners) into a
361 properly-escaped full domain name. Note that strings passed to listeners are
362 ALREADY ESCAPED where necessary.<P>
363 @param serviceName
364 The service name - any dots or slashes must NOT be escaped.
365 May be null (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
366 <P>
367 @param regType
368 The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
369 <P>
370 @param domain
371 The domain name, e.g. "apple.com". Any literal dots or backslashes must be escaped.
372 <P>
373 @return The full domain name.
374
375 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
376 @see RuntimePermission
377 */
378 public static String constructFullName( String serviceName, String regType, String domain)
379 throws DNSSDException
380 { return getInstance()._constructFullName( serviceName, regType, domain); }
381
382 /** Instruct the daemon to verify the validity of a resource record that appears to
383 be out of date. (e.g. because tcp connection to a service's target failed.) <P>
384
385 Causes the record to be flushed from the daemon's cache (as well as all other
386 daemons' caches on the network) if the record is determined to be invalid.<P>
387 @param flags
388 Currently unused, reserved for future use.
389 <P>
390 @param ifIndex
391 If non-zero, specifies the interface on which to reconfirm the record
392 (the index for a given interface is determined via the if_nametoindex()
393 family of calls.) Passing 0 causes the name to be reconfirmed on all
394 interfaces. Passing -1 causes the name to be reconfirmed only on the
395 local host.
396 <P>
397 @param fullName
398 The resource record's full domain name.
399 <P>
400 @param rrtype
401 The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
402 <P>
403 @param rrclass
404 The class of the resource record, as defined in nameser.h (usually 1).
405 <P>
406 @param rdata
407 The raw rdata of the resource record.
408
409 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
410 @see RuntimePermission
411 */
412 public static void reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
413 int rrclass, byte[] rdata)
414 { getInstance()._reconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); }
415
416 /** Return the canonical name of a particular interface index.<P>
417 @param ifIndex
418 A valid interface index. Must not be ALL_INTERFACES.
419 <P>
420 @return The name of the interface, which should match java.net.NetworkInterface.getName().
421
422 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
423 @see RuntimePermission
424 */
425 public static String getNameForIfIndex( int ifIndex)
426 { return getInstance()._getNameForIfIndex( ifIndex); }
427
428 /** Return the index of a named interface.<P>
429 @param ifName
430 A valid interface name. An example is java.net.NetworkInterface.getName().
431 <P>
432 @return The interface index.
433
434 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
435 @see RuntimePermission
436 */
437 public static int getIfIndexForName( String ifName)
438 { return getInstance()._getIfIndexForName( ifName); }
439
440 protected DNSSD() {} // prevent direct instantiation
441
442 /** Return the single instance of DNSSD. */
443 static protected final DNSSD getInstance()
444 {
445 SecurityManager sm = System.getSecurityManager();
446 if ( sm != null)
447 sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));
448 return fInstance;
449 }
450
451 abstract protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener listener)
452 throws DNSSDException;
453
454 abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
455 String domain, ResolveListener listener)
456 throws DNSSDException;
457
458 abstract protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
459 String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
460 throws DNSSDException;
461
462 abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
463 int rrclass, QueryListener listener)
464 throws DNSSDException;
465
466 abstract protected DNSSDService _enumerateDomains( int flags, int ifIndex, DomainListener listener)
467 throws DNSSDException;
468
469 abstract protected String _constructFullName( String serviceName, String regType, String domain)
470 throws DNSSDException;
471
472 abstract protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
473 int rrclass, byte[] rdata);
474
475 abstract protected String _getNameForIfIndex( int ifIndex);
476
477 abstract protected int _getIfIndexForName( String ifName);
478
479 protected static DNSSD fInstance;
480
481 static
482 {
483 try
484 {
485 String name = System.getProperty( "com.apple.dnssd.DNSSD" );
486 if( name == null )
487 name = "com.apple.dnssd.AppleDNSSD"; // Fall back to Apple-provided class.
488 fInstance = (DNSSD) Class.forName( name ).newInstance();
489 }
490 catch( Exception e )
491 {
492 throw new InternalError( "cannot instantiate DNSSD" + e );
493 }
494 }
495 }
496
497
498 // Concrete implementation of DNSSDException
499 class AppleDNSSDException extends DNSSDException
500 {
501 public AppleDNSSDException( int errorCode) { fErrorCode = errorCode; }
502
503 public int getErrorCode() { return fErrorCode; }
504
505 public String getMessage()
506 {
507 final String kMessages[] = { // should probably be put into a resource or something
508 "UNKNOWN",
509 "NO_SUCH_NAME",
510 "NO_MEMORY",
511 "BAD_PARAM",
512 "BAD_REFERENCE",
513 "BAD_STATE",
514 "BAD_FLAGS",
515 "UNSUPPORTED",
516 "NOT_INITIALIZED",
517 "", // there is NO number 6
518 "ALREADY_REGISTERED",
519 "NAME_CONFLICT",
520 "INVALID",
521 "", // another MIA
522 "INCOMPATIBLE",
523 "BAD_INTERFACE_INDEX"
524 };
525
526 if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
527 {
528 return "DNS-SD Error " + String.valueOf( fErrorCode) + ": " + kMessages[ UNKNOWN - fErrorCode];
529 }
530 else
531 return super.getMessage() + "(" + String.valueOf( fErrorCode) + ")";
532 }
533
534 protected int fErrorCode;
535 }
536
537 // The concrete, default implementation.
538 class AppleDNSSD extends DNSSD
539 {
540 static
541 {
542 System.loadLibrary( "jdns_sd");
543
544 int libInitResult = InitLibrary( 1);
545
546 if ( libInitResult != DNSSDException.NO_ERROR)
547 throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
548 }
549
550 static public boolean hasAutoCallbacks; // Set by InitLibrary() to value of AUTO_CALLBACKS
551
552 protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
553 throws DNSSDException
554 {
555 return new AppleBrowser( flags, ifIndex, regType, domain, client);
556 }
557
558 protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
559 String domain, ResolveListener client)
560 throws DNSSDException
561 {
562 return new AppleResolver( flags, ifIndex, serviceName, regType, domain, client);
563 }
564
565 protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
566 String domain, String host, int port, TXTRecord txtRecord, RegisterListener client)
567 throws DNSSDException
568 {
569 return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port,
570 ( txtRecord != null) ? txtRecord.getRawBytes() : null, client);
571 }
572
573 protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
574 int rrclass, QueryListener client)
575 throws DNSSDException
576 {
577 return new AppleQuery( flags, ifIndex, serviceName, rrtype, rrclass, client);
578 }
579
580 protected DNSSDService _enumerateDomains( int flags, int ifIndex, DomainListener listener)
581 throws DNSSDException
582 {
583 return new AppleDomainEnum( flags, ifIndex, listener);
584 }
585
586 protected String _constructFullName( String serviceName, String regType, String domain)
587 throws DNSSDException
588 {
589 String[] responseHolder = new String[1]; // lame maneuver to get around Java's lack of reference parameters
590
591 int rc = ConstructName( serviceName, regType, domain, responseHolder);
592 if ( rc != 0)
593 throw new AppleDNSSDException( rc);
594
595 return responseHolder[0];
596 }
597
598 protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
599 int rrclass, byte[] rdata)
600 {
601 ReconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata);
602 }
603
604 protected String _getNameForIfIndex( int ifIndex)
605 {
606 return GetNameForIfIndex( ifIndex);
607 }
608
609 protected int _getIfIndexForName( String ifName)
610 {
611 return GetIfIndexForName( ifName);
612 }
613
614
615 protected native int ConstructName( String serviceName, String regType, String domain, String[] pOut);
616
617 protected native void ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
618 int rrclass, byte[] rdata);
619
620 protected native String GetNameForIfIndex( int ifIndex);
621
622 protected native int GetIfIndexForName( String ifName);
623
624 protected static native int InitLibrary( int callerVersion);
625 }
626
627 class AppleService implements DNSSDService, Runnable
628 {
629 public AppleService() { fNativeContext = 0; }
630
631 public void stop() { this.HaltOperation(); }
632
633 public void finalize() throws Throwable
634 {
635 this.stop();
636 super.finalize();
637 }
638
639 /* The run() method is used internally to schedule an update from another thread */
640 public void run()
641 {
642 this.ProcessResults();
643 }
644
645 /* Block for timeout ms (or forever if -1). Returns 1 if data present, 0 if timed out, -1 if not browsing. */
646 protected native int BlockForData( int msTimeout);
647
648 /* Call ProcessResults when data appears on socket descriptor. */
649 protected native void ProcessResults();
650
651 protected native void HaltOperation();
652
653 protected void ThrowOnErr( int rc) throws DNSSDException
654 {
655 if ( rc != 0)
656 throw new AppleDNSSDException( rc);
657 }
658
659 protected int /* warning */ fNativeContext; // Private storage for native side
660 }
661
662
663 // A ServiceThread calls AppleService.BlockForData() and schedules its client
664 // when data appears.
665 class ServiceThread extends Thread
666 {
667 public ServiceThread( AppleService owner) { fOwner = owner; }
668
669 public void run()
670 {
671 int result;
672
673 while ( true )
674 {
675 result = fOwner.BlockForData( -1);
676 if ( result == 1)
677 {
678 fOwner.run();
679 }
680 else
681 break; // terminate thread
682 }
683 }
684
685 protected AppleService fOwner;
686 }
687
688
689 class AppleBrowser extends AppleService
690 {
691 public AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
692 throws DNSSDException
693 {
694 fClient = client;
695 this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
696 if ( !AppleDNSSD.hasAutoCallbacks)
697 new ServiceThread( this).start();
698 }
699
700 // Sets fNativeContext. Returns non-zero on error.
701 protected native int CreateBrowser( int flags, int ifIndex, String regType, String domain);
702
703 protected BrowseListener fClient;
704 }
705
706 class AppleResolver extends AppleService
707 {
708 public AppleResolver( int flags, int ifIndex, String serviceName, String regType,
709 String domain, ResolveListener client)
710 throws DNSSDException
711 {
712 fClient = client;
713 this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
714 if ( !AppleDNSSD.hasAutoCallbacks)
715 new ServiceThread( this).start();
716 }
717
718 // Sets fNativeContext. Returns non-zero on error.
719 protected native int CreateResolver( int flags, int ifIndex, String serviceName, String regType,
720 String domain);
721
722 protected ResolveListener fClient;
723 }
724
725 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
726 class AppleDNSRecord implements DNSRecord
727 {
728 public AppleDNSRecord( AppleService owner)
729 {
730 fOwner = owner;
731 fRecord = 0; // record always starts out empty
732 }
733
734 public void update( int flags, byte[] rData, int ttl)
735 throws DNSSDException
736 {
737 this.ThrowOnErr( this.Update( flags, rData, ttl));
738 }
739
740 public void remove()
741 throws DNSSDException
742 {
743 this.ThrowOnErr( this.Remove());
744 }
745
746 protected int fRecord; // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
747 protected AppleService fOwner;
748
749 protected void ThrowOnErr( int rc) throws DNSSDException
750 {
751 if ( rc != 0)
752 throw new AppleDNSSDException( rc);
753 }
754
755 protected native int Update( int flags, byte[] rData, int ttl);
756
757 protected native int Remove();
758 }
759
760 class AppleRegistration extends AppleService implements DNSSDRegistration
761 {
762 public AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain,
763 String host, int port, byte[] txtRecord, RegisterListener client)
764 throws DNSSDException
765 {
766 fClient = client;
767 this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
768 if ( !AppleDNSSD.hasAutoCallbacks)
769 new ServiceThread( this).start();
770 }
771
772 public DNSRecord addRecord( int flags, int rrType, byte[] rData, int ttl)
773 throws DNSSDException
774 {
775 AppleDNSRecord newRecord = new AppleDNSRecord( this);
776
777 this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
778
779 return newRecord;
780 }
781
782 public DNSRecord getTXTRecord()
783 throws DNSSDException
784 {
785 return new AppleDNSRecord( this); // A record with ref 0 is understood to be primary TXT record
786 }
787
788 // Sets fNativeContext. Returns non-zero on error.
789 protected native int BeginRegister( int ifIndex, int flags, String serviceName, String regType,
790 String domain, String host, int port, byte[] txtRecord);
791
792 // Sets fNativeContext. Returns non-zero on error.
793 protected native int AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj);
794
795 protected RegisterListener fClient;
796 }
797
798 class AppleQuery extends AppleService
799 {
800 public AppleQuery( int flags, int ifIndex, String serviceName, int rrtype,
801 int rrclass, QueryListener client)
802 throws DNSSDException
803 {
804 fClient = client;
805 this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
806 if ( !AppleDNSSD.hasAutoCallbacks)
807 new ServiceThread( this).start();
808 }
809
810 // Sets fNativeContext. Returns non-zero on error.
811 protected native int CreateQuery( int flags, int ifIndex, String serviceName, int rrtype, int rrclass);
812
813 protected QueryListener fClient;
814 }
815
816 class AppleDomainEnum extends AppleService
817 {
818 public AppleDomainEnum( int flags, int ifIndex, DomainListener listener)
819 throws DNSSDException
820 {
821 fClient = listener;
822 this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
823 if ( !AppleDNSSD.hasAutoCallbacks)
824 new ServiceThread( this).start();
825 }
826
827 // Sets fNativeContext. Returns non-zero on error.
828 protected native int BeginEnum( int flags, int ifIndex);
829
830 protected DomainListener fClient;
831 }
832
833