]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSShared/Java/DNSSD.java
mDNSResponder-108.4.tar.gz
[apple/mdnsresponder.git] / mDNSShared / Java / DNSSD.java
index 79cb5c703a10bd288694d051b669b398ae069365..50d29e411e7e2722ef69255afa867780652ffe4d 100644 (file)
@@ -3,8 +3,6 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
- * 
  * 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
     Change History (most recent first):
 
 $Log: DNSSD.java,v $
+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.3  2004/11/12 03:23:08  rpantos
+rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
+
 Revision 1.2  2004/05/20 17:43:18  cheshire
 Fix invalid UTF-8 characters in file
 
@@ -510,13 +529,23 @@ class     AppleDNSSDException extends DNSSDException
                        "BAD_FLAGS",
                        "UNSUPPORTED",
                        "NOT_INITIALIZED",
-                       "",             // there is NO number 6
+                       "NO_CACHE",
                        "ALREADY_REGISTERED",
                        "NAME_CONFLICT",
                        "INVALID",
-                       "",             // another MIA
+                       "FIREWALL",
                        "INCOMPATIBLE",
-                       "BAD_INTERFACE_INDEX"
+                       "BAD_INTERFACE_INDEX",
+                       "REFUSED",
+                       "NOSUCHRECORD",
+                       "NOAUTH",
+                       "NOSUCHKEY",
+                       "NATTRAVERSAL",
+                       "DOUBLENAT",
+                       "BADTIME",
+                       "BADSIG",
+                       "BADKEY",
+                       "TRANSIENT"
                };
        
                if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
@@ -599,12 +628,12 @@ class     AppleDNSSD extends DNSSD
 
        protected String                        _getNameForIfIndex( int ifIndex)
        {
-               return null;            // ••Fix me - RNP
+               return GetNameForIfIndex( ifIndex);
        }
 
        protected int                           _getIfIndexForName( String ifName)
        {
-               return 0;               // ••Fix me - RNP
+               return GetIfIndexForName( ifName);
        }
 
 
@@ -613,34 +642,26 @@ class     AppleDNSSD extends DNSSD
        protected native void   ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype, 
                                                                                int rrclass, byte[] rdata);
 
+       protected native String GetNameForIfIndex( int ifIndex);
+
+       protected native int    GetIfIndexForName( String ifName);
+
        protected static native int     InitLibrary( int callerVersion);
 }
 
 class  AppleService implements DNSSDService, Runnable
 {
-       public                                  AppleService()  { fNativeContext = 0; }
+       public                                  AppleService(BaseListener listener)     { fNativeContext = 0; fListener = listener; }
 
        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. */
-       protected native void   ProcessResults();
+       protected native int    ProcessResults();
 
-       protected native void   HaltOperation();
+       protected synchronized native void HaltOperation();
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
        {
@@ -649,32 +670,45 @@ class     AppleService implements DNSSDService, Runnable
        }
 
        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; }
 
        public void             run()
        {
-               int             result;
-               
                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;
 }
 
 
@@ -683,16 +717,14 @@ class     AppleBrowser extends AppleService
        public                  AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client) 
        throws DNSSDException
        { 
-               fClient = client; 
+               super(client);
                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);
-
-       protected BrowseListener        fClient;
 }
 
 class  AppleResolver extends AppleService
@@ -701,23 +733,50 @@ class     AppleResolver extends AppleService
                                                                        String domain, ResolveListener client) 
        throws DNSSDException
        { 
-               fClient = client
+               super(client)
                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.
        protected native int    CreateResolver( int flags, int ifIndex, String serviceName, String regType, 
                                                                                        String domain);
-
-       protected ResolveListener       fClient;
 }
 
 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
-class  AppleDNSRecord extends DNSRecord
+class  AppleDNSRecord implements DNSRecord
 {
-       public int              fRecord;                // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
+       public                  AppleDNSRecord( AppleService owner) 
+       { 
+               fOwner = owner; 
+               fRecord = 0;            // record always starts out empty
+       }
+
+       public void                     update( int flags, byte[] rData, int ttl)
+       throws DNSSDException
+       {
+               this.ThrowOnErr( this.Update( flags, rData, ttl));
+       }
+
+       public void                     remove()
+       throws DNSSDException
+       {
+               this.ThrowOnErr( this.Remove());
+       }
+
+       protected int                   fRecord;                // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
+       protected AppleService  fOwner;
+
+       protected void                  ThrowOnErr( int rc) throws DNSSDException
+       {
+               if ( rc != 0)
+                       throw new AppleDNSSDException( rc);
+       }
+
+       protected native int    Update( int flags, byte[] rData, int ttl);
+
+       protected native int    Remove();
 }
 
 class  AppleRegistration extends AppleService implements DNSSDRegistration
@@ -726,32 +785,26 @@ class     AppleRegistration extends AppleService implements DNSSDRegistration
                                                                String host, int port, byte[] txtRecord, RegisterListener client) 
        throws DNSSDException
        { 
-               fClient = client
+               super(client)
                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)
        throws DNSSDException
        {
-               AppleDNSRecord  newRecord = new AppleDNSRecord();
+               AppleDNSRecord  newRecord = new AppleDNSRecord( this);
 
                this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
 
                return newRecord;
        }
 
-       public void                     updateRecord( DNSRecord record, int flags, byte[] rData, int ttl)
+       public DNSRecord        getTXTRecord()
        throws DNSSDException
        {
-               this.ThrowOnErr( this.UpdateRecord( (AppleDNSRecord) record, flags, rData, ttl));
-       }
-
-       public void                     removeRecord( DNSRecord record, int flags)
-       throws DNSSDException
-       {
-               this.ThrowOnErr( this.RemoveRecord( (AppleDNSRecord) record, flags));
+               return new AppleDNSRecord( this);       // A record with ref 0 is understood to be primary TXT record
        }
 
        // Sets fNativeContext. Returns non-zero on error.
@@ -760,12 +813,6 @@ class      AppleRegistration extends AppleService implements DNSSDRegistration
 
        // Sets fNativeContext. Returns non-zero on error.
        protected native int    AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj);
-
-       protected native int    UpdateRecord( AppleDNSRecord destObj, int flags, byte[] rData, int ttl);
-
-       protected native int    RemoveRecord( AppleDNSRecord destObj, int flags);
-
-       protected RegisterListener      fClient;
 }
 
 class  AppleQuery extends AppleService
@@ -774,33 +821,29 @@ class     AppleQuery extends AppleService
                                                                                int rrclass, QueryListener client) 
        throws DNSSDException
        { 
-               fClient = client
+               super(client)
                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);
-
-       protected QueryListener fClient;
 }
 
 class  AppleDomainEnum extends AppleService
 {
-       public                  AppleDomainEnum( int flags, int ifIndex, DomainListener listener
+       public                  AppleDomainEnum( int flags, int ifIndex, DomainListener client
        throws DNSSDException
        { 
-               fClient = listener
+               super(client)
                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);
-
-       protected DomainListener        fClient;
 }