2  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  23     Change History (most recent first): 
  25 $Log: JNISupport.c,v $ 
  26 Revision 1.9  2004/12/11 03:01:00  rpantos 
  27 <rdar://problem/3907498> Java DNSRecord API should be cleaned up 
  29 Revision 1.8  2004/11/30 23:51:05  cheshire 
  30 Remove double semicolons 
  32 Revision 1.7  2004/11/23 08:12:04  shersche 
  33 Implement if_nametoindex and if_indextoname for Win32 platforms 
  35 Revision 1.6  2004/11/23 03:41:14  cheshire 
  36 Change JNISupport.c to call if_indextoname & if_nametoindex directly. 
  37 (May require some additional glue code to work on Windows.) 
  39 Revision 1.5  2004/11/17 17:07:44  cheshire 
  40 Updated comment about AUTO_CALLBACKS 
  42 Revision 1.4  2004/11/12 03:23:09  rpantos 
  43 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex. 
  45 Revision 1.3  2004/06/18 04:44:17  rpantos 
  46 Adapt to API unification on Windows 
  48 Revision 1.2  2004/05/28 23:34:42  ksekar 
  49 <rdar://problem/3672903>: Java project build errors 
  51 Revision 1.1  2004/04/30 16:29:35  rpantos 
  55         This file contains the platform support for DNSSD and related Java classes. 
  56         It is used to shim through to the underlying <dns_sd.h> API. 
  59 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response 
  60 // callbacks automatically (as in the early Windows prototypes). 
  61 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to 
  62 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.). 
  63 // (Invoking callbacks automatically on a different thread sounds attractive, but while 
  64 // the client gains by not needing to add an event source to its main event loop, it loses 
  65 // by being forced to deal with concurrency and locking, which can be a bigger burden.) 
  66 #ifndef AUTO_CALLBACKS 
  67 #define AUTO_CALLBACKS  0 
  74 #include <sys/types.h> 
  75 #include <sys/select.h> 
  77 #endif // AUTO_CALLBACKS 
  87 static char     *       if_indextoname( DWORD ifIndex
, char * nameBuff
); 
  88 static DWORD    
if_nametoindex( const char * nameStr 
); 
  89 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH 
  91 #include <sys/socket.h> 
  96 #include "DNSSD.java.h" 
  98 // convenience definition  
 100 #define _UNUSED __attribute__ ((unused)) 
 106         kInterfaceVersion 
= 1           // Must match version in .jar file 
 109 typedef struct OpContext        OpContext
; 
 113         DNSServiceRef   ServiceRef
; 
 121 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall. 
 123 JavaVM          
*gJavaVM 
= NULL
; 
 127 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv 
*pEnv
, jclass cls
,  
 130         /* Ensure that caller & interface versions match. */ 
 131         if ( callerVersion 
!= kInterfaceVersion
) 
 132                 return kDNSServiceErr_Incompatible
; 
 138                 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
)) 
 139                         return kDNSServiceErr_BadState
; 
 143         // Set AppleDNSSD.hasAutoCallbacks 
 146                 jboolean        hasAutoC 
= JNI_TRUE
; 
 148                 jboolean        hasAutoC 
= JNI_FALSE
; 
 150                 jfieldID        hasAutoCField 
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z"); 
 151                 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
); 
 154         return kDNSServiceErr_NoError
; 
 158 static const char*      SafeGetUTFChars( JNIEnv 
*pEnv
, jstring str
) 
 159 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str. 
 161         return str 
