]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSShared/Java/DNSSD.java
mDNSResponder-214.3.2.tar.gz
[apple/mdnsresponder.git] / mDNSShared / Java / DNSSD.java
index 831b4b458142c7aa24985123149c006534731519..e608869f8618b47239f317e0f3cd74ee6eab73c6 100644 (file)
@@ -1,28 +1,58 @@
-/*
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
  * 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.
  * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: DNSSD.java,v $
 
     Change History (most recent first):
 
 $Log: DNSSD.java,v $
+Revision 1.16  2008/11/04 20:06:20  cheshire
+<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
+
+Revision 1.15  2007/03/13 00:28:03  vazquez
+<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
+
+Revision 1.14  2007/03/13 00:10:14  vazquez
+<rdar://problem/4455206> Java: 64 bit JNI patch
+
+Revision 1.13  2007/02/24 23:08:02  mkrochma
+<rdar://problem/5001673> Typo in Bonjour Java API document
+
+Revision 1.12  2007/02/09 00:33:02  cheshire
+Add missing error codes to kMessages array
+
+Revision 1.11  2006/08/14 23:25:08  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.10  2006/06/20 23:05:55  rpantos
+<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
+
+Revision 1.9  2005/10/26 01:52:24  cheshire
+<rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
+
+Revision 1.8  2005/07/11 01:55:21  cheshire
+<rdar://problem/4175511> Race condition in Java API
+
+Revision 1.7  2005/07/05 13:01:52  cheshire
+<rdar://problem/4169791> 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
 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
 
 Revision 1.4  2004/12/11 03:00:59  rpantos
 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
 
@@ -39,10 +69,6 @@ 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.
        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
  */
 
 
  */
 
 
@@ -53,19 +79,19 @@ package     com.apple.dnssd;
        DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
 
        It is a factory class that is used to invoke registration and discovery-related
        DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
 
        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.<P>
 
        with the result of an operation. Callbacks are made from a separate worker thread.<P>
 
-       For example, in this program<P> 
+       For example, in this program<P>
        <PRE><CODE>
     class   MyClient implements BrowseListener {
         void    lookForWebServers() {
        <PRE><CODE>
     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) {}
                             String serviceName, String regType, String domain) {}
-        ... 
+        ...
     }</CODE></PRE>
        <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
        default browse domain(s).
     }</CODE></PRE>
        <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
        default browse domain(s).
@@ -77,14 +103,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.
                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 );
 
        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.<P> 
-       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.<P>
+       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 );
        (i.e. the default name may not not be used).
      */
        public static final int         NO_AUTO_RENAME = ( 1 << 3 );
@@ -103,7 +129,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         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;
 
        /** Pass for ifIndex to specify all available interfaces. */
     public static final int     ALL_INTERFACES = 0;
@@ -111,7 +137,7 @@ abstract public class       DNSSD
        /** Pass for ifIndex to specify the localhost interface. */
     public static final int     LOCALHOST_ONLY = -1;
 
        /** Pass for ifIndex to specify the localhost interface. */
     public static final int     LOCALHOST_ONLY = -1;
 
