1 /* -*- Mode: Java; tab-width: 4 -*-
3 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 This file declares and implements DNSSD, the central Java factory class
18 for doing DNS Service Discovery. It includes the mostly-abstract public
19 interface, as well as the Apple* implementation subclasses.
23 package com
.apple
.dnssd
;
27 DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
29 It is a factory class that is used to invoke registration and discovery-related
30 operations. Most operations are non-blocking; clients are called back through an interface
31 with the result of an operation. Callbacks are made from a separate worker thread.<P>
33 For example, in this program<P>
35 class MyClient implements BrowseListener {
36 void lookForWebServers() {
37 myBrowser = DNSSD.browse("_http._tcp", this);
40 public void serviceFound(DNSSDService browser, int flags, int ifIndex,
41 String serviceName, String regType, String domain) {}
44 <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
45 default browse domain(s).
48 abstract public class DNSSD
50 /** Flag indicates to a {@link BrowseListener} that another result is
51 queued. Applications should not update their UI to display browse
52 results if the MORE_COMING flag is set; they will be called at least once
53 more with the flag clear.
55 public static final int MORE_COMING
= ( 1 << 0 );
57 /** If flag is set in a {@link DomainListener} callback, indicates that the result is the default domain. */
58 public static final int DEFAULT
= ( 1 << 2 );
60 /** If flag is set, a name conflict will trigger an exception when registering non-shared records.<P>
61 A name must be explicitly specified when registering a service if this bit is set
62 (i.e. the default name may not not be used).
64 public static final int NO_AUTO_RENAME
= ( 1 << 3 );
66 /** If flag is set, allow multiple records with this name on the network (e.g. PTR records)
67 when registering individual records on a {@link DNSSDRegistration}.
69 public static final int SHARED
= ( 1 << 4 );
71 /** If flag is set, records with this name must be unique on the network (e.g. SRV records). */
72 public static final int UNIQUE
= ( 1 << 5 );
74 /** Set flag when calling enumerateDomains() to restrict results to domains recommended for browsing. */
75 public static final int BROWSE_DOMAINS
= ( 1 << 6 );
76 /** Set flag when calling enumerateDomains() to restrict results to domains recommended for registration. */
77 public static final int REGISTRATION_DOMAINS
= ( 1 << 7 );
79 /** Maximum length, in bytes, of a domain name represented as an escaped C-String. */
80 public static final int MAX_DOMAIN_NAME
= 1009;
82 /** Pass for ifIndex to specify all available interfaces. */
83 public static final int ALL_INTERFACES
= 0;
85 /** Pass for ifIndex to specify the localhost interface. */
86 public static final int LOCALHOST_ONLY
= -1;
88 /** Browse for instances of a service.<P>
90 Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
93 Currently ignored, reserved for future use.
96 If non-zero, specifies the interface on which to browse for services
97 (the index for a given interface is determined via the if_nametoindex()
98 family of calls.) Most applications will pass 0 to browse on all available
99 interfaces. Pass -1 to only browse for services provided on the local host.
102 The registration type being browsed for followed by the protocol, separated by a
103 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
106 If non-null, specifies the domain on which to browse for services.
107 Most applications will not specify a domain, instead browsing on the
111 This object will get called when instances of the service are discovered (or disappear).
113 @return A {@link DNSSDService} that represents the active browse operation.
115 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
116 @see RuntimePermission
118 public static DNSSDService
browse( int flags
, int ifIndex
, String regType
, String domain
, BrowseListener listener
)
119 throws DNSSDException
120 { return getInstance()._makeBrowser( flags
, ifIndex
, regType
, domain
, listener
); }
122 /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
125 The registration type being browsed for followed by the protocol, separated by a
126 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
129 This object will get called when instances of the service are discovered (or disappear).
131 @return A {@link DNSSDService} that represents the active browse operation.
133 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
134 @see RuntimePermission
136 public static DNSSDService
browse( String regType
, BrowseListener listener
)
137 throws DNSSDException
138 { return browse( 0, 0, regType
, "", listener
); }
140 /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
142 Note: Applications should NOT use resolve() solely for txt record monitoring - use
143 queryRecord() instead, as it is more efficient for this task.<P>
145 Note: When the desired results have been returned, the client MUST terminate the resolve by
146 calling {@link DNSSDService#stop}.<P>
148 Note: resolve() behaves correctly for typical services that have a single SRV record and
149 a single TXT record (the TXT record may be empty.) To resolve non-standard services with
150 multiple SRV or TXT records, use queryRecord().<P>
153 Currently ignored, reserved for future use.
156 The interface on which to resolve the service. The client should
157 pass the interface on which the serviceName was discovered (i.e.
158 the ifIndex passed to the serviceFound() callback)
159 or 0 to resolve the named service on all available interfaces.
162 The servicename to be resolved.
165 The registration type being resolved followed by the protocol, separated by a
166 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
169 The domain on which the service is registered, i.e. the domain passed
170 to the serviceFound() callback.
173 This object will get called when the service is resolved.
175 @return A {@link DNSSDService} that represents the active resolve operation.
177 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
178 @see RuntimePermission
180 public static DNSSDService
resolve( int flags
, int ifIndex
, String serviceName
, String regType
,
181 String domain
, ResolveListener listener
)
182 throws DNSSDException
183 { return getInstance()._resolve( flags
, ifIndex
, serviceName
, regType
, domain
, listener
); }
185 /** Register a service, to be discovered via browse() and resolve() calls.<P>
187 Possible values are: NO_AUTO_RENAME.
190 If non-zero, specifies the interface on which to register the service
191 (the index for a given interface is determined via the if_nametoindex()
192 family of calls.) Most applications will pass 0 to register on all
193 available interfaces. Pass -1 to register a service only on the local
194 machine (service will not be visible to remote hosts).
197 If non-null, specifies the service name to be registered.
198 Applications need not specify a name, in which case the
199 computer name is used (this name is communicated to the client via
200 the serviceRegistered() callback).
203 The registration type being registered followed by the protocol, separated by a
204 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
207 If non-null, specifies the domain on which to advertise the service.
208 Most applications will not specify a domain, instead automatically
209 registering in the default domain(s).
212 If non-null, specifies the SRV target host name. Most applications
213 will not specify a host, instead automatically using the machine's
214 default host name(s). Note that specifying a non-null host does NOT
215 create an address record for that host - the application is responsible
216 for ensuring that the appropriate address record exists, or creating it
217 via {@link DNSSDRegistration#addRecord}.
220 The port on which the service accepts connections. Pass 0 for a
221 "placeholder" service (i.e. a service that will not be discovered by
222 browsing, but will cause a name conflict if another client tries to
223 register that same name.) Most clients will not use placeholder services.
226 The txt record rdata. May be null. Note that a non-null txtRecord
227 MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
228 <length byte> <data> ...
231 This object will get called when the service is registered.
233 @return A {@link DNSSDRegistration} that controls the active registration.
235 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
236 @see RuntimePermission
238 public static DNSSDRegistration
register( int flags
, int ifIndex
, String serviceName
, String regType
,
239 String domain
, String host
, int port
, TXTRecord txtRecord
, RegisterListener listener
)
240 throws DNSSDException
241 { return getInstance()._register( flags
, ifIndex
, serviceName
, regType
, domain
, host
, port
, txtRecord
, listener
); }
243 /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
245 If non-null, specifies the service name to be registered.
246 Applications need not specify a name, in which case the
247 computer name is used (this name is communicated to the client via
248 the serviceRegistered() callback).
251 The registration type being registered followed by the protocol, separated by a
252 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
255 The port on which the service accepts connections. Pass 0 for a
256 "placeholder" service (i.e. a service that will not be discovered by
257 browsing, but will cause a name conflict if another client tries to
258 register that same name.) Most clients will not use placeholder services.
261 This object will get called when the service is registered.
263 @return A {@link DNSSDRegistration} that controls the active registration.
265 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
266 @see RuntimePermission
268 public static DNSSDRegistration
register( String serviceName
, String regType
, int port
, RegisterListener listener
)
269 throws DNSSDException
270 { return register( 0, 0, serviceName
, regType
, null, null, port
, null, listener
); }
272 /** Create a {@link DNSSDRecordRegistrar} allowing efficient registration of
273 multiple individual records.<P>
275 @return A {@link DNSSDRecordRegistrar} that can be used to register records.
277 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
278 @see RuntimePermission
280 public static DNSSDRecordRegistrar
createRecordRegistrar( RegisterRecordListener listener
)
281 throws DNSSDException
282 { return getInstance()._createRecordRegistrar( listener
); }
284 /** Query for an arbitrary DNS record.<P>
286 Possible values are: MORE_COMING.
289 If non-zero, specifies the interface on which to issue the query
290 (the index for a given interface is determined via the if_nametoindex()
291 family of calls.) Passing 0 causes the name to be queried for on all
292 interfaces. Passing -1 causes the name to be queried for only on the
296 The full domain name of the resource record to be queried for.
299 The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
300 as defined in nameser.h.
303 The class of the resource record, as defined in nameser.h
304 (usually 1 for the Internet class).
307 This object will get called when the query completes.
309 @return A {@link DNSSDService} that controls the active query.
311 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
312 @see RuntimePermission
314 public static DNSSDService
queryRecord( int flags
, int ifIndex
, String serviceName
, int rrtype
,
315 int rrclass
, QueryListener listener
)
316 throws DNSSDException
317 { return getInstance()._queryRecord( flags
, ifIndex
, serviceName
, rrtype
, rrclass
, listener
); }
319 /** Asynchronously enumerate domains available for browsing and registration.<P>
321 Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
323 The enumeration MUST be cancelled by calling {@link DNSSDService#stop} when no more domains
326 Possible values are: BROWSE_DOMAINS, REGISTRATION_DOMAINS.
329 If non-zero, specifies the interface on which to look for domains.
330 (the index for a given interface is determined via the if_nametoindex()
331 family of calls.) Most applications will pass 0 to enumerate domains on
335 This object will get called when domains are found.
337 @return A {@link DNSSDService} that controls the active enumeration.
339 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
340 @see RuntimePermission
342 public static DNSSDService
enumerateDomains( int flags
, int ifIndex
, DomainListener listener
)
343 throws DNSSDException
344 { return getInstance()._enumerateDomains( flags
, ifIndex
, listener
); }
346 /** Concatenate a three-part domain name (as provided to the listeners) into a
347 properly-escaped full domain name. Note that strings passed to listeners are
348 ALREADY ESCAPED where necessary.<P>
350 The service name - any dots or slashes must NOT be escaped.
351 May be null (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
354 The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
357 The domain name, e.g. "apple.com". Any literal dots or backslashes must be escaped.
359 @return The full domain name.
361 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
362 @see RuntimePermission
364 public static String
constructFullName( String serviceName
, String regType
, String domain
)
365 throws DNSSDException
366 { return getInstance()._constructFullName( serviceName
, regType
, domain
); }
368 /** Instruct the daemon to verify the validity of a resource record that appears to
369 be out of date. (e.g. because tcp connection to a service's target failed.) <P>
371 Causes the record to be flushed from the daemon's cache (as well as all other
372 daemons' caches on the network) if the record is determined to be invalid.<P>
374 Currently unused, reserved for future use.
377 If non-zero, specifies the interface on which to reconfirm the record
378 (the index for a given interface is determined via the if_nametoindex()
379 family of calls.) Passing 0 causes the name to be reconfirmed on all
380 interfaces. Passing -1 causes the name to be reconfirmed only on the
384 The resource record's full domain name.
387 The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
390 The class of the resource record, as defined in nameser.h (usually 1).
393 The raw rdata of the resource record.
395 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
396 @see RuntimePermission
398 public static void reconfirmRecord( int flags
, int ifIndex
, String fullName
, int rrtype
,
399 int rrclass
, byte[] rdata
)
400 { getInstance()._reconfirmRecord( flags
, ifIndex
, fullName
, rrtype
, rrclass
, rdata
); }
402 /** Return the canonical name of a particular interface index.<P>
404 A valid interface index. Must not be ALL_INTERFACES.
406 @return The name of the interface, which should match java.net.NetworkInterface.getName().
408 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
409 @see RuntimePermission
411 public static String
getNameForIfIndex( int ifIndex
)
412 { return getInstance()._getNameForIfIndex( ifIndex
); }
414 /** Return the index of a named interface.<P>
416 A valid interface name. An example is java.net.NetworkInterface.getName().
418 @return The interface index.
420 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
421 @see RuntimePermission
423 public static int getIfIndexForName( String ifName
)
424 { return getInstance()._getIfIndexForName( ifName
); }
426 protected DNSSD() {} // prevent direct instantiation
428 /** Return the single instance of DNSSD. */
429 static protected final DNSSD
getInstance()
431 SecurityManager sm
= System
.getSecurityManager();
433 sm
.checkPermission( new RuntimePermission( "getDNSSDInstance"));
437 abstract protected DNSSDService
_makeBrowser( int flags
, int ifIndex
, String regType
, String domain
, BrowseListener listener
)
438 throws DNSSDException
;
440 abstract protected DNSSDService
_resolve( int flags
, int ifIndex
, String serviceName
, String regType
,
441 String domain
, ResolveListener listener
)
442 throws DNSSDException
;
444 abstract protected DNSSDRegistration
_register( int flags
, int ifIndex
, String serviceName
, String regType
,
445 String domain
, String host
, int port
, TXTRecord txtRecord
, RegisterListener listener
)
446 throws DNSSDException
;
448 abstract protected DNSSDRecordRegistrar
_createRecordRegistrar( RegisterRecordListener listener
)
449 throws DNSSDException
;
451 abstract protected DNSSDService
_queryRecord( int flags
, int ifIndex
, String serviceName
, int rrtype
,
452 int rrclass
, QueryListener listener
)
453 throws DNSSDException
;
455 abstract protected DNSSDService
_enumerateDomains( int flags
, int ifIndex
, DomainListener listener
)
456 throws DNSSDException
;
458 abstract protected String
_constructFullName( String serviceName
, String regType
, String domain
)
459 throws DNSSDException
;
461 abstract protected void _reconfirmRecord( int flags
, int ifIndex
, String fullName
, int rrtype
,
462 int rrclass
, byte[] rdata
);
464 abstract protected String
_getNameForIfIndex( int ifIndex
);
466 abstract protected int _getIfIndexForName( String ifName
);
468 protected static DNSSD fInstance
;
474 String name
= System
.getProperty( "com.apple.dnssd.DNSSD" );
476 name
= "com.apple.dnssd.AppleDNSSD"; // Fall back to Apple-provided class.
477 fInstance
= (DNSSD
) Class
.forName(name
).newInstance();
481 throw new InternalError( "cannot instantiate DNSSD" + e
);
487 // Concrete implementation of DNSSDException
488 class AppleDNSSDException
extends DNSSDException
490 public AppleDNSSDException( int errorCode
) { fErrorCode
= errorCode
; }
492 public int getErrorCode() { return fErrorCode
; }
494 public String
getMessage()
496 final String kMessages
[] = { // should probably be put into a resource or something
507 "ALREADY_REGISTERED",
512 "BAD_INTERFACE_INDEX",
524 "NATPORTMAPPINGUNSUPPORTED",
525 "NATPORTMAPPINGDISABLED"
528 if (fErrorCode
<= UNKNOWN
&& fErrorCode
> ( UNKNOWN
- kMessages
.length
))
530 return "DNS-SD Error " + String
.valueOf( fErrorCode
) + ": " + kMessages
[ UNKNOWN
- fErrorCode
];
533 return super.getMessage() + "(" + String
.valueOf( fErrorCode
) + ")";
536 protected int fErrorCode
;
539 // The concrete, default implementation.
540 class AppleDNSSD
extends DNSSD
544 System
.loadLibrary( "jdns_sd");
546 int libInitResult
= InitLibrary( 2); // Current version number (must be sync'd with jnilib version)
548 if (libInitResult
!= DNSSDException
.NO_ERROR
)
549 throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult
).getMessage());
552 static public boolean hasAutoCallbacks
; // Set by InitLibrary() to value of AUTO_CALLBACKS
554 protected DNSSDService
_makeBrowser( int flags
, int ifIndex
, String regType
, String domain
, BrowseListener client
)
555 throws DNSSDException
557 return new AppleBrowser( flags
, ifIndex
, regType
, domain
, client
);
560 protected DNSSDService
_resolve( int flags
, int ifIndex
, String serviceName
, String regType
,
561 String domain
, ResolveListener client
)
562 throws DNSSDException
564 return new AppleResolver( flags
, ifIndex
, serviceName
, regType
, domain
, client
);
567 protected DNSSDRegistration
_register( int flags
, int ifIndex
, String serviceName
, String regType
,
568 String domain
, String host
, int port
, TXTRecord txtRecord
, RegisterListener client
)
569 throws DNSSDException
571 return new AppleRegistration( flags
, ifIndex
, serviceName
, regType
, domain
, host
, port
,
572 ( txtRecord
!= null) ? txtRecord
.getRawBytes() : null, client
);
575 protected DNSSDRecordRegistrar
_createRecordRegistrar( RegisterRecordListener listener
)
576 throws DNSSDException
578 return new AppleRecordRegistrar( listener
);
581 protected DNSSDService
_queryRecord( int flags
, int ifIndex
, String serviceName
, int rrtype
,
582 int rrclass
, QueryListener client
)
583 throws DNSSDException
585 return new AppleQuery( flags
, ifIndex
, serviceName
, rrtype
, rrclass
, client
);
588 protected DNSSDService
_enumerateDomains( int flags
, int ifIndex
, DomainListener listener
)
589 throws DNSSDException
591 return new AppleDomainEnum( flags
, ifIndex
, listener
);
594 protected String
_constructFullName( String serviceName
, String regType
, String domain
)
595 throws DNSSDException
597 String
[] responseHolder
= new String
[1]; // lame maneuver to get around Java's lack of reference parameters
599 int rc
= ConstructName( serviceName
, regType
, domain
, responseHolder
);
601 throw new AppleDNSSDException( rc
);
603 return responseHolder
[0];
606 protected void _reconfirmRecord( int flags
, int ifIndex
, String fullName
, int rrtype
,
607 int rrclass
, byte[] rdata
)
609 ReconfirmRecord( flags
, ifIndex
, fullName
, rrtype
, rrclass
, rdata
);
612 protected String
_getNameForIfIndex( int ifIndex
)
614 return GetNameForIfIndex( ifIndex
);
617 protected int _getIfIndexForName( String ifName
)
619 return GetIfIndexForName( ifName
);
623 protected native int ConstructName( String serviceName
, String regType
, String domain
, String
[] pOut
);
625 protected native void ReconfirmRecord( int flags
, int ifIndex
, String fullName
, int rrtype
,
626 int rrclass
, byte[] rdata
);
628 protected native String
GetNameForIfIndex( int ifIndex
);
630 protected native int GetIfIndexForName( String ifName
);
632 protected static native int InitLibrary( int callerVersion
);
635 class AppleService
implements DNSSDService
, Runnable
637 public AppleService(BaseListener listener
) { fNativeContext
= 0; fListener
= listener
; }
639 public void stop() { this.HaltOperation(); }
641 /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
642 protected native int BlockForData();
644 /* Call ProcessResults when data appears on socket descriptor. */
645 protected native int ProcessResults();
647 protected synchronized native void HaltOperation();
649 protected void ThrowOnErr( int rc
) throws DNSSDException
652 throw new AppleDNSSDException( rc
);
655 protected long /* warning */ fNativeContext
; // Private storage for native side
661 // Note: We want to allow our DNS-SD operation to be stopped from other threads, so we have to
662 // block waiting for data *outside* the synchronized section. Because we're doing this unsynchronized
663 // we have to write some careful code. Suppose our DNS-SD operation is stopped from some other thread,
664 // and then immediately afterwards that thread (or some third, unrelated thread) starts a new DNS-SD
665 // operation. The Unix kernel always allocates the lowest available file descriptor to a new socket,
666 // so the same file descriptor is highly likely to be reused for the new operation, and if our old
667 // stale ServiceThread accidentally consumes bytes off that new socket we'll get really messed up.
668 // To guard against that, before calling ProcessResults we check to ensure that our
669 // fNativeContext has not been deleted, which is a telltale sign that our operation was stopped.
670 // After calling ProcessResults we check again, because it's extremely common for callback
671 // functions to stop their own operation and start others. For example, a resolveListener callback
672 // may well stop the resolve and then start a QueryRecord call to monitor the TXT record.
674 // The remaining risk is that between our checking fNativeContext and calling ProcessResults(),
675 // some other thread could stop the operation and start a new one using same file descriptor, and
676 // we wouldn't know. To prevent this, the AppleService object's HaltOperation() routine is declared
677 // synchronized and we perform our checks synchronized on the AppleService object, which ensures
678 // that HaltOperation() can't execute while we're doing it. Because Java locks are re-entrant this
679 // locking DOESN'T prevent the callback routine from stopping its own operation, but DOES prevent
680 // any other thread from stopping it until after the callback has completed and returned to us here.
682 int result
= BlockForData();
685 if (fNativeContext
== 0) break; // Some other thread stopped our DNSSD operation; time to terminate this thread
686 if (result
== 0) continue; // If BlockForData() said there was no data, go back and block again
687 result
= ProcessResults();
688 if (fNativeContext
== 0) break; // Event listener stopped its own DNSSD operation; terminate this thread
689 if (result
!= 0) { fListener
.operationFailed(this, result
); break; } // If error, notify listener
694 protected BaseListener fListener
;
698 class AppleBrowser
extends AppleService
700 public AppleBrowser( int flags
, int ifIndex
, String regType
, String domain
, BrowseListener client
)
701 throws DNSSDException
704 this.ThrowOnErr( this.CreateBrowser( flags
, ifIndex
, regType
, domain
));
705 if (!AppleDNSSD
.hasAutoCallbacks
)
706 new Thread(this).start();
709 // Sets fNativeContext. Returns non-zero on error.
710 protected native int CreateBrowser( int flags
, int ifIndex
, String regType
, String domain
);
713 class AppleResolver
extends AppleService
715 public AppleResolver( int flags
, int ifIndex
, String serviceName
, String regType
,
716 String domain
, ResolveListener client
)
717 throws DNSSDException
720 this.ThrowOnErr( this.CreateResolver( flags
, ifIndex
, serviceName
, regType
, domain
));
721 if (!AppleDNSSD
.hasAutoCallbacks
)
722 new Thread(this).start();
725 // Sets fNativeContext. Returns non-zero on error.
726 protected native int CreateResolver( int flags
, int ifIndex
, String serviceName
, String regType
,
730 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
731 class AppleDNSRecord
implements DNSRecord
733 public AppleDNSRecord( AppleService owner
)
736 fRecord
= 0; // record always starts out empty
739 public void update( int flags
, byte[] rData
, int ttl
)
740 throws DNSSDException
742 this.ThrowOnErr( this.Update( flags
, rData
, ttl
));
746 throws DNSSDException
748 this.ThrowOnErr( this.Remove());
751 protected long fRecord
; // Really a DNSRecord; sizeof(long) == sizeof(void*) ?
752 protected AppleService fOwner
;
754 protected void ThrowOnErr( int rc
) throws DNSSDException
757 throw new AppleDNSSDException( rc
);
760 protected native int Update( int flags
, byte[] rData
, int ttl
);
762 protected native int Remove();
765 class AppleRegistration
extends AppleService
implements DNSSDRegistration
767 public AppleRegistration( int flags
, int ifIndex
, String serviceName
, String regType
, String domain
,
768 String host
, int port
, byte[] txtRecord
, RegisterListener client
)
769 throws DNSSDException
772 this.ThrowOnErr( this.BeginRegister( ifIndex
, flags
, serviceName
, regType
, domain
, host
, port
, txtRecord
));
773 if (!AppleDNSSD
.hasAutoCallbacks
)
774 new Thread(this).start();
777 public DNSRecord
addRecord( int flags
, int rrType
, byte[] rData
, int ttl
)
778 throws DNSSDException
780 AppleDNSRecord newRecord
= new AppleDNSRecord( this);
782 this.ThrowOnErr( this.AddRecord( flags
, rrType
, rData
, ttl
, newRecord
));
786 public DNSRecord
getTXTRecord()
787 throws DNSSDException
789 return new AppleDNSRecord( this); // A record with ref 0 is understood to be primary TXT record
792 // Sets fNativeContext. Returns non-zero on error.
793 protected native int BeginRegister( int ifIndex
, int flags
, String serviceName
, String regType
,
794 String domain
, String host
, int port
, byte[] txtRecord
);
796 // Sets fNativeContext. Returns non-zero on error.
797 protected native int AddRecord( int flags
, int rrType
, byte[] rData
, int ttl
, AppleDNSRecord destObj
);
800 class AppleRecordRegistrar
extends AppleService
implements DNSSDRecordRegistrar
802 public AppleRecordRegistrar( RegisterRecordListener listener
)
803 throws DNSSDException
806 this.ThrowOnErr( this.CreateConnection());
807 if (!AppleDNSSD
.hasAutoCallbacks
)
808 new Thread(this).start();
811 public DNSRecord
registerRecord( int flags
, int ifIndex
, String fullname
, int rrtype
,
812 int rrclass
, byte[] rdata
, int ttl
)
813 throws DNSSDException
815 AppleDNSRecord newRecord
= new AppleDNSRecord( this);
817 this.ThrowOnErr( this.RegisterRecord( flags
, ifIndex
, fullname
, rrtype
, rrclass
, rdata
, ttl
, newRecord
));
821 // Sets fNativeContext. Returns non-zero on error.
822 protected native int CreateConnection();
824 // Sets fNativeContext. Returns non-zero on error.
825 protected native int RegisterRecord( int flags
, int ifIndex
, String fullname
, int rrtype
,
826 int rrclass
, byte[] rdata
, int ttl
, AppleDNSRecord destObj
);
829 class AppleQuery
extends AppleService
831 public AppleQuery( int flags
, int ifIndex
, String serviceName
, int rrtype
,
832 int rrclass
, QueryListener client
)
833 throws DNSSDException
836 this.ThrowOnErr( this.CreateQuery( flags
, ifIndex
, serviceName
, rrtype
, rrclass
));
837 if (!AppleDNSSD
.hasAutoCallbacks
)
838 new Thread(this).start();
841 // Sets fNativeContext. Returns non-zero on error.
842 protected native int CreateQuery( int flags
, int ifIndex
, String serviceName
, int rrtype
, int rrclass
);
845 class AppleDomainEnum
extends AppleService
847 public AppleDomainEnum( int flags
, int ifIndex
, DomainListener client
)
848 throws DNSSDException
851 this.ThrowOnErr( this.BeginEnum( flags
, ifIndex
));
852 if (!AppleDNSSD
.hasAutoCallbacks
)
853 new Thread(this).start();
856 // Sets fNativeContext. Returns non-zero on error.
857 protected native int BeginEnum( int flags
, int ifIndex
);