X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/c9d2d929f6ad52e6996754033ee77c725b90d1d4..8ec81f6c99056f5c63e0045ca48a7c405058254b:/mDNSShared/Java/DNSSD.java diff --git a/mDNSShared/Java/DNSSD.java b/mDNSShared/Java/DNSSD.java index d8a7ce1..f749a88 100644 --- a/mDNSShared/Java/DNSSD.java +++ b/mDNSShared/Java/DNSSD.java @@ -1,60 +1,22 @@ -/* +/* -*- Mode: Java; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - - Change History (most recent first): - -$Log: DNSSD.java,v $ -Revision 1.8 2005/07/11 01:55:21 cheshire - Race condition in Java API - -Revision 1.7 2005/07/05 13:01:52 cheshire - If mDNSResponder daemon is stopped, Java API spins, burning CPU time - -Revision 1.6 2005/07/05 00:02:25 cheshire -Add missing comma - -Revision 1.5 2005/07/04 21:13:47 cheshire -Add missing error message strings - -Revision 1.4 2004/12/11 03:00:59 rpantos - Java DNSRecord API should be cleaned up - -Revision 1.3 2004/11/12 03:23:08 rpantos -rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex. - -Revision 1.2 2004/05/20 17:43:18 cheshire -Fix invalid UTF-8 characters in file - -Revision 1.1 2004/04/30 16:32:34 rpantos -First checked in. - This file declares and implements DNSSD, the central Java factory class for doing DNS Service Discovery. It includes the mostly-abstract public interface, as well as the Apple* implementation subclasses. - - To do: - - implement network interface mappings - - RegisterRecord */ @@ -65,19 +27,19 @@ package com.apple.dnssd; DNSSD provides access to DNS Service Discovery features of ZeroConf networking.

It is a factory class that is used to invoke registration and discovery-related - operations. Most operations are non-blocking; clients are called back through an interface + operations. Most operations are non-blocking; clients are called back through an interface with the result of an operation. Callbacks are made from a separate worker thread.

- For example, in this program