-       /** Browse for instances of a service.<P> 
+       /** Browse for instances of a service.<P>
 
                Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
 
 
                Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
 
@@ -125,12 +151,12 @@ abstract public class     DNSSD
                                        interfaces.  Pass -1 to only browse for services provided on the local host.
                <P>
                @param  regType
                                        interfaces.  Pass -1 to only browse for services provided on the local host.
                <P>
                @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".
                <P>
                @param  domain
                                        If non-null, specifies the domain on which to browse for services.
                                        dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
                <P>
                @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).
                <P>
                @param  listener
                                        default domain(s).
                <P>
                @param  listener
@@ -145,10 +171,10 @@ abstract public class     DNSSD
        throws DNSSDException
        { return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); }
 
        throws DNSSDException
        { return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); }
 
-       /** Browse for instances of a service. Use default flags, ifIndex and domain.<P> 
+       /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
 
                @param  regType
 
                @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".
                <P>
                @param  listener
                                        dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
                <P>
                @param  listener
@@ -163,16 +189,16 @@ abstract public class     DNSSD
        throws DNSSDException
        { return browse( 0, 0, regType, "", listener); }
 
        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.<P> 
+       /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
                
                
-               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.<P>
                
                queryRecord() instead, as it is more efficient for this task.<P>
                
-               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}.<P>
 
                Note: resolve() behaves correctly for typical services that have a single SRV record and
                calling {@link DNSSDService#stop}.<P>
 
                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().<P>
 
                @param  flags
                multiple SRV or TXT records, use queryRecord().<P>
 
                @param  flags
@@ -180,7 +206,7 @@ abstract public class       DNSSD
                <P>
                @param  ifIndex
                                        The interface on which to resolve the service.  The client should
                <P>
                @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.
                <P>
                                        the ifIndex passed to the serviceFound() callback)
                                        or 0 to resolve the named service on all available interfaces.
                <P>
@@ -188,8 +214,8 @@ abstract public class       DNSSD
                                        The servicename to be resolved.
                <P>
                @param  regType
                                        The servicename to be resolved.
                <P>
                @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".
                <P>
                @param  domain
                                        The domain on which the service is registered, i.e. the domain passed
                <P>
                @param  domain
                                        The domain on which the service is registered, i.e. the domain passed
@@ -203,54 +229,54 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @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); }
 
                                                                                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.<P> 
+       /** Register a service, to be discovered via browse() and resolve() calls.<P>
                @param  flags
                                        Possible values are: NO_AUTO_RENAME.
                <P>
                @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()
                @param  flags
                                        Possible values are: NO_AUTO_RENAME.
                <P>
                @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).
                <P>
                @param  serviceName
                                        machine (service will not be visible to remote hosts).
                <P>
                @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).
                <P>
                @param  regType
                                        the serviceRegistered() callback).
                <P>
                @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".
                <P>
                @param  domain
                                        If non-null, specifies the domain on which to advertise the service.
                <P>
                @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).
                <P>
                @param  host
                                        If non-null, specifies the SRV target host name.  Most applications
                                        will not specify a host, instead automatically using the machine's
                                        registering in the default domain(s).
                <P>
                @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}.
                <P>
                @param  port
                                        for ensuring that the appropriate address record exists, or creating it
                                        via {@link DNSSDRegistration#addRecord}.
                <P>
                @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.
                <P>
                @param  txtRecord
                                        register that same name.)  Most clients will not use placeholder services.
                <P>
                @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. &lt;length byte&gt; &lt;data&gt; 
+                                       The txt record rdata.  May be null.  Note that a non-null txtRecord
+                                       MUST be a properly formatted DNS TXT record, i.e. &lt;length byte&gt; &lt;data&gt;
                                        &lt;length byte&gt; &lt;data&gt; ...
                <P>
                @param  listener
                                        &lt;length byte&gt; &lt;data&gt; ...
                <P>
                @param  listener
@@ -261,26 +287,26 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @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); }
 
                                                                        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.<P> 
+       /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
                @param  serviceName
                @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).
                <P>
                @param  regType
                                        the serviceRegistered() callback).
                <P>
                @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".
                <P>
                @param  port
                <P>
                @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.
                <P>
                @param  listener
                                        register that same name.)  Most clients will not use placeholder services.
                <P>
                @param  listener
@@ -295,14 +321,26 @@ abstract public class     DNSSD
        throws DNSSDException
        { return register( 0, 0, serviceName, regType, null, null, port, null, listener); }
 
        throws DNSSDException
        { return register( 0, 0, serviceName, regType, null, null, port, null, listener); }
 
-       /** Query for an arbitrary DNS record.<P> 
+       /** Create a {@link DNSSDRecordRegistrar} allowing efficient registration of
+               multiple individual records.<P>
+               <P>
+               @return         A {@link DNSSDRecordRegistrar} that can be used to register records.
+
+               @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
+               @see    RuntimePermission
+       */
+       public static DNSSDRecordRegistrar      createRecordRegistrar( RegisterRecordListener listener)
+       throws DNSSDException
+       { return getInstance()._createRecordRegistrar( listener); }
+
+       /** Query for an arbitrary DNS record.<P>
                @param  flags
                                        Possible values are: MORE_COMING.
                <P>
                @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()
                @param  flags
                                        Possible values are: MORE_COMING.
                <P>
                @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.
                <P>
                                        interfaces.  Passing -1 causes the name to be queried for only on the
                                        local host.
                <P>
@@ -314,7 +352,7 @@ abstract public class       DNSSD
                                        as defined in nameser.h.
                <P>
                @param  rrclass
                                        as defined in nameser.h.
                <P>
                @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).
                <P>
                @param  listener
                                        (usually 1 for the Internet class).
                <P>
                @param  listener
@@ -325,12 +363,12 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @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); }
 
                                                                                int rrclass, QueryListener listener)
        throws DNSSDException
        { return getInstance()._queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, listener); }
 
-       /** Asynchronously enumerate domains available for browsing and registration.<P> 
+       /** Asynchronously enumerate domains available for browsing and registration.<P>
        
                Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
                
        
                Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
                
@@ -342,8 +380,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()
                @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.
                <P>
                @param  listener
                                        This object will get called when domains are found.
                <P>
                @param  listener
                                        This object will get called when domains are found.
@@ -357,15 +395,15 @@ abstract public class     DNSSD
        throws DNSSDException
        { return getInstance()._enumerateDomains( flags, ifIndex, listener); }
 
        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.<P> 
+       /**     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.<P>
                @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").
                <P>
                @param  regType
                @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").
                <P>
                @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").
                <P>
                @param  domain
                                        The domain name, e.g. "apple.com".  Any literal dots or backslashes must be escaped.
                <P>
                @param  domain
                                        The domain name, e.g. "apple.com".  Any literal dots or backslashes must be escaped.
@@ -379,10 +417,10 @@ abstract public class     DNSSD
        throws DNSSDException
        { return getInstance()._constructFullName( serviceName, regType, domain); }
 
        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.) <P> 
+       /** 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.) <P>
                
                
-               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.<P>
                @param  flags
                                        Currently unused, reserved for future use.
                daemons' caches on the network) if the record is determined to be invalid.<P>
                @param  flags
                                        Currently unused, reserved for future use.
@@ -390,7 +428,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()
                @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.
                <P>
                                        interfaces.  Passing -1 causes the name to be reconfirmed only on the
                                        local host.
                <P>
@@ -409,11 +447,11 @@ abstract public class     DNSSD
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @see    RuntimePermission
        */
                @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
                @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); }
 
                                                                                int rrclass, byte[] rdata)
        { getInstance()._reconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); }
 
