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.13 2005/10/26 01:52:24 cheshire
27 <rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
29 Revision 1.12 2005/07/13 19:20:32 cheshire
30 <rdar://problem/4175511> Race condition in Java API
31 Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
33 Revision 1.11 2005/07/11 01:55:21 cheshire
34 <rdar://problem/4175511> Race condition in Java API
36 Revision 1.10 2005/07/05 13:01:52 cheshire
37 <rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
39 Revision 1.9 2004/12/11 03:01:00 rpantos
40 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
42 Revision 1.8 2004/11/30 23:51:05 cheshire
43 Remove double semicolons
45 Revision 1.7 2004/11/23 08:12:04 shersche
46 Implement if_nametoindex and if_indextoname for Win32 platforms
48 Revision 1.6 2004/11/23 03:41:14 cheshire
49 Change JNISupport.c to call if_indextoname & if_nametoindex directly.
50 (May require some additional glue code to work on Windows.)
52 Revision 1.5 2004/11/17 17:07:44 cheshire
53 Updated comment about AUTO_CALLBACKS
55 Revision 1.4 2004/11/12 03:23:09 rpantos
56 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
58 Revision 1.3 2004/06/18 04:44:17 rpantos
59 Adapt to API unification on Windows
61 Revision 1.2 2004/05/28 23:34:42 ksekar
62 <rdar://problem/3672903>: Java project build errors
64 Revision 1.1 2004/04/30 16:29:35 rpantos
68 This file contains the platform support for DNSSD and related Java classes.
69 It is used to shim through to the underlying <dns_sd.h> API.
72 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
73 // callbacks automatically (as in the early Windows prototypes).
74 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
75 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
76 // (Invoking callbacks automatically on a different thread sounds attractive, but while
77 // the client gains by not needing to add an event source to its main event loop, it loses
78 // by being forced to deal with concurrency and locking, which can be a bigger burden.)
79 #ifndef AUTO_CALLBACKS
80 #define AUTO_CALLBACKS 0
87 #include <sys/types.h>
88 #include <sys/select.h>
90 #endif // AUTO_CALLBACKS
100 static char * if_indextoname( DWORD ifIndex
, char * nameBuff
);
101 static DWORD
if_nametoindex( const char * nameStr
);
102 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
104 #include <sys/socket.h>
109 #include "DNSSD.java.h"
111 // convenience definition
113 #define _UNUSED __attribute__ ((unused))
119 kInterfaceVersion
= 1 // Must match version in .jar file
122 typedef struct OpContext OpContext
;
126 DNSServiceRef ServiceRef
;
134 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
136 JavaVM
*gJavaVM
= NULL
;
140 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv
*pEnv
, jclass cls
,
143 /* Ensure that caller & interface versions match. */
144 if ( callerVersion
!= kInterfaceVersion
)
145 return kDNSServiceErr_Incompatible
;
151 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
))
152 return kDNSServiceErr_BadState
;
156 // Set AppleDNSSD.hasAutoCallbacks
159 jboolean hasAutoC
= JNI_TRUE
;
161 jboolean hasAutoC
= JNI_FALSE
;
163 jfieldID hasAutoCField
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z");
164 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
);
167 return kDNSServiceErr_NoError
;
171 static const char* SafeGetUTFChars( JNIEnv
*pEnv
, jstring str
)
172 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
174 return str
!= NULL
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
;
177 static void SafeReleaseUTFChars( JNIEnv
*pEnv
, jstring str
, const char *buff
)
178 // Wrapper for JNI GetStringUTFChars() that handles null str.
181 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
);
186 static void SetupCallbackState( JNIEnv
**ppEnv
)
188 (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
);
191 static void TeardownCallbackState( void )
193 (*gJavaVM
)->DetachCurrentThread( gJavaVM
);
196 #else // AUTO_CALLBACKS
198 static void SetupCallbackState( JNIEnv
**ppEnv _UNUSED
)
200 // No setup necessary if ProcessResults() has been called
203 static void TeardownCallbackState( void )
205 // No teardown necessary if ProcessResults() has been called
207 #endif // AUTO_CALLBACKS
210 static OpContext
*NewContext( JNIEnv
*pEnv
, jobject owner
,
211 const char *callbackName
, const char *callbackSig
)
212 // Create and initialize a new OpContext.
214 OpContext
*pContext
= (OpContext
*) malloc( sizeof *pContext
);
216 if ( pContext
!= NULL
)
218 jfieldID clientField
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),
219 "fListener", "Lcom/apple/dnssd/BaseListener;");
221 pContext
->JavaObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
); // must convert local ref to global to cache;
222 pContext
->ClientObj
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
);
223 pContext
->ClientObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
); // must convert local ref to global to cache
224 pContext
->Callback
= (*pEnv
)->GetMethodID( pEnv
,
225 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
226 callbackName
, callbackSig
);
227 pContext
->Callback2
= NULL
; // not always used
234 static void ReportError( JNIEnv
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
)
235 // Invoke operationFailed() method on target with err.
237 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, target
);
238 jmethodID opFailed
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",
239 "(Lcom/apple/dnssd/DNSSDService;I)V");
241 (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
);
244 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv
*pEnv
, jobject pThis
)
245 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
247 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
248 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
250 if ( contextField
!= 0)
252 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
253 if ( pContext
!= NULL
)
255 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
256 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, 0);
257 if ( pContext
->ServiceRef
!= NULL
)
258 DNSServiceRefDeallocate( pContext
->ServiceRef
);
260 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
);
261 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
);
268 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv
*pEnv
, jobject pThis
)
269 /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
271 // BlockForData() not supported with AUTO_CALLBACKS
273 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
274 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
276 if ( contextField
!= 0)
278 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
279 if ( pContext
!= NULL
)
282 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
283 struct timeval timeout
= { 1, 0 };
285 FD_SET( sd
, &readFDs
);
287 // Q: Why do we poll here?
288 // A: Because there's no other thread-safe way to do it.
289 // Mac OS X terminates a select() call if you close one of the sockets it's listening on, but Linux does not,
290 // and arguably Linux is correct (See <http://www.ussg.iu.edu/hypermail/linux/kernel/0405.1/0418.html>)
291 // The problem is that the Mac OS X behaviour assumes that it's okay for one thread to close a socket while
292 // some other thread is monitoring that socket in select(), but the difficulty is that there's no general way
293 // to make that thread-safe, because there's no atomic way to enter select() and release a lock simultaneously.
294 // If we try to do this without holding any lock, then right as we jump to the select() routine,
295 // some other thread could stop our operation (thereby closing the socket),
296 // and then that thread (or even some third, unrelated thread)
297 // could do some other DNS-SD operation (or some other operation that opens a new file descriptor)
298 // and then we'd blindly resume our fall into the select() call, now blocking on a file descriptor
299 // that may coincidentally have the same numerical value, but is semantically unrelated
300 // to the true file descriptor we thought we were blocking on.
301 // We can't stop this race condition from happening, but at least if we wake up once a second we can detect
302 // when fNativeContext has gone to zero, and thereby discover that we were blocking on the wrong fd.
304 if (select( sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
) == 1) return(1);
307 #endif // !AUTO_CALLBACKS
312 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
*pEnv
, jobject pThis
)
313 /* Call through to DNSServiceProcessResult() while data remains on socket. */
315 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
317 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
318 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
319 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
320 DNSServiceErrorType err
= kDNSServiceErr_BadState
;
322 if ( pContext
!= NULL
)
324 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
326 struct timeval zeroTimeout
= { 0, 0 };
328 pContext
->Env
= pEnv
;
331 FD_SET( sd
, &readFDs
);
333 err
= kDNSServiceErr_NoError
;
334 if (0 < select(sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
))
336 err
= DNSServiceProcessResult(pContext
->ServiceRef
);
338 // We cannot touch any data structures associated with this operation!
339 // The DNSServiceProcessResult() routine should have invoked our callback,
340 // and our callback could have terminated the operation with op.stop();
341 // and that means HaltOperation() will have been called, which frees pContext.
342 // Basically, from here we just have to get out without touching any stale
343 // data structures that could blow up on us! Particularly, any attempt
344 // to loop here reading more results from the file descriptor is unsafe.
348 #endif // AUTO_CALLBACKS
352 static void DNSSD_API
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
353 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,
354 const char *replyDomain
, void *context
)
356 OpContext
*pContext
= (OpContext
*) context
;
358 SetupCallbackState( &pContext
->Env
);
360 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
362 if ( errorCode
== kDNSServiceErr_NoError
)
364 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
365 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
366 pContext
->JavaObj
, flags
, interfaceIndex
,
367 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
368 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
),
369 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
372 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
375 TeardownCallbackState();
378 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv
*pEnv
, jobject pThis
,
379 jint flags
, jint ifIndex
, jstring regType
, jstring domain
)
381 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
382 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
383 OpContext
*pContext
= NULL
;
384 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
386 if ( contextField
!= 0)
387 pContext
= NewContext( pEnv
, pThis
, "serviceFound",
388 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
390 err
= kDNSServiceErr_BadParam
;
392 if ( pContext
!= NULL
)
394 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
395 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
397 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
398 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
399 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
401 err
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
);
402 if ( err
== kDNSServiceErr_NoError
)
404 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
407 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
408 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
411 err
= kDNSServiceErr_NoMemory
;
417 static void DNSSD_API
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
418 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,
419 uint16_t port
, uint16_t txtLen
, const char *txtRecord
, void *context
)
421 OpContext
*pContext
= (OpContext
*) context
;
428 SetupCallbackState( &pContext
->Env
);
430 txtCls
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord");
431 txtCtor
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V");
433 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&& txtCtor
!= NULL
&&
434 NULL
!= ( txtBytes
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
)))
436 if ( errorCode
== kDNSServiceErr_NoError
)
438 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
439 // pattern into a number here.
440 port
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1];
442 // Initialize txtBytes with contents of txtRecord
443 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
);
444 memcpy( pBytes
, txtRecord
, txtLen
);
445 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
);
447 // Construct txtObj with txtBytes
448 txtObj
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
);
449 (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
);
451 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
452 pContext
->JavaObj
, flags
, interfaceIndex
,
453 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
),
454 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
),
458 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
461 TeardownCallbackState();
464 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
*pEnv
, jobject pThis
,
465 jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
)
467 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
468 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
469 OpContext
*pContext
= NULL
;
470 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
472 if ( contextField
!= 0)
473 pContext
= NewContext( pEnv
, pThis
, "serviceResolved",
474 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
476 err
= kDNSServiceErr_BadParam
;
478 if ( pContext
!= NULL
)
480 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
481 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
482 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
484 err
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,
485 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
);
486 if ( err
== kDNSServiceErr_NoError
)
488 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
491 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
492 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
493 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
496 err
= kDNSServiceErr_NoMemory
;
502 static void DNSSD_API
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,
503 DNSServiceErrorType errorCode
, const char *serviceName
,
504 const char *regType
, const char *domain
, void *context
)
506 OpContext
*pContext
= (OpContext
*) context
;
508 SetupCallbackState( &pContext
->Env
);
510 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
512 if ( errorCode
== kDNSServiceErr_NoError
)
514 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
515 pContext
->JavaObj
, flags
,
516 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
517 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
),
518 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
));
521 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
523 TeardownCallbackState();
526 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv
*pEnv
, jobject pThis
,
527 jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,
528 jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
)
530 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
531 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
532 OpContext
*pContext
= NULL
;
533 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
537 if ( contextField
!= 0)
538 pContext
= NewContext( pEnv
, pThis
, "serviceRegistered",
539 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
541 err
= kDNSServiceErr_BadParam
;
543 if ( pContext
!= NULL
)
545 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
546 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
547 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
548 const char *hostStr
= SafeGetUTFChars( pEnv
, host
);
550 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
551 // big-endian number into a 16-bit pattern here.
552 uint16_t portBits
= port
;
553 portBits
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1];
555 pBytes
= txtRecord
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
;
556 numBytes
= txtRecord
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0;
558 err
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,
559 domainStr
, hostStr
, portBits
,
560 numBytes
, pBytes
, ServiceRegisterReply
, pContext
);
561 if ( err
== kDNSServiceErr_NoError
)
563 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
567 (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0);
569 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
570 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
571 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
572 SafeReleaseUTFChars( pEnv
, host
, hostStr
);
575 err
= kDNSServiceErr_NoMemory
;
580 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
*pEnv
, jobject pThis
,
581 jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
)
583 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
584 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
585 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
586 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "I");
587 OpContext
*pContext
= NULL
;
588 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
593 if ( contextField
!= 0)
594 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
595 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
596 return kDNSServiceErr_BadParam
;
598 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
599 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
601 err
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
);
602 if ( err
== kDNSServiceErr_NoError
)
604 (*pEnv
)->SetIntField( pEnv
, destObj
, recField
, (jint
) recRef
);
608 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
613 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv
*pEnv
, jobject pThis
,
614 jint flags
, jbyteArray rData
, jint ttl
)
616 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
617 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
618 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I");
619 OpContext
*pContext
= NULL
;
620 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
623 DNSRecordRef recRef
= NULL
;
625 if ( ownerField
!= 0)
627 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
628 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
629 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I");
630 if ( contextField
!= 0)
631 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
);
634 recRef
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
);
635 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
636 return kDNSServiceErr_BadParam
;
638 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
639 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
641 err
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
);
644 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
649 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv
*pEnv
, jobject pThis
)
651 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
652 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
653 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I");
654 OpContext
*pContext
= NULL
;
655 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
656 DNSRecordRef recRef
= NULL
;
658 if ( ownerField
!= 0)
660 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
661 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
662 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I");
663 if ( contextField
!= 0)
664 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
);
667 recRef
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
);
668 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
669 return kDNSServiceErr_BadParam
;
671 err
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0);
677 static void DNSSD_API
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
678 DNSServiceErrorType errorCode
, const char *serviceName
,
679 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
,
680 const void *rdata
, uint32_t ttl
, void *context
)
682 OpContext
*pContext
= (OpContext
*) context
;
686 SetupCallbackState( &pContext
->Env
);
688 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&&
689 NULL
!= ( rDataObj
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
)))
691 if ( errorCode
== kDNSServiceErr_NoError
)
693 // Initialize rDataObj with contents of rdata
694 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
);
695 memcpy( pBytes
, rdata
, rdlen
);
696 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
);
698 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
699 pContext
->JavaObj
, flags
, interfaceIndex
,
700 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
701 rrtype
, rrclass
, rDataObj
, ttl
);
704 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
706 TeardownCallbackState();
709 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv
*pEnv
, jobject pThis
,
710 jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
)
712 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
713 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
714 OpContext
*pContext
= NULL
;
715 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
717 if ( contextField
!= 0)
718 pContext
= NewContext( pEnv
, pThis
, "queryAnswered",
719 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
721 err
= kDNSServiceErr_BadParam
;
723 if ( pContext
!= NULL
)
725 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
727 err
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,
728 rrtype
, rrclass
, ServiceQueryReply
, pContext
);
729 if ( err
== kDNSServiceErr_NoError
)
731 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
734 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
737 err
= kDNSServiceErr_NoMemory
;
743 static void DNSSD_API
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
744 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
746 OpContext
*pContext
= (OpContext
*) context
;
748 SetupCallbackState( &pContext
->Env
);
750 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
752 if ( errorCode
== kDNSServiceErr_NoError
)
754 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
755 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
756 pContext
->JavaObj
, flags
, interfaceIndex
,
757 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
760 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
762 TeardownCallbackState();
765 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv
*pEnv
, jobject pThis
,
766 jint flags
, jint ifIndex
)
768 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
769 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
770 OpContext
*pContext
= NULL
;
771 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
773 if ( contextField
!= 0)
774 pContext
= NewContext( pEnv
, pThis
, "domainFound",
775 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
777 err
= kDNSServiceErr_BadParam
;
779 if ( pContext
!= NULL
)
781 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
782 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
783 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
785 err
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,
786 DomainEnumReply
, pContext
);
787 if ( err
== kDNSServiceErr_NoError
)
789 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
793 err
= kDNSServiceErr_NoMemory
;
799 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
800 jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
)
802 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
803 const char *nameStr
= SafeGetUTFChars( pEnv
, serviceName
);
804 const char *regStr
= SafeGetUTFChars( pEnv
, regtype
);
805 const char *domStr
= SafeGetUTFChars( pEnv
, domain
);
806 char buff
[ kDNSServiceMaxDomainName
+ 1];
808 err
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
);
810 if ( err
== kDNSServiceErr_NoError
)
812 // pOut is expected to be a String[1] array.
813 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
));
816 SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
);
817 SafeReleaseUTFChars( pEnv
, regtype
, regStr
);
818 SafeReleaseUTFChars( pEnv
, domain
, domStr
);
823 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
824 jint flags
, jint ifIndex
, jstring fullName
,
825 jint rrtype
, jint rrclass
, jbyteArray rdata
)
829 const char *nameStr
= SafeGetUTFChars( pEnv
, fullName
);
831 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
);
832 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rdata
);
834 DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
);
837 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0);
839 SafeReleaseUTFChars( pEnv
, fullName
, nameStr
);
842 #define LOCAL_ONLY_NAME "loo"
844 JNIEXPORT jstring JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
847 char *p
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
];
849 if (ifIndex
!= kDNSServiceInterfaceIndexLocalOnly
)
850 p
= if_indextoname( ifIndex
, nameBuff
);
852 return (*pEnv
)->NewStringUTF( pEnv
, p
);
856 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
859 uint32_t ifIndex
= kDNSServiceInterfaceIndexLocalOnly
;
860 const char *nameStr
= SafeGetUTFChars( pEnv
, ifName
);
862 if (strcmp(nameStr
, LOCAL_ONLY_NAME
))
863 ifIndex
= if_nametoindex( nameStr
);
865 SafeReleaseUTFChars( pEnv
, ifName
, nameStr
);
873 if_indextoname( DWORD ifIndex
, char * nameBuff
)
875 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
876 PIP_ADAPTER_INFO pAdapter
= NULL
;
878 char * ifName
= NULL
;
879 ULONG ulOutBufLen
= 0;
881 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
886 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
888 if (pAdapterInfo
== NULL
)
893 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
895 if (dwRetVal
!= NO_ERROR
)
900 pAdapter
= pAdapterInfo
;
903 if (pAdapter
->Index
== ifIndex
)
905 // It would be better if we passed in the length of nameBuff to this
906 // function, so we would have absolute certainty that no buffer
907 // overflows would occur. Buffer overflows *shouldn't* occur because
908 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
909 strcpy( nameBuff
, pAdapter
->AdapterName
);
914 pAdapter
= pAdapter
->Next
;
919 if (pAdapterInfo
!= NULL
)
921 free( pAdapterInfo
);
930 if_nametoindex( const char * nameStr
)
932 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
933 PIP_ADAPTER_INFO pAdapter
= NULL
;
936 ULONG ulOutBufLen
= 0;
938 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
943 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
945 if (pAdapterInfo
== NULL
)
950 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
952 if (dwRetVal
!= NO_ERROR
)
957 pAdapter
= pAdapterInfo
;
960 if (strcmp(pAdapter
->AdapterName
, nameStr
) == 0)
962 ifIndex
= pAdapter
->Index
;
966 pAdapter
= pAdapter
->Next
;
971 if (pAdapterInfo
!= NULL
)
973 free( pAdapterInfo
);