]> 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 50d29e411e7e2722ef69255afa867780652ffe4d..e608869f8618b47239f317e0f3cd74ee6eab73c6 100644 (file)
@@ -1,28 +1,43 @@
-/*
+/* -*- 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.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)
 
@@ -54,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.
-
-       To do:
-       - implement network interface mappings
-       - RegisterRecord
  */
 
 
@@ -68,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
-       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>
 
-       For example, in this program<P> 
+       For example, in this program<P>
        <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) {}
-        ... 
+        ...
     }</CODE></PRE>
        <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
        default browse domain(s).
@@ -92,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.
-       */ 
+       */
        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 );
@@ -118,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     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;
@@ -126,7 +137,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.<P> 
+       /** Browse for instances of a service.<P>
 
                Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
 
@@ -140,12 +151,12 @@ abstract public class     DNSSD
                                        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.
-                                       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
@@ -160,10 +171,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.<P> 
+       /** Browse for instances of a service. Use default flags, ifIndex and domain.<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  listener
@@ -178,16 +189,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.<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>
                
-               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
-               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
@@ -195,7 +206,7 @@ abstract public class       DNSSD
                <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>
@@ -203,8 +214,8 @@ abstract public class       DNSSD
                                        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
@@ -218,54 +229,54 @@ abstract public class     DNSSD
                @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); }
 
-       /** 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()
-                                       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
-                                       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 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.
-                                       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
-                                       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
-                                       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
-                                       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
@@ -276,26 +287,26 @@ abstract public class     DNSSD
                @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); }
 
-       /** 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
-                                       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 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
-                                       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
@@ -310,14 +321,26 @@ abstract public class     DNSSD
        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()
-                                       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>
@@ -329,7 +352,7 @@ abstract public class       DNSSD
                                        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
@@ -340,12 +363,12 @@ abstract public class     DNSSD
                @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); }
 
-       /** 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>
                
@@ -357,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()
-                                       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.
@@ -372,15 +395,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.<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
-                                       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.
@@ -394,10 +417,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.) <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.
@@ -405,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()
-                                       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>
@@ -424,11 +447,11 @@ abstract public class     DNSSD
                @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); }
 
-       /** 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>
@@ -440,7 +463,7 @@ abstract public class       DNSSD
        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>
@@ -455,26 +478,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;
 
@@ -484,7 +510,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);
@@ -496,7 +522,7 @@ abstract public class       DNSSD
        static
        {
                try
-               {                       
+               {
                        String name = System.getProperty( "com.apple.dnssd.DNSSD" );
                        if( name == null )
                                name = "com.apple.dnssd.AppleDNSSD";    // Fall back to Apple-provided class.
@@ -545,7 +571,10 @@ class      AppleDNSSDException extends DNSSDException
                        "BADTIME",
                        "BADSIG",
                        "BADKEY",
-                       "TRANSIENT"
+                       "TRANSIENT",
+                       "SERVICENOTRUNNING",
+                       "NATPORTMAPPINGUNSUPPORTED",
+                       "NATPORTMAPPINGDISABLED"
                };
        
                if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
@@ -566,7 +595,7 @@ 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)
                        throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
@@ -580,22 +609,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
        {
@@ -620,7 +655,7 @@ class       AppleDNSSD extends DNSSD
                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);
@@ -639,7 +674,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);
@@ -669,7 +704,7 @@ class       AppleService implements DNSSDService, Runnable
                        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()
        {
@@ -714,9 +749,9 @@ 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)
@@ -729,27 +764,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)
                        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
        }
 
@@ -765,7 +800,7 @@ 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
@@ -781,11 +816,11 @@ 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)
                        new Thread(this).start();
@@ -797,7 +832,6 @@ class       AppleRegistration extends AppleService implements DNSSDRegistration
                AppleDNSRecord  newRecord = new AppleDNSRecord( this);
 
                this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
-
                return newRecord;
        }
 
@@ -808,20 +842,49 @@ 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)
                        new Thread(this).start();
@@ -833,10 +896,10 @@ 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)
                        new Thread(this).start();