!= NULL 
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
; 
 164 static void                     SafeReleaseUTFChars( JNIEnv 
*pEnv
, jstring str
, const char *buff
) 
 165 // Wrapper for JNI GetStringUTFChars() that handles null str. 
 168                 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
); 
 173 static void     SetupCallbackState( JNIEnv 
**ppEnv
) 
 175         (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
); 
 178 static void     TeardownCallbackState( void ) 
 180         (*gJavaVM
)->DetachCurrentThread( gJavaVM
); 
 183 #else   // AUTO_CALLBACKS 
 185 static void     SetupCallbackState( JNIEnv 
**ppEnv _UNUSED
) 
 187         // No setup necessary if ProcessResults() has been called 
 190 static void     TeardownCallbackState( void ) 
 192         // No teardown necessary if ProcessResults() has been called 
 194 #endif  // AUTO_CALLBACKS 
 197 static OpContext        
*NewContext( JNIEnv 
*pEnv
, jobject owner
, const char *ownerClass
, 
 198                                                                 const char *callbackName
, const char *callbackSig
) 
 199 // Create and initialize a new OpContext. 
 201         OpContext                               
*pContext 
= (OpContext
*) malloc( sizeof *pContext
); 
 203         if ( pContext 
!= NULL
) 
 205                 jfieldID                clientField 
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),  
 206                                                                                                                         "fClient", ownerClass
); 
 208                 pContext
->JavaObj 
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
);    // must convert local ref to global to cache; 
 209                 pContext
->ClientObj 
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
); 
 210                 pContext
->ClientObj 
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
);    // must convert local ref to global to cache 
 211                 pContext
->Callback 
= (*pEnv
)->GetMethodID( pEnv
,  
 212                                                                 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),  
 213                                                                 callbackName
, callbackSig
); 
 214                 pContext
->Callback2 
= NULL
;             // not always used 
 221 static void                     ReportError( JNIEnv 
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
) 
 222 // Invoke operationFailed() method on target with err. 
 224         jclass                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, target
); 
 225         jmethodID               opFailed 
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",  
 226                                                                 "(Lcom/apple/dnssd/DNSSDService;I)V"); 
 228         (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
); 
 231 JNIEXPORT 
void JNICALL 
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv 
*pEnv
, jobject pThis
) 
 232 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */ 
 234         jclass                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 235         jfieldID                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 237         if ( contextField 
!= 0) 
 239                 OpContext       
*pContext 
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
); 
 240                 if ( pContext 
!= NULL
) 
 242                         (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, 0); 
 243                         if ( pContext
->ServiceRef 
!= NULL
) 
 244                                 DNSServiceRefDeallocate( pContext
->ServiceRef
); 
 246                         (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
); 
 247                         (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
); 
 254 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv 
*pEnv
, jobject pThis
, jint msTimeout
) 
 255 /* Block for timeout ms (or forever if -1). Returns 1 if data present, 0 if timed out, -1 if not browsing. */ 
 258         return -1;                              // BlockForData() not supported with AUTO_CALLBACKS  
 259 #else // AUTO_CALLBACKS 
 260         jclass                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 261         jfieldID                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 264         if ( contextField 
!= 0) 
 266                 OpContext       
*pContext 
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
); 
 267                 if ( pContext 
!= NULL
) 
 270                         int                             sd 
= DNSServiceRefSockFD( pContext
->ServiceRef
); 
 271                         struct timeval  timeout 
= { msTimeout 
/ 1000, 10 * (msTimeout 
% 1000) }; 
 272                         struct timeval  
*pTimeout 
= msTimeout 
== -1 ? NULL 
: &timeout
; 
 275                         FD_SET( sd
, &readFDs
); 
 277                         rc 
= select( sd 
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, pTimeout
); 
 282 #endif // AUTO_CALLBACKS 
 286 JNIEXPORT 
void JNICALL 
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv 
*pEnv
, jobject pThis
) 
 287 /* Call through to DNSServiceProcessResult() while data remains on socket. */ 
 289 #if !AUTO_CALLBACKS     // ProcessResults() not supported with AUTO_CALLBACKS  
 291         jclass                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 292         jfieldID                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 293         OpContext               
*pContext 
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
); 
 295         if ( pContext 
!= NULL
) 
 297                 int                             sd 
