1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: JNISupport.c,v $
20 Revision 1.17 2006/08/14 23:25:08 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.16 2006/07/14 02:35:47 cheshire
24 Added (commented out) syslog debugging messages
26 Revision 1.15 2006/06/27 19:34:43 cheshire
27 <rdar://problem/4430023> txtRecord parameter of DNSServiceResolveReply() should be unsigned char *
29 Revision 1.14 2006/06/20 23:03:35 rpantos
30 <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
32 Revision 1.13 2005/10/26 01:52:24 cheshire
33 <rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
35 Revision 1.12 2005/07/13 19:20:32 cheshire
36 <rdar://problem/4175511> Race condition in Java API
37 Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
39 Revision 1.11 2005/07/11 01:55:21 cheshire
40 <rdar://problem/4175511> Race condition in Java API
42 Revision 1.10 2005/07/05 13:01:52 cheshire
43 <rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
45 Revision 1.9 2004/12/11 03:01:00 rpantos
46 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
48 Revision 1.8 2004/11/30 23:51:05 cheshire
49 Remove double semicolons
51 Revision 1.7 2004/11/23 08:12:04 shersche
52 Implement if_nametoindex and if_indextoname for Win32 platforms
54 Revision 1.6 2004/11/23 03:41:14 cheshire
55 Change JNISupport.c to call if_indextoname & if_nametoindex directly.
56 (May require some additional glue code to work on Windows.)
58 Revision 1.5 2004/11/17 17:07:44 cheshire
59 Updated comment about AUTO_CALLBACKS
61 Revision 1.4 2004/11/12 03:23:09 rpantos
62 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
64 Revision 1.3 2004/06/18 04:44:17 rpantos
65 Adapt to API unification on Windows
67 Revision 1.2 2004/05/28 23:34:42 ksekar
68 <rdar://problem/3672903>: Java project build errors
70 Revision 1.1 2004/04/30 16:29:35 rpantos
74 This file contains the platform support for DNSSD and related Java classes.
75 It is used to shim through to the underlying <dns_sd.h> API.
78 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
79 // callbacks automatically (as in the early Windows prototypes).
80 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
81 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
82 // (Invoking callbacks automatically on a different thread sounds attractive, but while
83 // the client gains by not needing to add an event source to its main event loop, it loses
84 // by being forced to deal with concurrency and locking, which can be a bigger burden.)
85 #ifndef AUTO_CALLBACKS
86 #define AUTO_CALLBACKS 0
93 #include <sys/types.h>
94 #include <sys/select.h>
96 #endif // AUTO_CALLBACKS
104 #include <winsock2.h>
105 #include <iphlpapi.h>
106 static char * if_indextoname( DWORD ifIndex
, char * nameBuff
);
107 static DWORD
if_nametoindex( const char * nameStr
);
108 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
110 #include <sys/socket.h>
115 #include "DNSSD.java.h"
117 //#include <syslog.h>
119 // convenience definition
121 #define _UNUSED __attribute__ ((unused))
127 kInterfaceVersion
= 1 // Must match version in .jar file
130 typedef struct OpContext OpContext
;
134 DNSServiceRef ServiceRef
;
142 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
144 JavaVM
*gJavaVM
= NULL
;
148 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv
*pEnv
, jclass cls
,
151 /* Ensure that caller & interface versions match. */
152 if ( callerVersion
!= kInterfaceVersion
)
153 return kDNSServiceErr_Incompatible
;
159 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
))
160 return kDNSServiceErr_BadState
;
164 // Set AppleDNSSD.hasAutoCallbacks
167 jboolean hasAutoC
= JNI_TRUE
;
169 jboolean hasAutoC
= JNI_FALSE
;
171 jfieldID hasAutoCField
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z");
172 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
);
175 return kDNSServiceErr_NoError
;
179 static const char* SafeGetUTFChars( JNIEnv
*pEnv
, jstring str
)
180 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
182 return str
!= NULL
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
;
185 static void SafeReleaseUTFChars( JNIEnv
*pEnv
, jstring str
, const char *buff
)
186 // Wrapper for JNI GetStringUTFChars() that handles null str.
189 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
);
194 static void SetupCallbackState( JNIEnv
**ppEnv
)
196 (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
);
199 static void TeardownCallbackState( void )
201 (*gJavaVM
)->DetachCurrentThread( gJavaVM
);
204 #else // AUTO_CALLBACKS
206 static void SetupCallbackState( JNIEnv
**ppEnv _UNUSED
)
208 // No setup necessary if ProcessResults() has been called
211 static void TeardownCallbackState( void )
213 // No teardown necessary if ProcessResults() has been called
215 #endif // AUTO_CALLBACKS
218 static OpContext
*NewContext( JNIEnv
*pEnv
, jobject owner
,
219 const char *callbackName
, const char *callbackSig
)
220 // Create and initialize a new OpContext.
222 OpContext
*pContext
= (OpContext
*) malloc( sizeof *pContext
);
224 if ( pContext
!= NULL
)
226 jfieldID clientField
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),
227 "fListener", "Lcom/apple/dnssd/BaseListener;");
229 pContext
->JavaObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
); // must convert local ref to global to cache;
230 pContext
->ClientObj
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
);
231 pContext
->ClientObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
); // must convert local ref to global to cache
232 pContext
->Callback
= (*pEnv
)->GetMethodID( pEnv
,
233 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
234 callbackName
, callbackSig
);
235 pContext
->Callback2
= NULL
; // not always used
242 static void ReportError( JNIEnv
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
)
243 // Invoke operationFailed() method on target with err.
245 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, target
);
246 jmethodID opFailed
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",
247 "(Lcom/apple/dnssd/DNSSDService;I)V");
249 (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
);
252 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv
*pEnv
, jobject pThis
)
253 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
255 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
256 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
258 if ( contextField
!= 0)
260 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
261 if ( pContext
!= NULL
)
263 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
264 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, 0);
265 if ( pContext
->ServiceRef
!= NULL
)
266 DNSServiceRefDeallocate( pContext
->ServiceRef
);
268 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
);
269 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
);
276 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv
*pEnv
, jobject pThis
)
277 /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
279 // BlockForData() not supported with AUTO_CALLBACKS
281 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
282 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
284 if ( contextField
!= 0)
286 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
287 if ( pContext
!= NULL
)
290 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
291 struct timeval timeout
= { 1, 0 };
293 FD_SET( sd
, &readFDs
);
295 // Q: Why do we poll here?
296 // A: Because there's no other thread-safe way to do it.
297 // Mac OS X terminates a select() call if you close one of the sockets it's listening on, but Linux does not,
298 // and arguably Linux is correct (See <http://www.ussg.iu.edu/hypermail/linux/kernel/0405.1/0418.html>)
299 // The problem is that the Mac OS X behaviour assumes that it's okay for one thread to close a socket while
300 // some other thread is monitoring that socket in select(), but the difficulty is that there's no general way
301 // to make that thread-safe, because there's no atomic way to enter select() and release a lock simultaneously.
302 // If we try to do this without holding any lock, then right as we jump to the select() routine,
303 // some other thread could stop our operation (thereby closing the socket),
304 // and then that thread (or even some third, unrelated thread)
305 // could do some other DNS-SD operation (or some other operation that opens a new file descriptor)
306 // and then we'd blindly resume our fall into the select() call, now blocking on a file descriptor
307 // that may coincidentally have the same numerical value, but is semantically unrelated
308 // to the true file descriptor we thought we were blocking on.
309 // We can't stop this race condition from happening, but at least if we wake up once a second we can detect
310 // when fNativeContext has gone to zero, and thereby discover that we were blocking on the wrong fd.
312 if (select( sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
) == 1) return(1);
315 #endif // !AUTO_CALLBACKS
320 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
*pEnv
, jobject pThis
)
321 /* Call through to DNSServiceProcessResult() while data remains on socket. */
323 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
325 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
326 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
327 OpContext
*pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
328 DNSServiceErrorType err
= kDNSServiceErr_BadState
;
330 if ( pContext
!= NULL
)
332 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
334 struct timeval zeroTimeout
= { 0, 0 };
336 pContext
->Env
= pEnv
;
339 FD_SET( sd
, &readFDs
);
341 err
= kDNSServiceErr_NoError
;
342 if (0 < select(sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
))
344 err
= DNSServiceProcessResult(pContext
->ServiceRef
);
346 // We cannot touch any data structures associated with this operation!
347 // The DNSServiceProcessResult() routine should have invoked our callback,
348 // and our callback could have terminated the operation with op.stop();
349 // and that means HaltOperation() will have been called, which frees pContext.
350 // Basically, from here we just have to get out without touching any stale
351 // data structures that could blow up on us! Particularly, any attempt
352 // to loop here reading more results from the file descriptor is unsafe.
356 #endif // AUTO_CALLBACKS
360 static void DNSSD_API
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
361 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,
362 const char *replyDomain
, void *context
)
364 OpContext
*pContext
= (OpContext
*) context
;
366 SetupCallbackState( &pContext
->Env
);
368 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
370 if ( errorCode
== kDNSServiceErr_NoError
)
372 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
373 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
374 pContext
->JavaObj
, flags
, interfaceIndex
,
375 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
376 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
),
377 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
380 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
383 TeardownCallbackState();
386 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv
*pEnv
, jobject pThis
,
387 jint flags
, jint ifIndex
, jstring regType
, jstring domain
)
389 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
390 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
391 OpContext
*pContext
= NULL
;
392 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
394 if ( contextField
!= 0)
395 pContext
= NewContext( pEnv
, pThis
, "serviceFound",
396 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
398 err
= kDNSServiceErr_BadParam
;
400 if ( pContext
!= NULL
)
402 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
403 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
405 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
406 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
407 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
409 err
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
);
410 if ( err
== kDNSServiceErr_NoError
)
412 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
415 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
416 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
419 err
= kDNSServiceErr_NoMemory
;
425 static void DNSSD_API
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
426 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,
427 uint16_t port
, uint16_t txtLen
, const unsigned char *txtRecord
, void *context
)
429 OpContext
*pContext
= (OpContext
*) context
;
436 SetupCallbackState( &pContext
->Env
);
438 txtCls
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord");
439 txtCtor
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V");
441 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&& txtCtor
!= NULL
&&
442 NULL
!= ( txtBytes
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
)))
444 if ( errorCode
== kDNSServiceErr_NoError
)
446 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
447 // pattern into a number here.
448 port
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1];
450 // Initialize txtBytes with contents of txtRecord
451 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
);
452 memcpy( pBytes
, txtRecord
, txtLen
);
453 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
);
455 // Construct txtObj with txtBytes
456 txtObj
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
);
457 (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
);
459 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
460 pContext
->JavaObj
, flags
, interfaceIndex
,
461 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
),
462 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
),
466 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
469 TeardownCallbackState();
472 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
*pEnv
, jobject pThis
,
473 jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
)
475 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
476 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
477 OpContext
*pContext
= NULL
;
478 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
480 if ( contextField
!= 0)
481 pContext
= NewContext( pEnv
, pThis
, "serviceResolved",
482 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
484 err
= kDNSServiceErr_BadParam
;
486 if ( pContext
!= NULL
)
488 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
489 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
490 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
492 err
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,
493 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
);
494 if ( err
== kDNSServiceErr_NoError
)
496 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
499 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
500 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
501 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
504 err
= kDNSServiceErr_NoMemory
;
510 static void DNSSD_API
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,
511 DNSServiceErrorType errorCode
, const char *serviceName
,
512 const char *regType
, const char *domain
, void *context
)
514 OpContext
*pContext
= (OpContext
*) context
;
516 SetupCallbackState( &pContext
->Env
);
518 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
520 if ( errorCode
== kDNSServiceErr_NoError
)
522 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
523 pContext
->JavaObj
, flags
,
524 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
525 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
),
526 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
));
529 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
531 TeardownCallbackState();
534 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv
*pEnv
, jobject pThis
,
535 jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,
536 jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
)
538 //syslog(LOG_ERR, "BR");
539 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
540 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
541 OpContext
*pContext
= NULL
;
542 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
546 //syslog(LOG_ERR, "BR: contextField %d", contextField);
548 if ( contextField
!= 0)
549 pContext
= NewContext( pEnv
, pThis
, "serviceRegistered",
550 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
552 err
= kDNSServiceErr_BadParam
;
554 if ( pContext
!= NULL
)
556 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
557 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
558 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
559 const char *hostStr
= SafeGetUTFChars( pEnv
, host
);
561 //syslog(LOG_ERR, "BR: regStr %s", regStr);
563 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
564 // big-endian number into a 16-bit pattern here.
565 uint16_t portBits
= port
;
566 portBits
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1];
568 pBytes
= txtRecord
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
;
569 numBytes
= txtRecord
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0;
571 err
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,
572 domainStr
, hostStr
, portBits
,
573 numBytes
, pBytes
, ServiceRegisterReply
, pContext
);
574 if ( err
== kDNSServiceErr_NoError
)
576 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
580 (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0);
582 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
583 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
584 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
585 SafeReleaseUTFChars( pEnv
, host
, hostStr
);
588 err
= kDNSServiceErr_NoMemory
;
593 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
*pEnv
, jobject pThis
,
594 jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
)
596 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
597 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
598 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
599 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "I");
600 OpContext
*pContext
= NULL
;
601 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
606 if ( contextField
!= 0)
607 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
608 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
609 return kDNSServiceErr_BadParam
;
611 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
612 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
614 err
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
);
615 if ( err
== kDNSServiceErr_NoError
)
617 (*pEnv
)->SetIntField( pEnv
, destObj
, recField
, (jint
) recRef
);
621 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
626 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv
*pEnv
, jobject pThis
,
627 jint flags
, jbyteArray rData
, jint ttl
)
629 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
630 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
631 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I");
632 OpContext
*pContext
= NULL
;
633 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
636 DNSRecordRef recRef
= NULL
;
638 if ( ownerField
!= 0)
640 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
641 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
642 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I");
643 if ( contextField
!= 0)
644 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
);
647 recRef
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
);
648 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
649 return kDNSServiceErr_BadParam
;
651 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
652 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
654 err
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
);
657 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
662 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv
*pEnv
, jobject pThis
)
664 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
665 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
666 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "I");
667 OpContext
*pContext
= NULL
;
668 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
669 DNSRecordRef recRef
= NULL
;
671 if ( ownerField
!= 0)
673 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
674 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
675 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "I");
676 if ( contextField
!= 0)
677 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, ownerObj
, contextField
);
680 recRef
= (DNSRecordRef
) (*pEnv
)->GetIntField( pEnv
, pThis
, recField
);
681 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
682 return kDNSServiceErr_BadParam
;
684 err
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0);
690 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv
*pEnv
, jobject pThis
)
692 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
693 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
694 OpContext
*pContext
= NULL
;
695 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
697 if ( contextField
!= 0)
698 pContext
= NewContext( pEnv
, pThis
, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
700 err
= kDNSServiceErr_BadParam
;
702 if ( pContext
!= NULL
)
704 err
= DNSServiceCreateConnection( &pContext
->ServiceRef
);
705 if ( err
== kDNSServiceErr_NoError
)
707 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
711 err
= kDNSServiceErr_NoMemory
;
716 struct RecordRegistrationRef
721 typedef struct RecordRegistrationRef RecordRegistrationRef
;
723 static void DNSSD_API
RegisterRecordReply( DNSServiceRef sdRef _UNUSED
,
724 DNSRecordRef recordRef _UNUSED
, DNSServiceFlags flags
,
725 DNSServiceErrorType errorCode
, void *context
)
727 RecordRegistrationRef
*regEnvelope
= (RecordRegistrationRef
*) context
;
728 OpContext
*pContext
= regEnvelope
->Context
;
730 SetupCallbackState( &pContext
->Env
);
732 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
734 if ( errorCode
== kDNSServiceErr_NoError
)
736 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
737 regEnvelope
->RecordObj
, flags
);
740 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
743 (*pContext
->Env
)->DeleteWeakGlobalRef( pContext
->Env
, regEnvelope
->RecordObj
);
746 TeardownCallbackState();
749 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv
*pEnv
, jobject pThis
,
750 jint flags
, jint ifIndex
, jstring fullname
, jint rrType
, jint rrClass
,
751 jbyteArray rData
, jint ttl
, jobject destObj
)
753 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
754 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
755 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
756 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "I");
757 const char *nameStr
= SafeGetUTFChars( pEnv
, fullname
);
758 OpContext
*pContext
= NULL
;
759 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
763 RecordRegistrationRef
*regEnvelope
;
765 if ( contextField
!= 0)
766 pContext
= (OpContext
*) (*pEnv
)->GetIntField( pEnv
, pThis
, contextField
);
767 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
|| nameStr
== NULL
)
768 return kDNSServiceErr_BadParam
;
770 regEnvelope
= calloc( 1, sizeof *regEnvelope
);
771 if ( regEnvelope
== NULL
)
772 return kDNSServiceErr_NoMemory
;
773 regEnvelope
->Context
= pContext
;
774 regEnvelope
->RecordObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, destObj
); // must convert local ref to global to cache
776 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
777 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
779 err
= DNSServiceRegisterRecord( pContext
->ServiceRef
, &recRef
, flags
, ifIndex
,
780 nameStr
, rrType
, rrClass
, numBytes
, pBytes
, ttl
,
781 RegisterRecordReply
, regEnvelope
);
783 if ( err
== kDNSServiceErr_NoError
)
785 (*pEnv
)->SetIntField( pEnv
, destObj
, recField
, (jint
) recRef
);
789 if ( regEnvelope
->RecordObj
!= NULL
)
790 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, regEnvelope
->RecordObj
);
795 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
797 SafeReleaseUTFChars( pEnv
, fullname
, nameStr
);
803 static void DNSSD_API
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
804 DNSServiceErrorType errorCode
, const char *serviceName
,
805 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
,
806 const void *rdata
, uint32_t ttl
, void *context
)
808 OpContext
*pContext
= (OpContext
*) context
;
812 SetupCallbackState( &pContext
->Env
);
814 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&&
815 NULL
!= ( rDataObj
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
)))
817 if ( errorCode
== kDNSServiceErr_NoError
)
819 // Initialize rDataObj with contents of rdata
820 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
);
821 memcpy( pBytes
, rdata
, rdlen
);
822 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
);
824 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
825 pContext
->JavaObj
, flags
, interfaceIndex
,
826 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
827 rrtype
, rrclass
, rDataObj
, ttl
);
830 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
832 TeardownCallbackState();
835 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv
*pEnv
, jobject pThis
,
836 jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
)
838 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
839 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
840 OpContext
*pContext
= NULL
;
841 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
843 if ( contextField
!= 0)
844 pContext
= NewContext( pEnv
, pThis
, "queryAnswered",
845 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
847 err
= kDNSServiceErr_BadParam
;
849 if ( pContext
!= NULL
)
851 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
853 err
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,
854 rrtype
, rrclass
, ServiceQueryReply
, pContext
);
855 if ( err
== kDNSServiceErr_NoError
)
857 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
860 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
863 err
= kDNSServiceErr_NoMemory
;
869 static void DNSSD_API
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
870 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
872 OpContext
*pContext
= (OpContext
*) context
;
874 SetupCallbackState( &pContext
->Env
);
876 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
878 if ( errorCode
== kDNSServiceErr_NoError
)
880 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
881 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
882 pContext
->JavaObj
, flags
, interfaceIndex
,
883 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
886 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
888 TeardownCallbackState();
891 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv
*pEnv
, jobject pThis
,
892 jint flags
, jint ifIndex
)
894 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
895 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "I");
896 OpContext
*pContext
= NULL
;
897 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
899 if ( contextField
!= 0)
900 pContext
= NewContext( pEnv
, pThis
, "domainFound",
901 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
903 err
= kDNSServiceErr_BadParam
;
905 if ( pContext
!= NULL
)
907 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
908 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
909 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
911 err
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,
912 DomainEnumReply
, pContext
);
913 if ( err
== kDNSServiceErr_NoError
)
915 (*pEnv
)->SetIntField( pEnv
, pThis
, contextField
, (jint
) pContext
);
919 err
= kDNSServiceErr_NoMemory
;
925 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
926 jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
)
928 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
929 const char *nameStr
= SafeGetUTFChars( pEnv
, serviceName
);
930 const char *regStr
= SafeGetUTFChars( pEnv
, regtype
);
931 const char *domStr
= SafeGetUTFChars( pEnv
, domain
);
932 char buff
[ kDNSServiceMaxDomainName
+ 1];
934 err
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
);
936 if ( err
== kDNSServiceErr_NoError
)
938 // pOut is expected to be a String[1] array.
939 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
));
942 SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
);
943 SafeReleaseUTFChars( pEnv
, regtype
, regStr
);
944 SafeReleaseUTFChars( pEnv
, domain
, domStr
);
949 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
950 jint flags
, jint ifIndex
, jstring fullName
,
951 jint rrtype
, jint rrclass
, jbyteArray rdata
)
955 const char *nameStr
= SafeGetUTFChars( pEnv
, fullName
);
957 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
);
958 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rdata
);
960 DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
);
963 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0);
965 SafeReleaseUTFChars( pEnv
, fullName
, nameStr
);
968 #define LOCAL_ONLY_NAME "loo"
970 JNIEXPORT jstring JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
973 char *p
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
];
975 if (ifIndex
!= (jint
) kDNSServiceInterfaceIndexLocalOnly
)
976 p
= if_indextoname( ifIndex
, nameBuff
);
978 return (*pEnv
)->NewStringUTF( pEnv
, p
);
982 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
985 uint32_t ifIndex
= kDNSServiceInterfaceIndexLocalOnly
;
986 const char *nameStr
= SafeGetUTFChars( pEnv
, ifName
);
988 if (strcmp(nameStr
, LOCAL_ONLY_NAME
))
989 ifIndex
= if_nametoindex( nameStr
);
991 SafeReleaseUTFChars( pEnv
, ifName
, nameStr
);
999 if_indextoname( DWORD ifIndex
, char * nameBuff
)
1001 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
1002 PIP_ADAPTER_INFO pAdapter
= NULL
;
1004 char * ifName
= NULL
;
1005 ULONG ulOutBufLen
= 0;
1007 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
1012 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
1014 if (pAdapterInfo
== NULL
)
1019 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
1021 if (dwRetVal
!= NO_ERROR
)
1026 pAdapter
= pAdapterInfo
;
1029 if (pAdapter
->Index
== ifIndex
)
1031 // It would be better if we passed in the length of nameBuff to this
1032 // function, so we would have absolute certainty that no buffer
1033 // overflows would occur. Buffer overflows *shouldn't* occur because
1034 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
1035 strcpy( nameBuff
, pAdapter
->AdapterName
);
1040 pAdapter
= pAdapter
->Next
;
1045 if (pAdapterInfo
!= NULL
)
1047 free( pAdapterInfo
);
1048 pAdapterInfo
= NULL
;
1056 if_nametoindex( const char * nameStr
)
1058 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
1059 PIP_ADAPTER_INFO pAdapter
= NULL
;
1062 ULONG ulOutBufLen
= 0;
1064 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
1069 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
1071 if (pAdapterInfo
== NULL
)
1076 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
1078 if (dwRetVal
!= NO_ERROR
)
1083 pAdapter
= pAdapterInfo
;
1086 if (strcmp(pAdapter
->AdapterName
, nameStr
) == 0)
1088 ifIndex
= pAdapter
->Index
;
1092 pAdapter
= pAdapter
->Next
;
1097 if (pAdapterInfo
!= NULL
)
1099 free( pAdapterInfo
);
1100 pAdapterInfo
= NULL
;