+ For example, in this program


     class   MyClient implements BrowseListener {
         void    lookForWebServers() {
-            myBrowser = DNSSD.browse("_http_.tcp", this);
+            myBrowser = DNSSD.browse("_http._tcp", this);
         }
     
-        public void serviceFound(DNSSDService browser, int flags, int ifIndex, 
+        public void serviceFound(DNSSDService browser, int flags, int ifIndex,
                             String serviceName, String regType, String domain) {}
-        ... 
+        ...
     }
MyClient.serviceFound() would be called for every HTTP server discovered in the default browse domain(s). @@ -89,14 +51,14 @@ abstract public class DNSSD queued. Applications should not update their UI to display browse results if the MORE_COMING flag is set; they will be called at least once more with the flag clear. - */ + */ public static final int MORE_COMING = ( 1 << 0 ); /** If flag is set in a {@link DomainListener} callback, indicates that the result is the default domain. */ public static final int DEFAULT = ( 1 << 2 ); - /** If flag is set, a name conflict will trigger an exception when registering non-shared records.

- A name must be explicitly specified when registering a service if this bit is set + /** If flag is set, a name conflict will trigger an exception when registering non-shared records.

+ A name must be explicitly specified when registering a service if this bit is set (i.e. the default name may not not be used). */ public static final int NO_AUTO_RENAME = ( 1 << 3 ); @@ -115,7 +77,7 @@ abstract public class DNSSD public static final int REGISTRATION_DOMAINS = ( 1 << 7 ); /** Maximum length, in bytes, of a domain name represented as an escaped C-String. */ - public static final int MAX_DOMAIN_NAME = 1005; + public static final int MAX_DOMAIN_NAME = 1009; /** Pass for ifIndex to specify all available interfaces. */ public static final int ALL_INTERFACES = 0; @@ -123,7 +85,7 @@ abstract public class DNSSD /** Pass for ifIndex to specify the localhost interface. */ public static final int LOCALHOST_ONLY = -1; - /** Browse for instances of a service.

+ /** Browse for instances of a service.

Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.

@@ -137,12 +99,12 @@ abstract public class DNSSD interfaces. Pass -1 to only browse for services provided on the local host.

@param regType - The registration type being browsed for followed by the protocol, separated by a + The registration type being browsed for followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".

@param domain If non-null, specifies the domain on which to browse for services. - Most applications will not specify a domain, instead browsing on the + Most applications will not specify a domain, instead browsing on the default domain(s).

@param listener @@ -157,10 +119,10 @@ abstract public class DNSSD throws DNSSDException { return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); } - /** Browse for instances of a service. Use default flags, ifIndex and domain.

+ /** Browse for instances of a service. Use default flags, ifIndex and domain.

@param regType - The registration type being browsed for followed by the protocol, separated by a + The registration type being browsed for followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".

@param listener @@ -175,16 +137,16 @@ abstract public class DNSSD throws DNSSDException { return browse( 0, 0, regType, "", listener); } - /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.

+ /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.

- Note: Applications should NOT use resolve() solely for txt record monitoring - use + Note: Applications should NOT use resolve() solely for txt record monitoring - use queryRecord() instead, as it is more efficient for this task.

- Note: When the desired results have been returned, the client MUST terminate the resolve by + Note: When the desired results have been returned, the client MUST terminate the resolve by calling {@link DNSSDService#stop}.

Note: resolve() behaves correctly for typical services that have a single SRV record and - a single TXT record (the TXT record may be empty.) To resolve non-standard services with + a single TXT record (the TXT record may be empty.) To resolve non-standard services with multiple SRV or TXT records, use queryRecord().

@param flags @@ -192,7 +154,7 @@ abstract public class DNSSD

@param ifIndex The interface on which to resolve the service. The client should - pass the interface on which the serviceName was discovered (i.e. + pass the interface on which the serviceName was discovered (i.e. the ifIndex passed to the serviceFound() callback) or 0 to resolve the named service on all available interfaces.

@@ -200,8 +162,8 @@ abstract public class DNSSD The servicename to be resolved.

@param regType - The registration type being resolved followed by the protocol, separated by a - dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". + The registration type being resolved followed by the protocol, separated by a + dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".

@param domain The domain on which the service is registered, i.e. the domain passed @@ -215,54 +177,54 @@ abstract public class DNSSD @throws SecurityException If a security manager is present and denies RuntimePermission("getDNSSDInstance"). @see RuntimePermission */ - public static DNSSDService resolve( int flags, int ifIndex, String serviceName, String regType, + public static DNSSDService resolve( int flags, int ifIndex, String serviceName, String regType, String domain, ResolveListener listener) throws DNSSDException { return getInstance()._resolve( flags, ifIndex, serviceName, regType, domain, listener); } - /** Register a service, to be discovered via browse() and resolve() calls.

+ /** Register a service, to be discovered via browse() and resolve() calls.

@param flags Possible values are: NO_AUTO_RENAME.

@param ifIndex If non-zero, specifies the interface on which to register the service (the index for a given interface is determined via the if_nametoindex() - family of calls.) Most applications will pass 0 to register on all - available interfaces. Pass -1 to register a service only on the local + family of calls.) Most applications will pass 0 to register on all + available interfaces. Pass -1 to register a service only on the local machine (service will not be visible to remote hosts).

@param serviceName - If non-null, specifies the service name to be registered. - Applications need not specify a name, in which case the - computer name is used (this name is communicated to the client via + If non-null, specifies the service name to be registered. + Applications need not specify a name, in which case the + computer name is used (this name is communicated to the client via the serviceRegistered() callback).

@param regType - The registration type being registered followed by the protocol, separated by a - dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". + The registration type being registered followed by the protocol, separated by a + dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".

@param domain If non-null, specifies the domain on which to advertise the service. - Most applications will not specify a domain, instead automatically + Most applications will not specify a domain, instead automatically registering in the default domain(s).

@param host If non-null, specifies the SRV target host name. Most applications will not specify a host, instead automatically using the machine's - default host name(s). Note that specifying a non-null host does NOT - create an address record for that host - the application is responsible + default host name(s). Note that specifying a non-null host does NOT + create an address record for that host - the application is responsible for ensuring that the appropriate address record exists, or creating it via {@link DNSSDRegistration#addRecord}.

@param port - The port on which the service accepts connections. Pass 0 for a - "placeholder" service (i.e. a service that will not be discovered by - browsing, but will cause a name conflict if another client tries to + The port on which the service accepts connections. Pass 0 for a + "placeholder" service (i.e. a service that will not be discovered by + browsing, but will cause a name conflict if another client tries to register that same name.) Most clients will not use placeholder services.

@param txtRecord - The txt record rdata. May be null. Note that a non-null txtRecord - MUST be a properly formatted DNS TXT record, i.e. <length byte> <data> + The txt record rdata. May be null. Note that a non-null txtRecord + MUST be a properly formatted DNS TXT record, i.e. <length byte> <data> <length byte> <data> ...

@param listener @@ -273,26 +235,26 @@ abstract public class DNSSD @throws SecurityException If a security manager is present and denies RuntimePermission("getDNSSDInstance"). @see RuntimePermission */ - public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType, + public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType, String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener) throws DNSSDException { return getInstance()._register( flags, ifIndex, serviceName, regType, domain, host, port, txtRecord, listener); } - /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.

+ /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.

@param serviceName - If non-null, specifies the service name to be registered. - Applications need not specify a name, in which case the - computer name is used (this name is communicated to the client via + If non-null, specifies the service name to be registered. + Applications need not specify a name, in which case the + computer name is used (this name is communicated to the client via the serviceRegistered() callback).

@param regType - The registration type being registered followed by the protocol, separated by a - dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". + The registration type being registered followed by the protocol, separated by a + dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".

@param port - The port on which the service accepts connections. Pass 0 for a - "placeholder" service (i.e. a service that will not be discovered by - browsing, but will cause a name conflict if another client tries to + The port on which the service accepts connections. Pass 0 for a + "placeholder" service (i.e. a service that will not be discovered by + browsing, but will cause a name conflict if another client tries to register that same name.) Most clients will not use placeholder services.

@param listener @@ -307,14 +269,26 @@ abstract public class DNSSD throws DNSSDException { return register( 0, 0, serviceName, regType, null, null, port, null, listener); } - /** Query for an arbitrary DNS record.

+ /** Create a {@link DNSSDRecordRegistrar} allowing efficient registration of + multiple individual records.

+

+ @return A {@link DNSSDRecordRegistrar} that can be used to register records. + + @throws SecurityException If a security manager is present and denies RuntimePermission("getDNSSDInstance"). + @see RuntimePermission + */ + public static DNSSDRecordRegistrar createRecordRegistrar( RegisterRecordListener listener) + throws DNSSDException + { return getInstance()._createRecordRegistrar( listener); } + + /** Query for an arbitrary DNS record.

@param flags Possible values are: MORE_COMING.

@param ifIndex If non-zero, specifies the interface on which to issue the query (the index for a given interface is determined via the if_nametoindex() - family of calls.) Passing 0 causes the name to be queried for on all + family of calls.) Passing 0 causes the name to be queried for on all interfaces. Passing -1 causes the name to be queried for only on the local host.

@@ -326,7 +300,7 @@ abstract public class DNSSD as defined in nameser.h.

@param rrclass - The class of the resource record, as defined in nameser.h + The class of the resource record, as defined in nameser.h (usually 1 for the Internet class).

@param listener @@ -337,12 +311,12 @@ abstract public class DNSSD @throws SecurityException If a security manager is present and denies RuntimePermission("getDNSSDInstance"). @see RuntimePermission */ - public static DNSSDService queryRecord( int flags, int ifIndex, String serviceName, int rrtype, + public static DNSSDService queryRecord( int flags, int ifIndex, String serviceName, int rrtype, int rrclass, QueryListener listener) throws DNSSDException { return getInstance()._queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, listener); } - /** Asynchronously enumerate domains available for browsing and registration.

+ /** Asynchronously enumerate domains available for browsing and registration.

Currently, the only domain returned is "local.", but other domains will be returned in future.

@@ -354,8 +328,8 @@ abstract public class DNSSD @param ifIndex If non-zero, specifies the interface on which to look for domains. (the index for a given interface is determined via the if_nametoindex() - family of calls.) Most applications will pass 0 to enumerate domains on - all interfaces. + family of calls.) Most applications will pass 0 to enumerate domains on + all interfaces.

@param listener This object will get called when domains are found. @@ -369,15 +343,15 @@ abstract public class DNSSD throws DNSSDException { return getInstance()._enumerateDomains( flags, ifIndex, listener); } - /** Concatenate a three-part domain name (as provided to the listeners) into a - properly-escaped full domain name. Note that strings passed to listeners are - ALREADY ESCAPED where necessary.

+ /** Concatenate a three-part domain name (as provided to the listeners) into a + properly-escaped full domain name. Note that strings passed to listeners are + ALREADY ESCAPED where necessary.

@param serviceName The service name - any dots or slashes must NOT be escaped. May be null (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").

@param regType - The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp"). + The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").

@param domain The domain name, e.g. "apple.com". Any literal dots or backslashes must be escaped. @@ -391,10 +365,10 @@ abstract public class DNSSD throws DNSSDException { return getInstance()._constructFullName( serviceName, regType, domain); } - /** Instruct the daemon to verify the validity of a resource record that appears to - be out of date. (e.g. because tcp connection to a service's target failed.)

+ /** Instruct the daemon to verify the validity of a resource record that appears to + be out of date. (e.g. because tcp connection to a service's target failed.)

- Causes the record to be flushed from the daemon's cache (as well as all other + Causes the record to be flushed from the daemon's cache (as well as all other daemons' caches on the network) if the record is determined to be invalid.

@param flags Currently unused, reserved for future use. @@ -402,7 +376,7 @@ abstract public class DNSSD @param ifIndex If non-zero, specifies the interface on which to reconfirm the record (the index for a given interface is determined via the if_nametoindex() - family of calls.) Passing 0 causes the name to be reconfirmed on all + family of calls.) Passing 0 causes the name to be reconfirmed on all interfaces. Passing -1 causes the name to be reconfirmed only on the local host.

@@ -421,11 +395,11 @@ abstract public class DNSSD @throws SecurityException If a security manager is present and denies RuntimePermission("getDNSSDInstance"). @see RuntimePermission */ - public static void reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, + public static void reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, int rrclass, byte[] rdata) { getInstance()._reconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); } - /** Return the canonical name of a particular interface index.

+ /** Return the canonical name of a particular interface index.

@param ifIndex A valid interface index. Must not be ALL_INTERFACES.

@@ -437,7 +411,7 @@ abstract public class DNSSD public static String getNameForIfIndex( int ifIndex) { return getInstance()._getNameForIfIndex( ifIndex); } - /** Return the index of a named interface.

+ /** Return the index of a named interface.

@param ifName A valid interface name. An example is java.net.NetworkInterface.getName().

@@ -452,26 +426,29 @@ abstract public class DNSSD protected DNSSD() {} // prevent direct instantiation /** Return the single instance of DNSSD. */ - static protected final DNSSD getInstance() + static protected final DNSSD getInstance() { SecurityManager sm = System.getSecurityManager(); - if ( sm != null) - sm.checkPermission( new RuntimePermission( "getDNSSDInstance")); - return fInstance; + if (sm != null) + sm.checkPermission( new RuntimePermission( "getDNSSDInstance")); + return fInstance; } abstract protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener listener) throws DNSSDException; - abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType, + abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType, String domain, ResolveListener listener) throws DNSSDException; - abstract protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType, + abstract protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType, String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener) throws DNSSDException; - abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype, + abstract protected DNSSDRecordRegistrar _createRecordRegistrar( RegisterRecordListener listener) + throws DNSSDException; + + abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype, int rrclass, QueryListener listener) throws DNSSDException; @@ -481,7 +458,7 @@ abstract public class DNSSD abstract protected String _constructFullName( String serviceName, String regType, String domain) throws DNSSDException; - abstract protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, + abstract protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, int rrclass, byte[] rdata); abstract protected String _getNameForIfIndex( int ifIndex); @@ -493,11 +470,11 @@ abstract public class DNSSD static { try - { + { String name = System.getProperty( "com.apple.dnssd.DNSSD" ); - if( name == null ) + if (name == null) name = "com.apple.dnssd.AppleDNSSD"; // Fall back to Apple-provided class. - fInstance = (DNSSD) Class.forName( name ).newInstance(); + fInstance = (DNSSD) Class.forName(name).newInstance(); } catch( Exception e ) { @@ -542,10 +519,13 @@ class AppleDNSSDException extends DNSSDException "BADTIME", "BADSIG", "BADKEY", - "TRANSIENT" + "TRANSIENT", + "SERVICENOTRUNNING", + "NATPORTMAPPINGUNSUPPORTED", + "NATPORTMAPPINGDISABLED" }; - if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length)) + if (fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length)) { return "DNS-SD Error " + String.valueOf( fErrorCode) + ": " + kMessages[ UNKNOWN - fErrorCode]; } @@ -563,9 +543,9 @@ class AppleDNSSD extends DNSSD { System.loadLibrary( "jdns_sd"); - int libInitResult = InitLibrary( 1); + int libInitResult = InitLibrary( 2); // Current version number (must be sync'd with jnilib version) - if ( libInitResult != DNSSDException.NO_ERROR) + if (libInitResult != DNSSDException.NO_ERROR) throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage()); } @@ -577,22 +557,28 @@ class AppleDNSSD extends DNSSD return new AppleBrowser( flags, ifIndex, regType, domain, client); } - protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType, + protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType, String domain, ResolveListener client) throws DNSSDException { return new AppleResolver( flags, ifIndex, serviceName, regType, domain, client); } - protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType, + protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType, String domain, String host, int port, TXTRecord txtRecord, RegisterListener client) throws DNSSDException { - return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port, + return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port, ( txtRecord != null) ? txtRecord.getRawBytes() : null, client); } - protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype, + protected DNSSDRecordRegistrar _createRecordRegistrar( RegisterRecordListener listener) + throws DNSSDException + { + return new AppleRecordRegistrar( listener); + } + + protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype, int rrclass, QueryListener client) throws DNSSDException { @@ -611,13 +597,13 @@ class AppleDNSSD extends DNSSD String[] responseHolder = new String[1]; // lame maneuver to get around Java's lack of reference parameters int rc = ConstructName( serviceName, regType, domain, responseHolder); - if ( rc != 0) + if (rc != 0) throw new AppleDNSSDException( rc); return responseHolder[0]; } - protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, + protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, int rrclass, byte[] rdata) { ReconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); @@ -636,7 +622,7 @@ class AppleDNSSD extends DNSSD protected native int ConstructName( String serviceName, String regType, String domain, String[] pOut); - protected native void ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, + protected native void ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, int rrclass, byte[] rdata); protected native String GetNameForIfIndex( int ifIndex); @@ -652,8 +638,8 @@ class AppleService implements DNSSDService, Runnable public void stop() { this.HaltOperation(); } - /* Block for timeout ms (or forever if -1). Returns 1 if data present, 0 if timed out, -1 if not browsing. */ - protected native int BlockForData( int msTimeout); + /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */ + protected native int BlockForData(); /* Call ProcessResults when data appears on socket descriptor. */ protected native int ProcessResults(); @@ -662,17 +648,19 @@ class AppleService implements DNSSDService, Runnable protected void ThrowOnErr( int rc) throws DNSSDException { - if ( rc != 0) + if (rc != 0) throw new AppleDNSSDException( rc); } - protected int /* warning */ fNativeContext; // Private storage for native side + protected long /* warning */ fNativeContext; // Private storage for native side public void run() { while ( true ) { - // We have to be very careful here. Suppose our DNS-SD operation is stopped from some other thread, + // Note: We want to allow our DNS-SD operation to be stopped from other threads, so we have to + // block waiting for data *outside* the synchronized section. Because we're doing this unsynchronized + // we have to write some careful code. Suppose our DNS-SD operation is stopped from some other thread, // and then immediately afterwards that thread (or some third, unrelated thread) starts a new DNS-SD // operation. The Unix kernel always allocates the lowest available file descriptor to a new socket, // so the same file descriptor is highly likely to be reused for the new operation, and if our old @@ -691,11 +679,11 @@ class AppleService implements DNSSDService, Runnable // locking DOESN'T prevent the callback routine from stopping its own operation, but DOES prevent // any other thread from stopping it until after the callback has completed and returned to us here. - int result = BlockForData(-1); - if (result != 1) break; // If socket has been closed, time to terminate this thread + int result = BlockForData(); synchronized (this) { if (fNativeContext == 0) break; // Some other thread stopped our DNSSD operation; time to terminate this thread + if (result == 0) continue; // If BlockForData() said there was no data, go back and block again result = ProcessResults(); if (fNativeContext == 0) break; // Event listener stopped its own DNSSD operation; terminate this thread if (result != 0) { fListener.operationFailed(this, result); break; } // If error, notify listener @@ -709,12 +697,12 @@ class AppleService implements DNSSDService, Runnable class AppleBrowser extends AppleService { - public AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client) + public AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client) throws DNSSDException - { + { super(client); this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain)); - if ( !AppleDNSSD.hasAutoCallbacks) + if (!AppleDNSSD.hasAutoCallbacks) new Thread(this).start(); } @@ -724,27 +712,27 @@ class AppleBrowser extends AppleService class AppleResolver extends AppleService { - public AppleResolver( int flags, int ifIndex, String serviceName, String regType, - String domain, ResolveListener client) + public AppleResolver( int flags, int ifIndex, String serviceName, String regType, + String domain, ResolveListener client) throws DNSSDException - { - super(client); + { + super(client); this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain)); - if ( !AppleDNSSD.hasAutoCallbacks) + if (!AppleDNSSD.hasAutoCallbacks) new Thread(this).start(); } // Sets fNativeContext. Returns non-zero on error. - protected native int CreateResolver( int flags, int ifIndex, String serviceName, String regType, + protected native int CreateResolver( int flags, int ifIndex, String serviceName, String regType, String domain); } // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord. class AppleDNSRecord implements DNSRecord { - public AppleDNSRecord( AppleService owner) - { - fOwner = owner; + public AppleDNSRecord( AppleService owner) + { + fOwner = owner; fRecord = 0; // record always starts out empty } @@ -760,12 +748,12 @@ class AppleDNSRecord implements DNSRecord this.ThrowOnErr( this.Remove()); } - protected int fRecord; // Really a DNSRecord; sizeof(int) == sizeof(void*) ? + protected long fRecord; // Really a DNSRecord; sizeof(long) == sizeof(void*) ? protected AppleService fOwner; protected void ThrowOnErr( int rc) throws DNSSDException { - if ( rc != 0) + if (rc != 0) throw new AppleDNSSDException( rc); } @@ -776,13 +764,13 @@ class AppleDNSRecord implements DNSRecord class AppleRegistration extends AppleService implements DNSSDRegistration { - public AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain, - String host, int port, byte[] txtRecord, RegisterListener client) + public AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain, + String host, int port, byte[] txtRecord, RegisterListener client) throws DNSSDException - { - super(client); + { + super(client); this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord)); - if ( !AppleDNSSD.hasAutoCallbacks) + if (!AppleDNSSD.hasAutoCallbacks) new Thread(this).start(); } @@ -792,7 +780,6 @@ class AppleRegistration extends AppleService implements DNSSDRegistration AppleDNSRecord newRecord = new AppleDNSRecord( this); this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord)); - return newRecord; } @@ -803,22 +790,51 @@ class AppleRegistration extends AppleService implements DNSSDRegistration } // Sets fNativeContext. Returns non-zero on error. - protected native int BeginRegister( int ifIndex, int flags, String serviceName, String regType, + protected native int BeginRegister( int ifIndex, int flags, String serviceName, String regType, String domain, String host, int port, byte[] txtRecord); // Sets fNativeContext. Returns non-zero on error. protected native int AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj); } +class AppleRecordRegistrar extends AppleService implements DNSSDRecordRegistrar +{ + public AppleRecordRegistrar( RegisterRecordListener listener) + throws DNSSDException + { + super(listener); + this.ThrowOnErr( this.CreateConnection()); + if (!AppleDNSSD.hasAutoCallbacks) + new Thread(this).start(); + } + + public DNSRecord registerRecord( int flags, int ifIndex, String fullname, int rrtype, + int rrclass, byte[] rdata, int ttl) + throws DNSSDException + { + AppleDNSRecord newRecord = new AppleDNSRecord( this); + + this.ThrowOnErr( this.RegisterRecord( flags, ifIndex, fullname, rrtype, rrclass, rdata, ttl, newRecord)); + return newRecord; + } + + // Sets fNativeContext. Returns non-zero on error. + protected native int CreateConnection(); + + // Sets fNativeContext. Returns non-zero on error. + protected native int RegisterRecord( int flags, int ifIndex, String fullname, int rrtype, + int rrclass, byte[] rdata, int ttl, AppleDNSRecord destObj); +} + class AppleQuery extends AppleService { - public AppleQuery( int flags, int ifIndex, String serviceName, int rrtype, - int rrclass, QueryListener client) + public AppleQuery( int flags, int ifIndex, String serviceName, int rrtype, + int rrclass, QueryListener client) throws DNSSDException - { - super(client); + { + super(client); this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass)); - if ( !AppleDNSSD.hasAutoCallbacks) + if (!AppleDNSSD.hasAutoCallbacks) new Thread(this).start(); } @@ -828,12 +844,12 @@ class AppleQuery extends AppleService class AppleDomainEnum extends AppleService { - public AppleDomainEnum( int flags, int ifIndex, DomainListener client) + public AppleDomainEnum( int flags, int ifIndex, DomainListener client) throws DNSSDException - { - super(client); + { + super(client); this.ThrowOnErr( this.BeginEnum( flags, ifIndex)); - if ( !AppleDNSSD.hasAutoCallbacks) + if (!AppleDNSSD.hasAutoCallbacks) new Thread(this).start(); }