= DNSServiceRefSockFD( pContext
->ServiceRef
); 
 299                 struct timeval  zeroTimeout 
= { 0, 0 }; 
 301                 pContext
->Env 
= pEnv
; 
 304                 FD_SET( sd
, &readFDs
); 
 306                 while ( 0 < select( sd 
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
)) 
 308                         DNSServiceProcessResult( pContext
->ServiceRef
); 
 311 #endif // AUTO_CALLBACKS 
 315 static void DNSSD_API   
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,  
 316                                                                 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,  
 317                                                                 const char *replyDomain
, void *context
) 
 319         OpContext               
*pContext 
= (OpContext
*) context
; 
 321         SetupCallbackState( &pContext
->Env
); 
 323         if ( pContext
->ClientObj 
!= NULL 
&& pContext
->Callback 
!= NULL
) 
 325                 if ( errorCode 
== kDNSServiceErr_NoError
) 
 327                         (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,  
 328                                                                 ( flags 
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback 
: pContext
->Callback2
,  
 329                                                                 pContext
->JavaObj
, flags
, interfaceIndex
,  
 330                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
), 
 331                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
), 
 332                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
)); 
 335                         ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
); 
 338         TeardownCallbackState(); 
 341 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv 
*pEnv
, jobject pThis
,  
 342                                                         jint flags
, jint ifIndex
, jstring regType
, jstring domain
) 
 344         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 345         jfieldID                                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 346         OpContext                               
*pContext 
= NULL
; 
 347         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 349         if ( contextField 
!= 0) 
 350                 pContext 
= NewContext( pEnv
, pThis
, "Lcom/apple/dnssd/BrowseListener;", "serviceFound",  
 351                                                                 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 
 353                 err 
= kDNSServiceErr_BadParam
; 
 355         if ( pContext 
!= NULL
) 
 357                 const char      *regStr 
= SafeGetUTFChars( pEnv
, regType
); 
 358                 const char      *domainStr 
= SafeGetUTFChars( pEnv
, domain
); 
 360                 pContext
->Callback2 
= (*pEnv
)->GetMethodID( pEnv
,  
 361                                                                 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),  
 362                                                                 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 
 364                 err 
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
); 
 365                 if ( err 
== kDNSServiceErr_NoError
) 
 367                         (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
); 
 370                 SafeReleaseUTFChars( pEnv
, regType
, regStr
); 
 371                 SafeReleaseUTFChars( pEnv
, domain
, domainStr
); 
 374                 err 
= kDNSServiceErr_NoMemory
; 
 380 static void DNSSD_API   
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,  
 381                                                                 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,  
 382                                                                 uint16_t port
, uint16_t txtLen
, const char *txtRecord
, void *context
) 
 384         OpContext               
*pContext 
= (OpContext
*) context
; 
 391         SetupCallbackState( &pContext
->Env
); 
 393         txtCls 
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord"); 
 394         txtCtor 
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V"); 
 396         if ( pContext
->ClientObj 
!= NULL 
&& pContext
->Callback 
!= NULL 
&& txtCtor 
!= NULL 
&& 
 397                  NULL 
!= ( txtBytes 
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
))) 
 399                 if ( errorCode 
== kDNSServiceErr_NoError
) 
 401                         // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit 
 402                         // pattern into a number here. 
 403                         port 
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1]; 
 405                         // Initialize txtBytes with contents of txtRecord 
 406                         pBytes 
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
); 
 407                         memcpy( pBytes
, txtRecord
, txtLen
); 
 408                         (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
); 
 410                         // Construct txtObj with txtBytes 
 411                         txtObj 
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
); 
 412                         (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
); 
 414                         (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,  
 415                                                                 pContext
->JavaObj
, flags
, interfaceIndex
,  
 416                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
), 
 417                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
), 
 421                         ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
); 
 424         TeardownCallbackState(); 
 427 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv 