-       /** Return the canonical name of a particular interface index.<P> 
+       /** Return the canonical name of a particular interface index.<P>
                @param  ifIndex
                                        A valid interface index. Must not be ALL_INTERFACES.
                <P>
                @param  ifIndex
                                        A valid interface index. Must not be ALL_INTERFACES.
                <P>
@@ -425,7 +463,7 @@ abstract public class       DNSSD
        public static String    getNameForIfIndex( int ifIndex)
        { return getInstance()._getNameForIfIndex( ifIndex); }
 
        public static String    getNameForIfIndex( int ifIndex)
        { return getInstance()._getNameForIfIndex( ifIndex); }
 
-       /** Return the index of a named interface.<P> 
+       /** Return the index of a named interface.<P>
                @param  ifName
                                        A valid interface name. An example is java.net.NetworkInterface.getName().
                <P>
                @param  ifName
                                        A valid interface name. An example is java.net.NetworkInterface.getName().
                <P>
@@ -440,26 +478,29 @@ abstract public class     DNSSD
        protected                                               DNSSD() {}      // prevent direct instantiation
 
        /** Return the single instance of 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();
        {
                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 _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;
 
                                                                                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;
 
                                                                        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;
 
                                                                                int rrclass, QueryListener listener)
        throws DNSSDException;
 
@@ -469,7 +510,7 @@ abstract public class       DNSSD
        abstract protected String               _constructFullName( String serviceName, String regType, String domain)
        throws DNSSDException;
 
        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);
                                                                                int rrclass, byte[] rdata);
 
        abstract protected String               _getNameForIfIndex( int ifIndex);
@@ -481,7 +522,7 @@ abstract public class       DNSSD
        static
        {
                try
        static
        {
                try
-               {                       
+               {
                        String name = System.getProperty( "com.apple.dnssd.DNSSD" );
                        if( name == null )
                                name = "com.apple.dnssd.AppleDNSSD";    // Fall back to Apple-provided class.
                        String name = System.getProperty( "com.apple.dnssd.DNSSD" );
                        if( name == null )
                                name = "com.apple.dnssd.AppleDNSSD";    // Fall back to Apple-provided class.
@@ -514,13 +555,26 @@ class     AppleDNSSDException extends DNSSDException
                        "BAD_FLAGS",
                        "UNSUPPORTED",
                        "NOT_INITIALIZED",
                        "BAD_FLAGS",
                        "UNSUPPORTED",
                        "NOT_INITIALIZED",
-                       "",             // there is NO number 6
+                       "NO_CACHE",
                        "ALREADY_REGISTERED",
                        "NAME_CONFLICT",
                        "INVALID",
                        "ALREADY_REGISTERED",
                        "NAME_CONFLICT",
                        "INVALID",
-                       "",             // another MIA
+                       "FIREWALL",
                        "INCOMPATIBLE",
                        "INCOMPATIBLE",
-                       "BAD_INTERFACE_INDEX"
+                       "BAD_INTERFACE_INDEX",
+                       "REFUSED",
+                       "NOSUCHRECORD",
+                       "NOAUTH",
+                       "NOSUCHKEY",
+                       "NATTRAVERSAL",
+                       "DOUBLENAT",
+                       "BADTIME",
+                       "BADSIG",
+                       "BADKEY",
+                       "TRANSIENT",
+                       "SERVICENOTRUNNING",
+                       "NATPORTMAPPINGUNSUPPORTED",
+                       "NATPORTMAPPINGDISABLED"
                };
        
                if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
                };
        
                if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
@@ -541,7 +595,7 @@ class       AppleDNSSD extends DNSSD
        {
                System.loadLibrary( "jdns_sd");
        
        {
                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)
                        throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
 
                if ( libInitResult != DNSSDException.NO_ERROR)
                        throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
@@ -555,22 +609,28 @@ class     AppleDNSSD extends DNSSD
                return new AppleBrowser( flags, ifIndex, regType, domain, client);
        }
 
                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);
        }
 
                                                                                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
        {
                                                                        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);
        }
 
                                                                                ( 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
        {
                                                                                int rrclass, QueryListener client)
        throws DNSSDException
        {
@@ -595,7 +655,7 @@ class       AppleDNSSD extends DNSSD
                return responseHolder[0];
        }
 
                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);
                                                                                int rrclass, byte[] rdata)
        {
                ReconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata);
@@ -614,7 +674,7 @@ class       AppleDNSSD extends DNSSD
 
        protected native int    ConstructName( String serviceName, String regType, String domain, String[] pOut);
 
 
        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);
                                                                                int rrclass, byte[] rdata);
 
        protected native String GetNameForIfIndex( int ifIndex);
@@ -626,29 +686,17 @@ class     AppleDNSSD extends DNSSD
 
 class  AppleService implements DNSSDService, Runnable
 {
 
 class  AppleService implements DNSSDService, Runnable
 {
-       public                                  AppleService()  { fNativeContext = 0; }
+       public                                  AppleService(BaseListener listener)     { fNativeContext = 0; fListener = listener; }
 
        public void                             stop() { this.HaltOperation(); }
 
 
        public void                             stop() { this.HaltOperation(); }
 
-       public void                             finalize() throws Throwable
-       {
-               this.stop();    
-               super.finalize();
-       }
-
-       /* The run() method is used internally to schedule an update from another thread */
-       public void                             run()
-       {
-               this.ProcessResults();
-       }
-
-       /* 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. */
 
        /* Call ProcessResults when data appears on socket descriptor. */
