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.12 2005/07/13 19:20:32 cheshire
27 <rdar://problem/4175511> Race condition in Java API
28 Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
30 Revision 1.11 2005/07/11 01:55:21 cheshire
31 <rdar://problem/4175511> Race condition in Java API
33 Revision 1.10 2005/07/05 13:01:52 cheshire
34 <rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
36 Revision 1.9 2004/12/11 03:01:00 rpantos
37 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
39 Revision 1.8 2004/11/30 23:51:05 cheshire
40 Remove double semicolons
42 Revision 1.7 2004/11/23 08:12:04 shersche
43 Implement if_nametoindex and if_indextoname for Win32 platforms
45 Revision 1.6 2004/11/23 03:41:14 cheshire
46 Change JNISupport.c to call if_indextoname & if_nametoindex directly.
47 (May require some additional glue code to work on Windows.)
49 Revision 1.5 2004/11/17 17:07:44 cheshire
50 Updated comment about AUTO_CALLBACKS
52 Revision 1.4 2004/11/12 03:23:09 rpantos
53 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
55 Revision 1.3 2004/06/18 04:44:17 rpantos
56 Adapt to API unification on Windows
58 Revision 1.2 2004/05/28 23:34:42 ksekar
59 <rdar://problem/3672903>: Java project build errors
61 Revision 1.1 2004/04/30 16:29:35 rpantos
65 This file contains the platform support for DNSSD and related Java classes.
66 It is used to shim through to the underlying <dns_sd.h> API.
69 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
70 // callbacks automatically (as in the early Windows prototypes).
71 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
72 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
73 // (Invoking callbacks automatically on a different thread sounds attractive, but while
74 // the client gains by not needing to add an event source to its main event loop, it loses
75 // by being forced to deal with concurrency and locking, which can be a bigger burden.)
76 #ifndef AUTO_CALLBACKS
77 #define AUTO_CALLBACKS 0
84 #include <sys/types.h>
85 #include <sys/select.h>
87 #endif // AUTO_CALLBACKS
97 static char * if_indextoname( DWORD ifIndex
, char * nameBuff
);
98 static DWORD
if_nametoindex( const char * nameStr
);
99 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
101 #include <sys/socket.h>
106 #include "DNSSD.java.h"
108 // convenience definition
110 #define _UNUSED __attribute__ ((unused))
116 kInterfaceVersion
= 1 // Must match version in .jar file
119 typedef struct OpContext OpContext
;
123 DNSServiceRef ServiceRef
;
131 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
133 JavaVM
*gJavaVM
= NULL
;
137 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv
*pEnv
, jclass cls
,
140 /* Ensure that caller & interface versions match. */
141 if ( callerVersion
!= kInterfaceVersion
)
142 return kDNSServiceErr_Incompatible
;
148 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
))
149 return kDNSServiceErr_BadState
;
153 // Set AppleDNSSD.hasAutoCallbacks
156 jboolean hasAutoC
= JNI_TRUE
;
158 jboolean hasAutoC
= JNI_FALSE
;
160 jfieldID hasAutoCField
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z");
161 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
);
164 return kDNSServiceErr_NoError
;
168 static const char* SafeGetUTFChars( JNIEnv
*pEnv
, jstring str
)
169 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
171 return str
!= NULL
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
;
174 static void SafeReleaseUTFChars( JNIEnv
*pEnv
, jstring str
, const char *buff
)
175 // Wrapper for JNI GetStringUTFChars() that handles null str.
178 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
);
183 static void SetupCallbackState( JNIEnv
**ppEnv
)
185 (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
);
188 static void TeardownCallbackState( void )
190 (*gJavaVM
)->DetachCurrentThread( gJavaVM
);
193 #else // AUTO_CALLBACKS
195 static void SetupCallbackState( JNIEnv
**ppEnv _UNUSED
)
197 // No setup necessary if ProcessResults() has been called
200 static void TeardownCallbackState( void )
202 // No teardown necessary if ProcessResults() has been called
204 #endif // AUTO_CALLBACKS
207 static OpContext
*NewContext( JNIEnv
*pEnv
, jobject owner
,
208 const char *callbackName
, const char *callbackSig
)
209 // Create and initialize a new OpContext.
211 OpContext
*pContext
= (OpContext
*) malloc( sizeof *pContext
);
213 if ( pContext
!= NULL
)
215 jfieldID clientField
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),
216 "fListener", "Lcom/apple/dnssd/BaseListener;");
218 pContext
->JavaObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
); // must convert local ref to global to cache;
219 pContext
->ClientObj
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
);
220 pContext
->ClientObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
); // must convert local ref to global to cache
221 pContext
->Callback
= (*pEnv
)->GetMethodID( pEnv
,
222 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
223 callbackName
, callbackSig
);
224 pContext
->Callback2
= NULL
; // not always used
231 static void ReportError( JNIEnv
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
)
232 // Invoke operationFailed() method on target with err.
234 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, target
);
235 jmethodID opFailed
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",
236 "(Lcom/apple/dnssd/DNSSDService;I)V");
238 (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
);
241 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv
*pEnv
, jobject pThis
)
242 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
244 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
245 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
247 if ( contextField
!= 0)
249 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
250 if ( pContext
!= NULL
)
252 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
253 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, 0);
254 if ( pContext
->ServiceRef
!= NULL
)
255 DNSServiceRefDeallocate( pContext
->ServiceRef
);
257 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
);
258 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
);
265 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv
*pEnv
, jobject pThis
, jint msTimeout
)
266 /* Block for timeout ms (or forever if -1). Returns 1 if data present, 0 if timed out, -1 if not browsing. */
269 return -1; // BlockForData() not supported with AUTO_CALLBACKS
270 #else // AUTO_CALLBACKS
271 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
272 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
275 if ( contextField
!= 0)
277 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
278 if ( pContext
!= NULL
)
281 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
282 struct timeval timeout
= { msTimeout
/ 1000, 10 * (msTimeout
% 1000) };
283 struct timeval
*pTimeout
= msTimeout
== -1 ? NULL
: &timeout
;
286 FD_SET( sd
, &readFDs
);
288 rc
= select( sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, pTimeout
);
293 #endif // AUTO_CALLBACKS
297 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
*pEnv
, jobject pThis
)
298 /* Call through to DNSServiceProcessResult() while data remains on socket. */
300 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
302 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
303 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
304 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
305 DNSServiceErrorType err
= kDNSServiceErr_BadState
;
307 if ( pContext
!= NULL
)
309 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
311 struct timeval zeroTimeout
= { 0, 0 };
313 pContext
->Env
= pEnv
;
316 FD_SET( sd
, &readFDs
);
318 err
= kDNSServiceErr_NoError
;
319 if (0 < select(sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
))
321 err
= DNSServiceProcessResult(pContext
->ServiceRef
);
323 // We cannot touch any data structures associated with this operation!
324 // The DNSServiceProcessResult() routine should have invoked our callback,
325 // and our callback could have terminated the operation with op.stop();
326 // and that means HaltOperation() will have been called, which frees pContext.
327 // Basically, from here we just have to get out without touching any stale
328 // data structures that could blow up on us! Particularly, any attempt
329 // to loop here reading more results from the file descriptor is unsafe.
333 #endif // AUTO_CALLBACKS
337 static void DNSSD_API
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
338 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,
339 const char *replyDomain
, void *context
)
341 OpContext
*pContext
= (OpContext
*) context
;
343 SetupCallbackState( &pContext
->Env
);
345 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
347 if ( errorCode
== kDNSServiceErr_NoError
)
349 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
350 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
351 pContext
->JavaObj
, flags
, interfaceIndex
,
352 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
353 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
),
354 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
357 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
360 TeardownCallbackState();
363 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv
*pEnv
, jobject pThis
,
364 jint flags
, jint ifIndex
, jstring regType
, jstring domain
)
366 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
367 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
368 OpContext
*pContext
= NULL
;
369 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
371 if ( contextField
!= 0)
372 pContext
= NewContext( pEnv
, pThis
, "serviceFound",
373 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
375 err
= kDNSServiceErr_BadParam
;
377 if ( pContext
!= NULL
)
379 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
380 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
382 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
383 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
384 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
386 err
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
);
387 if ( err
== kDNSServiceErr_NoError
)
389 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
392 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
393 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
396 err
= kDNSServiceErr_NoMemory
;
402 static void DNSSD_API
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
403 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,
404 uint16_t port
, uint16_t txtLen
, const char *txtRecord
, void *context
)
406 OpContext
*pContext
= (OpContext
*) context
;
413 SetupCallbackState( &pContext
->Env
);
415 txtCls
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord");
416 txtCtor
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V");
418 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&& txtCtor
!= NULL
&&
419 NULL
!= ( txtBytes
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
)))
421 if ( errorCode
== kDNSServiceErr_NoError
)
423 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
424 // pattern into a number here.
425 port
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1];
427 // Initialize txtBytes with contents of txtRecord
428 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
);
429 memcpy( pBytes
, txtRecord
, txtLen
);
430 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
);
432 // Construct txtObj with txtBytes
433 txtObj
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
);
434 (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
);
436 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
437 pContext
->JavaObj
, flags
, interfaceIndex
,
438 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
),
439 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
),
443 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
446 TeardownCallbackState();
449 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
*pEnv
, jobject pThis
,
450 jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
)
452 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
453 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
454 OpContext
*pContext
= NULL
;
455 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
457 if ( contextField
!= 0)
458 pContext
= NewContext( pEnv
, pThis
, "serviceResolved",
459 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
461 err
= kDNSServiceErr_BadParam
;
463 if ( pContext
!= NULL
)
465 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
466 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
467 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
469 err
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,
470 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
);
471 if ( err
== kDNSServiceErr_NoError
)
473 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
476 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
477 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
478 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
481 err
= kDNSServiceErr_NoMemory
;
487 static void DNSSD_API
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,
488 DNSServiceErrorType errorCode
, const char *serviceName
,
489 const char *regType
, const char *domain
, void *context
)
491 OpContext
*pContext
= (OpContext
*) context
;
493 SetupCallbackState( &pContext
->Env
);
495 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
497 if ( errorCode
== kDNSServiceErr_NoError
)
499 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
500 pContext
->JavaObj
, flags
,
501 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
502 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
),
503 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
));
506 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
508 TeardownCallbackState();
511 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv
*pEnv
, jobject pThis
,
512 jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,
513 jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
)
515 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
516 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
517 OpContext
*pContext
= NULL
;
518 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
522 if ( contextField
!= 0)
523 pContext
= NewContext( pEnv
, pThis
, "serviceRegistered",
524 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
526 err
= kDNSServiceErr_BadParam
;
528 if ( pContext
!= NULL
)
530 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
531 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
532 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
533 const char *hostStr
= SafeGetUTFChars( pEnv
, host
);
535 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
536 // big-endian number into a 16-bit pattern here.
537 uint16_t portBits
= port
;
538 portBits
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1];
540 pBytes
= txtRecord
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
;
541 numBytes
= txtRecord
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0;
543 err
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,
544 domainStr
, hostStr
, portBits
,
545 numBytes
, pBytes
, ServiceRegisterReply
, pContext
);
546 if ( err
== kDNSServiceErr_NoError
)
548 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
552 (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0);
554 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
555 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
556 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
557 SafeReleaseUTFChars( pEnv
, host
, hostStr
);
560 err
= kDNSServiceErr_NoMemory
;
565 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
*pEnv
, jobject pThis
,
566 jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
)
568 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
569 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
570 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
571 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "I");
572 OpContext
*pContext
= NULL
;
573 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
578 if ( contextField
!= 0)
579 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
580 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
581 return kDNSServiceErr_BadParam
;
583 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
584 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
586 err
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
);
587 if ( err
== kDNSServiceErr_NoError
)
589 (*pEnv
)->SetIntField( pEnv
, destObj
, recField
, (jint
) recRef
);
593 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
598 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv
*pEnv
, jobject pThis
,
599 jint flags
, jbyteArray rData
, jint ttl
)
601 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
602 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
603 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I");
604 OpContext
*pContext
= NULL
;
605 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
608 DNSRecordRef recRef
= NULL
;
610 if ( ownerField
!= 0)
612 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
613 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
614 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I");
615 if ( contextField
!= 0)
616 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
);
619 recRef
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
);
620 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
621 return kDNSServiceErr_BadParam
;
623 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
624 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
626 err
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
);
629 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
634 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv
*pEnv
, jobject pThis
)
636 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
637 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
638 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I");
639 OpContext
*pContext
= NULL
;
640 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
641 DNSRecordRef recRef
= NULL
;
643 if ( ownerField
!= 0)
645 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
646 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
647 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I");
648 if ( contextField
!= 0)
649 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
);
652 recRef
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
);
653 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
654 return kDNSServiceErr_BadParam
;
656 err
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0);
662 static void DNSSD_API
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
663 DNSServiceErrorType errorCode
, const char *serviceName
,
664 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
,
665 const void *rdata
, uint32_t ttl
, void *context
)
667 OpContext
*pContext
= (OpContext
*) context
;
671 SetupCallbackState( &pContext
->Env
);
673 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&&
674 NULL
!= ( rDataObj
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
)))
676 if ( errorCode
== kDNSServiceErr_NoError
)
678 // Initialize rDataObj with contents of rdata
679 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
);
680 memcpy( pBytes
, rdata
, rdlen
);
681 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
);
683 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
684 pContext
->JavaObj
, flags
, interfaceIndex
,
685 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
686 rrtype
, rrclass
, rDataObj
, ttl
);
689 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
691 TeardownCallbackState();
694 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv
*pEnv
, jobject pThis
,
695 jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
)
697 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
698 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
699 OpContext
*pContext
= NULL
;
700 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
702 if ( contextField
!= 0)
703 pContext
= NewContext( pEnv
, pThis
, "queryAnswered",
704 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
706 err
= kDNSServiceErr_BadParam
;
708 if ( pContext
!= NULL
)
710 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
712 err
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,
713 rrtype
, rrclass
, ServiceQueryReply
, pContext
);
714 if ( err
== kDNSServiceErr_NoError
)
716 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
719 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
722 err
= kDNSServiceErr_NoMemory
;
728 static void DNSSD_API
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
729 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
731 OpContext
*pContext
= (OpContext
*) context
;
733 SetupCallbackState( &pContext
->Env
);
735 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
737 if ( errorCode
== kDNSServiceErr_NoError
)
739 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
740 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
741 pContext
->JavaObj
, flags
, interfaceIndex
,
742 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
745 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
747 TeardownCallbackState();
750 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv
*pEnv
, jobject pThis
,
751 jint flags
, jint ifIndex
)
753 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
754 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
755 OpContext
*pContext
= NULL
;
756 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
758 if ( contextField
!= 0)
759 pContext
= NewContext( pEnv
, pThis
, "domainFound",
760 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
762 err
= kDNSServiceErr_BadParam
;
764 if ( pContext
!= NULL
)
766 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
767 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
768 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
770 err
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,
771 DomainEnumReply
, pContext
);
772 if ( err
== kDNSServiceErr_NoError
)
774 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
778 err
= kDNSServiceErr_NoMemory
;
784 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
785 jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
)
787 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
788 const char *nameStr
= SafeGetUTFChars( pEnv
, serviceName
);
789 const char *regStr
= SafeGetUTFChars( pEnv
, regtype
);
790 const char *domStr
= SafeGetUTFChars( pEnv
, domain
);
791 char buff
[ kDNSServiceMaxDomainName
+ 1];
793 err
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
);
795 if ( err
== kDNSServiceErr_NoError
)
797 // pOut is expected to be a String[1] array.
798 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
));
801 SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
);
802 SafeReleaseUTFChars( pEnv
, regtype
, regStr
);
803 SafeReleaseUTFChars( pEnv
, domain
, domStr
);
808 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
809 jint flags
, jint ifIndex
, jstring fullName
,
810 jint rrtype
, jint rrclass
, jbyteArray rdata
)
814 const char *nameStr
= SafeGetUTFChars( pEnv
, fullName
);
816 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
);
817 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rdata
);
819 DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
);
822 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0);
824 SafeReleaseUTFChars( pEnv
, fullName
, nameStr
);
827 #define LOCAL_ONLY_NAME "loo"
829 JNIEXPORT jstring JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
832 char *p
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
];
834 if (ifIndex
!= kDNSServiceInterfaceIndexLocalOnly
)
835 p
= if_indextoname( ifIndex
, nameBuff
);
837 return (*pEnv
)->NewStringUTF( pEnv
, p
);
841 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
844 uint32_t ifIndex
= kDNSServiceInterfaceIndexLocalOnly
;
845 const char *nameStr
= SafeGetUTFChars( pEnv
, ifName
);
847 if (strcmp(nameStr
, LOCAL_ONLY_NAME
))
848 ifIndex
= if_nametoindex( nameStr
);
850 SafeReleaseUTFChars( pEnv
, ifName
, nameStr
);
858 if_indextoname( DWORD ifIndex
, char * nameBuff
)
860 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
861 PIP_ADAPTER_INFO pAdapter
= NULL
;
863 char * ifName
= NULL
;
864 ULONG ulOutBufLen
= 0;
866 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
871 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
873 if (pAdapterInfo
== NULL
)
878 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
880 if (dwRetVal
!= NO_ERROR
)
885 pAdapter
= pAdapterInfo
;
888 if (pAdapter
->Index
== ifIndex
)
890 // It would be better if we passed in the length of nameBuff to this
891 // function, so we would have absolute certainty that no buffer
892 // overflows would occur. Buffer overflows *shouldn't* occur because
893 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
894 strcpy( nameBuff
, pAdapter
->AdapterName
);
899 pAdapter
= pAdapter
->Next
;
904 if (pAdapterInfo
!= NULL
)
906 free( pAdapterInfo
);
915 if_nametoindex( const char * nameStr
)
917 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
918 PIP_ADAPTER_INFO pAdapter
= NULL
;
921 ULONG ulOutBufLen
= 0;
923 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
928 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
930 if (pAdapterInfo
== NULL
)
935 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
937 if (dwRetVal
!= NO_ERROR
)
942 pAdapter
= pAdapterInfo
;
945 if (strcmp(pAdapter
->AdapterName
, nameStr
) == 0)
947 ifIndex
= pAdapter
->Index
;
951 pAdapter
= pAdapter
->Next
;
956 if (pAdapterInfo
!= NULL
)
958 free( pAdapterInfo
);