*pEnv
, jobject pThis
,  
 428                                                         jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
) 
 430         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 431         jfieldID                                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 432         OpContext                               
*pContext 
= NULL
; 
 433         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 435         if ( contextField 
!= 0) 
 436                 pContext 
= NewContext( pEnv
, pThis
, "Lcom/apple/dnssd/ResolveListener;", "serviceResolved",  
 437                                                                 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V"); 
 439                 err 
= kDNSServiceErr_BadParam
; 
 441         if ( pContext 
!= NULL
) 
 443                 const char      *servStr 
= SafeGetUTFChars( pEnv
, serviceName
); 
 444                 const char      *regStr 
= SafeGetUTFChars( pEnv
, regType
); 
 445                 const char      *domainStr 
= SafeGetUTFChars( pEnv
, domain
); 
 447                 err 
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,  
 448                                                                 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
); 
 449                 if ( err 
== kDNSServiceErr_NoError
) 
 451                         (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
); 
 454                 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
); 
 455                 SafeReleaseUTFChars( pEnv
, regType
, regStr
); 
 456                 SafeReleaseUTFChars( pEnv
, domain
, domainStr
); 
 459                 err 
= kDNSServiceErr_NoMemory
; 
 465 static void DNSSD_API   
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,  
 466                                                                 DNSServiceErrorType errorCode
, const char *fullname
,  
 467                                                                 const char *regType
, const char *domain
, void *context
) 
 469         OpContext               
*pContext 
= (OpContext
*) context
; 
 471         SetupCallbackState( &pContext
->Env
); 
 473         if ( pContext
->ClientObj 
!= NULL 
&& pContext
->Callback 
!= NULL
) 
 475                 if ( errorCode 
== kDNSServiceErr_NoError
) 
 477                         (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,  
 478                                                                 pContext
->JavaObj
, flags
,  
 479                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
), 
 480                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
), 
 481                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
)); 
 484                         ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
); 
 486         TeardownCallbackState(); 
 489 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv 
*pEnv
, jobject pThis
,  
 490                                                         jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,  
 491                                                         jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
) 
 493         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 494         jfieldID                                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 495         OpContext                               
*pContext 
= NULL
; 
 496         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 500         if ( contextField 
!= 0) 
 501                 pContext 
= NewContext( pEnv
, pThis
, "Lcom/apple/dnssd/RegisterListener;", "serviceRegistered",  
 502                                                                 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 
 504                 err 
= kDNSServiceErr_BadParam
; 
 506         if ( pContext 
!= NULL
) 
 508                 const char      *servStr 
= SafeGetUTFChars( pEnv
, serviceName
); 
 509                 const char      *regStr 
= SafeGetUTFChars( pEnv
, regType
); 
 510                 const char      *domainStr 
= SafeGetUTFChars( pEnv
, domain
); 
 511                 const char      *hostStr 
= SafeGetUTFChars( pEnv
, host
); 
 513                 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a  
 514                 // big-endian number into a 16-bit pattern here. 
 515                 uint16_t        portBits 
= port
; 
 516                 portBits 
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1]; 
 518                 pBytes 
= txtRecord 
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
; 
 519                 numBytes 
= txtRecord 
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0; 
 521                 err 
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,   
 522                                                                 domainStr
, hostStr
, portBits
,  
 523                                                                 numBytes
, pBytes
, ServiceRegisterReply
, pContext
); 
 524                 if ( err 
== kDNSServiceErr_NoError
) 
 526                         (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
); 
 530                         (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0); 
 532                 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
); 
 533                 SafeReleaseUTFChars( pEnv
, regType
, regStr
); 
 534                 SafeReleaseUTFChars( pEnv
, domain
, domainStr
); 
 535                 SafeReleaseUTFChars( pEnv
, host
, hostStr
); 
 538                 err 
= kDNSServiceErr_NoMemory
; 
 543 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv 