-       protected native void   ProcessResults();
+       protected native int    ProcessResults();
 
 
-       protected native void   HaltOperation();
+       protected synchronized native void HaltOperation();
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
        {
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
        {
@@ -656,78 +704,87 @@ class     AppleService implements DNSSDService, Runnable
                        throw new AppleDNSSDException( rc);
        }
 
                        throw new AppleDNSSDException( rc);
        }
 
-       protected int   /* warning */   fNativeContext;         // Private storage for native side
-}
-
-
-// A ServiceThread calls AppleService.BlockForData() and schedules its client
-// when data appears.
-class  ServiceThread extends Thread
-{
-       public                  ServiceThread( AppleService owner) { fOwner = owner; }
+       protected long  /* warning */   fNativeContext;         // Private storage for native side
 
        public void             run()
        {
 
        public void             run()
        {
-               int             result;
-               
                while ( true )
                {
                while ( true )
                {
-                       result = fOwner.BlockForData( -1);
-                       if ( result == 1)
+                       // 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
+                       // stale ServiceThread accidentally consumes bytes off that new socket we'll get really messed up.
+                       // To guard against that, before calling ProcessResults we check to ensure that our
+                       // fNativeContext has not been deleted, which is a telltale sign that our operation was stopped.
+                       // After calling ProcessResults we check again, because it's extremely common for callback
+                       // functions to stop their own operation and start others. For example, a resolveListener callback
+                       // may well stop the resolve and then start a QueryRecord call to monitor the TXT record.
+                       //
+                       // The remaining risk is that between our checking fNativeContext and calling ProcessResults(),
+                       // some other thread could stop the operation and start a new one using same file descriptor, and
+                       // we wouldn't know. To prevent this, the AppleService object's HaltOperation() routine is declared
+                       // synchronized and we perform our checks synchronized on the AppleService object, which ensures
+                       // that HaltOperation() can't execute while we're doing it. Because Java locks are re-entrant this
+                       // 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();
+                       synchronized (this)
                        {
                        {
-                               fOwner.run();
+                               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
                        }
                        }
-                       else
-                               break;  // terminate thread
                }
        }
 
                }
        }
 
-       protected AppleService  fOwner;
+       protected BaseListener fListener;
 }
 
 
 class  AppleBrowser extends AppleService
 {
 }
 
 
 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
        throws DNSSDException