*pEnv
, jobject pThis
,  
 544                                                         jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
) 
 546         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 547         jfieldID                                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 548         jclass                                  destCls 
= (*pEnv
)->GetObjectClass( pEnv
, destObj
); 
 549         jfieldID                                recField 
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "I"); 
 550         OpContext                               
*pContext 
= NULL
; 
 551         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 556         if ( contextField 
!= 0) 
 557                 pContext 
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
); 
 558         if ( pContext 
== NULL 
|| pContext
->ServiceRef 
== NULL
) 
 559                 return kDNSServiceErr_BadParam
; 
 561         pBytes 
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
); 
 562         numBytes 
= (*pEnv
)->GetArrayLength( pEnv
, rData
); 
 564         err 
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
); 
 565         if ( err 
== kDNSServiceErr_NoError
) 
 567                 (*pEnv
)->SetIntField( pEnv
, destObj
, recField
, (jint
) recRef
); 
 571                 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0); 
 576 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv 
*pEnv
, jobject pThis
,  
 577                                                                                                                 jint flags
, jbyteArray rData
, jint ttl
) 
 579         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 580         jfieldID                                ownerField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;"); 
 581         jfieldID                                recField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I"); 
 582         OpContext                               
*pContext 
= NULL
; 
 583         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 586         DNSRecordRef                    recRef 
= NULL
; 
 588         if ( ownerField 
!= 0) 
 590                 jobject         ownerObj 
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
); 
 591                 jclass          ownerClass 
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
); 
 592                 jfieldID        contextField 
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I"); 
 593                 if ( contextField 
!= 0) 
 594                         pContext 
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
); 
 597                 recRef 
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
); 
 598         if ( pContext 
== NULL 
|| pContext
->ServiceRef 
== NULL
) 
 599                 return kDNSServiceErr_BadParam
; 
 601         pBytes 
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
); 
 602         numBytes 
= (*pEnv
)->GetArrayLength( pEnv
, rData
); 
 604         err 
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
); 
 607                 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0); 
 612 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv 
*pEnv
, jobject pThis
) 
 614         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 615         jfieldID                                ownerField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;"); 
 616         jfieldID                                recField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I"); 
 617         OpContext                               
*pContext 
= NULL
; 
 618         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 619         DNSRecordRef                    recRef 
= NULL
; 
 621         if ( ownerField 
!= 0) 
 623                 jobject         ownerObj 
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
); 
 624                 jclass          ownerClass 
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
); 
 625                 jfieldID        contextField 
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I"); 
 626                 if ( contextField 
!= 0) 
 627                         pContext 
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
); 
 630                 recRef 
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
); 
 631         if ( pContext 
== NULL 
|| pContext
->ServiceRef 
== NULL
) 
 632                 return kDNSServiceErr_BadParam
; 
 634         err 
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0); 
 640 static void DNSSD_API   
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,  
 641                                                                 DNSServiceErrorType errorCode
, const char *serviceName
, 
 642                                                                 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
, 
 643                                                                 const void *rdata
, uint32_t ttl
, void *context
) 
 645         OpContext               
*pContext 
= (OpContext
*) context
; 
 649         SetupCallbackState( &pContext
->Env
); 
 651         if ( pContext
->ClientObj 
!= NULL 
&& pContext
->Callback 
!= NULL 
&&  
 652                  NULL 
!= ( rDataObj 
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
))) 
 654                 if ( errorCode 
== kDNSServiceErr_NoError
) 
 656                         // Initialize rDataObj with contents of rdata 
 657                         pBytes 
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
); 
 658                         memcpy( pBytes
, rdata
, rdlen
); 
 659                         (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
); 
 661                         (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,  
 662                                                                 pContext
->JavaObj
, flags
, interfaceIndex
,  
 663                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
), 
 664                                                                 rrtype
, rrclass
, rDataObj
, ttl
); 
 667                         ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
); 
 669         TeardownCallbackState(); 
 672 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv 
*pEnv
, jobject pThis
,  
 673                                                         jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
) 
 675         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 676         jfieldID                                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 677         OpContext                               
*pContext 
= NULL
; 
 678         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 680         if ( contextField 
!= 0) 
 681                 pContext 
= NewContext( pEnv
, pThis
, "Lcom/apple/dnssd/QueryListener;", "queryAnswered",  
 682                                                                 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V"); 
 684                 err 
= kDNSServiceErr_BadParam
; 
 686         if ( pContext 
!= NULL
) 
 688                 const char      *servStr 
= SafeGetUTFChars( pEnv
, serviceName
); 
 690                 err 
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,  
 691                                                                         rrtype
, rrclass
, ServiceQueryReply
, pContext
); 
 692                 if ( err 
== kDNSServiceErr_NoError
) 
 694                         (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
); 
 697                 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
); 
 700                 err 
= kDNSServiceErr_NoMemory
; 
 706 static void DNSSD_API   
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,  
 707                                                                 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
) 
 709         OpContext               
*pContext 
= (OpContext
*) context
; 
 711         SetupCallbackState( &pContext
->Env
); 
 713         if ( pContext
->ClientObj 
!= NULL 
&& pContext
->Callback 
!= NULL
) 
 715                 if ( errorCode 
== kDNSServiceErr_NoError
) 
 717                         (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,  
 718                                                                 ( flags 
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback 
: pContext
->Callback2
,  
 719                                                                 pContext
->JavaObj
, flags
, interfaceIndex
,  
 720                                                                 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
)); 
 723                         ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
); 
 725         TeardownCallbackState(); 
 728 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv 
*pEnv
, jobject pThis
,  
 729                                                         jint flags
, jint ifIndex
) 
 731         jclass                                  cls 
= (*pEnv
)->GetObjectClass( pEnv
, pThis
); 
 732         jfieldID                                contextField 
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I"); 
 733         OpContext                               
*pContext 
= NULL
; 
 734         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 736         if ( contextField 
!= 0) 
 737                 pContext 
= NewContext( pEnv
, pThis
, "Lcom/apple/dnssd/DomainListener;", "domainFound",  
 738                                                                 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V"); 
 740                 err 
= kDNSServiceErr_BadParam
; 
 742         if ( pContext 
!= NULL
) 
 744                 pContext
->Callback2 
= (*pEnv
)->GetMethodID( pEnv
,  
 745                                                                 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),  
 746                                                                 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V"); 
 748                 err 
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,  
 749                                                                                         DomainEnumReply
, pContext
); 
 750                 if ( err 
== kDNSServiceErr_NoError
) 
 752                         (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
); 
 756                 err 
= kDNSServiceErr_NoMemory
; 
 762 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv 
*pEnv
, jobject pThis _UNUSED
,  
 763                                                         jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
) 
 765         DNSServiceErrorType             err 
= kDNSServiceErr_NoError
; 
 766         const char                              *nameStr 
= SafeGetUTFChars( pEnv
, serviceName
); 
 767         const char                              *regStr 
= SafeGetUTFChars( pEnv
, regtype
); 
 768         const char                              *domStr 
= SafeGetUTFChars( pEnv
, domain
); 
 769         char                                    buff
[ kDNSServiceMaxDomainName 
+ 1]; 
 771         err 
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
); 
 773         if ( err 
== kDNSServiceErr_NoError
) 
 775                 // pOut is expected to be a String[1] array. 
 776                 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
)); 
 779         SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
); 
 780         SafeReleaseUTFChars( pEnv
, regtype
, regStr
); 
 781         SafeReleaseUTFChars( pEnv
, domain
, domStr
); 
 786 JNIEXPORT 
void JNICALL 
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv 
*pEnv
, jobject pThis _UNUSED
,  
 787                                                         jint flags