-       { 
-               fClient = client; 
+       {
+               super(client);
                this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
                if ( !AppleDNSSD.hasAutoCallbacks)
                this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
                if ( !AppleDNSSD.hasAutoCallbacks)
-                       new ServiceThread( this).start();
+                       new Thread(this).start();
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    CreateBrowser( int flags, int ifIndex, String regType, String domain);
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    CreateBrowser( int flags, int ifIndex, String regType, String domain);
-
-       protected BrowseListener        fClient;
 }
 
 class  AppleResolver 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
        throws DNSSDException
-       { 
-               fClient = client; 
+       {
+               super(client);
                this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
                if ( !AppleDNSSD.hasAutoCallbacks)
                this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
                if ( !AppleDNSSD.hasAutoCallbacks)
-                       new ServiceThread( this).start();
+                       new Thread(this).start();
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        }
 
        // 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);
                                                                                        String domain);
-
-       protected ResolveListener       fClient;
 }
 
 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
 class  AppleDNSRecord implements DNSRecord
 {
 }
 
 // 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
        }
 
                fRecord = 0;            // record always starts out empty
        }
 
@@ -743,7 +800,7 @@ class       AppleDNSRecord implements DNSRecord
                this.ThrowOnErr( this.Remove());
        }
 
                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
        protected AppleService  fOwner;
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
@@ -759,14 +816,14 @@ class     AppleDNSRecord implements DNSRecord
 
 class  AppleRegistration extends AppleService implements DNSSDRegistration
 {
 
 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
        throws DNSSDException
-       { 
-               fClient = client; 
+       {
+               super(client);
                this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
                if ( !AppleDNSSD.hasAutoCallbacks)
                this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
                if ( !AppleDNSSD.hasAutoCallbacks)
-                       new ServiceThread( this).start();
+                       new Thread(this).start();
        }
 
        public DNSRecord        addRecord( int flags, int rrType, byte[] rData, int ttl)
        }
 
        public DNSRecord        addRecord( int flags, int rrType, byte[] rData, int ttl)
@@ -775,7 +832,6 @@ class       AppleRegistration extends AppleService implements DNSSDRegistration
                AppleDNSRecord  newRecord = new AppleDNSRecord( this);
 
                this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
                AppleDNSRecord  newRecord = new AppleDNSRecord( this);
 
                this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
-
                return newRecord;
        }
 
                return newRecord;
        }
 
@@ -786,48 +842,71 @@ class     AppleRegistration extends AppleService implements DNSSDRegistration
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        }
 
        // 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);
                                                                                        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();
 
 
-       protected RegisterListener      fClient;
+       // 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
 {
 }
 
 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
        throws DNSSDException
-       { 
-               fClient = client; 
+       {
+               super(client);
                this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
                if ( !AppleDNSSD.hasAutoCallbacks)
                this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
                if ( !AppleDNSSD.hasAutoCallbacks)
-                       new ServiceThread( this).start();
+                       new Thread(this).start();
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    CreateQuery( int flags, int ifIndex, String serviceName, int rrtype, int rrclass);
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    CreateQuery( int flags, int ifIndex, String serviceName, int rrtype, int rrclass);
-
-       protected QueryListener fClient;
 }
 
 class  AppleDomainEnum extends AppleService
 {
 }
 
 class  AppleDomainEnum extends AppleService
 {
-       public                  AppleDomainEnum( int flags, int ifIndex, DomainListener listener) 
+       public                  AppleDomainEnum( int flags, int ifIndex, DomainListener client)
        throws DNSSDException
        throws DNSSDException
-       { 
-               fClient = listener; 
+       {
+               super(client);
                this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
                if ( !AppleDNSSD.hasAutoCallbacks)
                this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
                if ( !AppleDNSSD.hasAutoCallbacks)
-                       new ServiceThread( this).start();
+                       new Thread(this).start();
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    BeginEnum( int flags, int ifIndex);
        }
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    BeginEnum( int flags, int ifIndex);
-
-       protected DomainListener        fClient;
 }
 
 
 }