, jint ifIndex
, jstring fullName
,  
 788                                                         jint rrtype
, jint rrclass
, jbyteArray rdata
) 
 792         const char                              *nameStr 
= SafeGetUTFChars( pEnv
, fullName
); 
 794         pBytes 
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
); 
 795         numBytes 
= (*pEnv
)->GetArrayLength( pEnv
, rdata
); 
 797         DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
); 
 800                 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0); 
 802         SafeReleaseUTFChars( pEnv
, fullName
, nameStr
); 
 805 #define LOCAL_ONLY_NAME "loo" 
 807 JNIEXPORT jstring JNICALL 
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv 
*pEnv
, jobject pThis _UNUSED
,  
 810         char                                    *p 
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
]; 
 812         if (ifIndex 
!= kDNSServiceInterfaceIndexLocalOnly
) 
 813                 p 
= if_indextoname( ifIndex
, nameBuff 
); 
 815         return (*pEnv
)->NewStringUTF( pEnv
, p
); 
 819 JNIEXPORT jint JNICALL 
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv 
*pEnv
, jobject pThis _UNUSED
,  
 822         uint32_t                                ifIndex 
= kDNSServiceInterfaceIndexLocalOnly
; 
 823         const char                              *nameStr 
= SafeGetUTFChars( pEnv
, ifName
); 
 825         if (strcmp(nameStr
, LOCAL_ONLY_NAME
)) 
 826                 ifIndex 
= if_nametoindex( nameStr
); 
 828         SafeReleaseUTFChars( pEnv
, ifName
, nameStr
); 
 836 if_indextoname( DWORD ifIndex
, char * nameBuff
) 
 838         PIP_ADAPTER_INFO        pAdapterInfo 
= NULL
; 
 839         PIP_ADAPTER_INFO        pAdapter 
= NULL
; 
 841         char                    *       ifName 
= NULL
; 
 842         ULONG                           ulOutBufLen 
= 0; 
 844         if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
) 
 849         pAdapterInfo 
= (IP_ADAPTER_INFO 
*) malloc(ulOutBufLen
);  
 851         if (pAdapterInfo 
== NULL
) 
 856         dwRetVal 
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen 
); 
 858         if (dwRetVal 
!= NO_ERROR
) 
 863         pAdapter 
= pAdapterInfo
; 
 866                 if (pAdapter
->Index 
== ifIndex
) 
 868                         // It would be better if we passed in the length of nameBuff to this 
 869                         // function, so we would have absolute certainty that no buffer 
 870                         // overflows would occur.  Buffer overflows *shouldn't* occur because 
 871                         // nameBuff is of size MAX_ADAPTER_NAME_LENGTH. 
 872                         strcpy( nameBuff
, pAdapter
->AdapterName 
); 
 877                 pAdapter 
= pAdapter
->Next
; 
 882         if (pAdapterInfo 
!= NULL
) 
 884                 free( pAdapterInfo 
); 
 893 if_nametoindex( const char * nameStr 
) 
 895         PIP_ADAPTER_INFO        pAdapterInfo 
= NULL
; 
 896         PIP_ADAPTER_INFO        pAdapter 
= NULL
; 
 899         ULONG                           ulOutBufLen 
= 0; 
 901         if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
) 
 906         pAdapterInfo 
= (IP_ADAPTER_INFO 
*) malloc(ulOutBufLen
);  
 908         if (pAdapterInfo 
== NULL
) 
 913         dwRetVal 
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen 
); 
 915         if (dwRetVal 
!= NO_ERROR
) 
 920         pAdapter 
= pAdapterInfo
; 
 923                 if (strcmp(pAdapter
->AdapterName
, nameStr
) == 0) 
 925                         ifIndex 
= pAdapter
->Index
; 
 929                 pAdapter 
= pAdapter
->Next
; 
 934         if (pAdapterInfo 
!= NULL
) 
 936                 free( pAdapterInfo 
);