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.21 2007/09/18 19:09:02 cheshire
21 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
23 Revision 1.20 2007/03/13 01:41:46 cheshire
24 Fixed compile warnings when building 32-bit
26 Revision 1.19 2007/03/13 00:28:03 vazquez
27 <rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
29 Revision 1.18 2007/03/13 00:10:14 vazquez
30 <rdar://problem/4455206> Java: 64 bit JNI patch
32 Revision 1.17 2006/08/14 23:25:08 cheshire
33 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
35 Revision 1.16 2006/07/14 02:35:47 cheshire
36 Added (commented out) syslog debugging messages
38 Revision 1.15 2006/06/27 19:34:43 cheshire
39 <rdar://problem/4430023> txtRecord parameter of DNSServiceResolveReply() should be unsigned char *
41 Revision 1.14 2006/06/20 23:03:35 rpantos
42 <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
44 Revision 1.13 2005/10/26 01:52:24 cheshire
45 <rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
47 Revision 1.12 2005/07/13 19:20:32 cheshire
48 <rdar://problem/4175511> Race condition in Java API
49 Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
51 Revision 1.11 2005/07/11 01:55:21 cheshire
52 <rdar://problem/4175511> Race condition in Java API
54 Revision 1.10 2005/07/05 13:01:52 cheshire
55 <rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
57 Revision 1.9 2004/12/11 03:01:00 rpantos
58 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
60 Revision 1.8 2004/11/30 23:51:05 cheshire
61 Remove double semicolons
63 Revision 1.7 2004/11/23 08:12:04 shersche
64 Implement if_nametoindex and if_indextoname for Win32 platforms
66 Revision 1.6 2004/11/23 03:41:14 cheshire
67 Change JNISupport.c to call if_indextoname & if_nametoindex directly.
68 (May require some additional glue code to work on Windows.)
70 Revision 1.5 2004/11/17 17:07:44 cheshire
71 Updated comment about AUTO_CALLBACKS
73 Revision 1.4 2004/11/12 03:23:09 rpantos
74 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
76 Revision 1.3 2004/06/18 04:44:17 rpantos
77 Adapt to API unification on Windows
79 Revision 1.2 2004/05/28 23:34:42 ksekar
80 <rdar://problem/3672903>: Java project build errors
82 Revision 1.1 2004/04/30 16:29:35 rpantos
86 This file contains the platform support for DNSSD and related Java classes.
87 It is used to shim through to the underlying <dns_sd.h> API.
90 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
91 // callbacks automatically (as in the early Windows prototypes).
92 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
93 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
94 // (Invoking callbacks automatically on a different thread sounds attractive, but while
95 // the client gains by not needing to add an event source to its main event loop, it loses
96 // by being forced to deal with concurrency and locking, which can be a bigger burden.)
97 #ifndef AUTO_CALLBACKS
98 #define AUTO_CALLBACKS 0
103 #include <winsock2.h>
105 #include <sys/types.h>
106 #include <sys/select.h>
108 #endif // AUTO_CALLBACKS
116 #include <winsock2.h>
117 #include <iphlpapi.h>
118 static char * if_indextoname( DWORD ifIndex
, char * nameBuff
);
119 static DWORD
if_nametoindex( const char * nameStr
);
120 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
122 #include <sys/socket.h>
127 #include "DNSSD.java.h"
129 //#include <syslog.h>
131 // convenience definition
133 #define _UNUSED __attribute__ ((unused))
139 kInterfaceVersionOne
= 1,
140 kInterfaceVersionCurrent
// Must match version in .jar file
143 typedef struct OpContext OpContext
;
147 DNSServiceRef ServiceRef
;
155 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
157 JavaVM
*gJavaVM
= NULL
;
161 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv
*pEnv
, jclass cls
,
164 /* Ensure that caller & interface versions match. */
165 if ( callerVersion
!= kInterfaceVersionCurrent
)
166 return kDNSServiceErr_Incompatible
;
172 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
))
173 return kDNSServiceErr_BadState
;
177 // Set AppleDNSSD.hasAutoCallbacks
180 jboolean hasAutoC
= JNI_TRUE
;
182 jboolean hasAutoC
= JNI_FALSE
;
184 jfieldID hasAutoCField
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z");
185 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
);
188 return kDNSServiceErr_NoError
;
192 static const char* SafeGetUTFChars( JNIEnv
*pEnv
, jstring str
)
193 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
195 return str
!= NULL
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
;
198 static void SafeReleaseUTFChars( JNIEnv
*pEnv
, jstring str
, const char *buff
)
199 // Wrapper for JNI GetStringUTFChars() that handles null str.
202 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
);
207 static void SetupCallbackState( JNIEnv
**ppEnv
)
209 (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
);
212 static void TeardownCallbackState( void )
214 (*gJavaVM
)->DetachCurrentThread( gJavaVM
);
217 #else // AUTO_CALLBACKS
219 static void SetupCallbackState( JNIEnv
**ppEnv _UNUSED
)
221 // No setup necessary if ProcessResults() has been called
224 static void TeardownCallbackState( void )
226 // No teardown necessary if ProcessResults() has been called
228 #endif // AUTO_CALLBACKS
231 static OpContext
*NewContext( JNIEnv
*pEnv
, jobject owner
,
232 const char *callbackName
, const char *callbackSig
)
233 // Create and initialize a new OpContext.
235 OpContext
*pContext
= (OpContext
*) malloc( sizeof *pContext
);
237 if ( pContext
!= NULL
)
239 jfieldID clientField
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),
240 "fListener", "Lcom/apple/dnssd/BaseListener;");
242 pContext
->JavaObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
); // must convert local ref to global to cache;
243 pContext
->ClientObj
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
);
244 pContext
->ClientObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
); // must convert local ref to global to cache
245 pContext
->Callback
= (*pEnv
)->GetMethodID( pEnv
,
246 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
247 callbackName
, callbackSig
);
248 pContext
->Callback2
= NULL
; // not always used
255 static void ReportError( JNIEnv
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
)
256 // Invoke operationFailed() method on target with err.
258 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, target
);
259 jmethodID opFailed
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",
260 "(Lcom/apple/dnssd/DNSSDService;I)V");
262 (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
);
265 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv
*pEnv
, jobject pThis
)
266 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
268 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
269 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
271 if ( contextField
!= 0)
273 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
274 if ( pContext
!= NULL
)
276 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
277 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, 0);
278 if ( pContext
->ServiceRef
!= NULL
)
279 DNSServiceRefDeallocate( pContext
->ServiceRef
);
281 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
);
282 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
);
289 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv
*pEnv
, jobject pThis
)
290 /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
292 // BlockForData() not supported with AUTO_CALLBACKS
294 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
295 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
297 if ( contextField
!= 0)
299 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
300 if ( pContext
!= NULL
)
303 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
304 struct timeval timeout
= { 1, 0 };
306 FD_SET( sd
, &readFDs
);
308 // Q: Why do we poll here?
309 // A: Because there's no other thread-safe way to do it.
310 // Mac OS X terminates a select() call if you close one of the sockets it's listening on, but Linux does not,
311 // and arguably Linux is correct (See <http://www.ussg.iu.edu/hypermail/linux/kernel/0405.1/0418.html>)
312 // The problem is that the Mac OS X behaviour assumes that it's okay for one thread to close a socket while
313 // some other thread is monitoring that socket in select(), but the difficulty is that there's no general way
314 // to make that thread-safe, because there's no atomic way to enter select() and release a lock simultaneously.
315 // If we try to do this without holding any lock, then right as we jump to the select() routine,
316 // some other thread could stop our operation (thereby closing the socket),
317 // and then that thread (or even some third, unrelated thread)
318 // could do some other DNS-SD operation (or some other operation that opens a new file descriptor)
319 // and then we'd blindly resume our fall into the select() call, now blocking on a file descriptor
320 // that may coincidentally have the same numerical value, but is semantically unrelated
321 // to the true file descriptor we thought we were blocking on.
322 // We can't stop this race condition from happening, but at least if we wake up once a second we can detect
323 // when fNativeContext has gone to zero, and thereby discover that we were blocking on the wrong fd.
325 if (select( sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
) == 1) return(1);
328 #endif // !AUTO_CALLBACKS
333 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
*pEnv
, jobject pThis
)
334 /* Call through to DNSServiceProcessResult() while data remains on socket. */
336 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
338 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
339 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
340 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
341 DNSServiceErrorType err
= kDNSServiceErr_BadState
;
343 if ( pContext
!= NULL
)
345 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
347 struct timeval zeroTimeout
= { 0, 0 };
349 pContext
->Env
= pEnv
;
352 FD_SET( sd
, &readFDs
);
354 err
= kDNSServiceErr_NoError
;
355 if (0 < select(sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
))
357 err
= DNSServiceProcessResult(pContext
->ServiceRef
);
359 // We cannot touch any data structures associated with this operation!
360 // The DNSServiceProcessResult() routine should have invoked our callback,
361 // and our callback could have terminated the operation with op.stop();
362 // and that means HaltOperation() will have been called, which frees pContext.
363 // Basically, from here we just have to get out without touching any stale
364 // data structures that could blow up on us! Particularly, any attempt
365 // to loop here reading more results from the file descriptor is unsafe.
369 #endif // AUTO_CALLBACKS
373 static void DNSSD_API
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
374 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,
375 const char *replyDomain
, void *context
)
377 OpContext
*pContext
= (OpContext
*) context
;
379 SetupCallbackState( &pContext
->Env
);
381 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
383 if ( errorCode
== kDNSServiceErr_NoError
)
385 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
386 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
387 pContext
->JavaObj
, flags
, interfaceIndex
,
388 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
389 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
),
390 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
393 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
396 TeardownCallbackState();
399 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv
*pEnv
, jobject pThis
,
400 jint flags
, jint ifIndex
, jstring regType
, jstring domain
)
402 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
403 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
404 OpContext
*pContext
= NULL
;
405 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
407 if ( contextField
!= 0)
408 pContext
= NewContext( pEnv
, pThis
, "serviceFound",
409 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
411 err
= kDNSServiceErr_BadParam
;
413 if ( pContext
!= NULL
)
415 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
416 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
418 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
419 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
420 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
422 err
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
);
423 if ( err
== kDNSServiceErr_NoError
)
425 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
428 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
429 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
432 err
= kDNSServiceErr_NoMemory
;
438 static void DNSSD_API
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
439 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,
440 uint16_t port
, uint16_t txtLen
, const unsigned char *txtRecord
, void *context
)
442 OpContext
*pContext
= (OpContext
*) context
;
449 SetupCallbackState( &pContext
->Env
);
451 txtCls
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord");
452 txtCtor
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V");
454 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&& txtCtor
!= NULL
&&
455 NULL
!= ( txtBytes
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
)))
457 if ( errorCode
== kDNSServiceErr_NoError
)
459 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
460 // pattern into a number here.
461 port
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1];
463 // Initialize txtBytes with contents of txtRecord
464 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
);
465 memcpy( pBytes
, txtRecord
, txtLen
);
466 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
);
468 // Construct txtObj with txtBytes
469 txtObj
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
);
470 (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
);
472 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
473 pContext
->JavaObj
, flags
, interfaceIndex
,
474 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
),
475 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
),
479 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
482 TeardownCallbackState();
485 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
*pEnv
, jobject pThis
,
486 jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
)
488 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
489 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
490 OpContext
*pContext
= NULL
;
491 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
493 if ( contextField
!= 0)
494 pContext
= NewContext( pEnv
, pThis
, "serviceResolved",
495 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
497 err
= kDNSServiceErr_BadParam
;
499 if ( pContext
!= NULL
)
501 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
502 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
503 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
505 err
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,
506 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
);
507 if ( err
== kDNSServiceErr_NoError
)
509 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
512 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
513 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
514 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
517 err
= kDNSServiceErr_NoMemory
;
523 static void DNSSD_API
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,
524 DNSServiceErrorType errorCode
, const char *serviceName
,
525 const char *regType
, const char *domain
, void *context
)
527 OpContext
*pContext
= (OpContext
*) context
;
529 SetupCallbackState( &pContext
->Env
);
531 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
533 if ( errorCode
== kDNSServiceErr_NoError
)
535 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
536 pContext
->JavaObj
, flags
,
537 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
538 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
),
539 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
));
542 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
544 TeardownCallbackState();
547 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv
*pEnv
, jobject pThis
,
548 jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,
549 jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
)
551 //syslog(LOG_ERR, "BR");
552 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
553 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
554 OpContext
*pContext
= NULL
;
555 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
559 //syslog(LOG_ERR, "BR: contextField %d", contextField);
561 if ( contextField
!= 0)
562 pContext
= NewContext( pEnv
, pThis
, "serviceRegistered",
563 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
565 err
= kDNSServiceErr_BadParam
;
567 if ( pContext
!= NULL
)
569 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
570 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
571 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
572 const char *hostStr
= SafeGetUTFChars( pEnv
, host
);
574 //syslog(LOG_ERR, "BR: regStr %s", regStr);
576 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
577 // big-endian number into a 16-bit pattern here.
578 uint16_t portBits
= port
;
579 portBits
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1];
581 pBytes
= txtRecord
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
;
582 numBytes
= txtRecord
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0;
584 err
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,
585 domainStr
, hostStr
, portBits
,
586 numBytes
, pBytes
, ServiceRegisterReply
, pContext
);
587 if ( err
== kDNSServiceErr_NoError
)
589 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
593 (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0);
595 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
596 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
597 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
598 SafeReleaseUTFChars( pEnv
, host
, hostStr
);
601 err
= kDNSServiceErr_NoMemory
;
606 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
*pEnv
, jobject pThis
,
607 jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
)
609 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
610 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
611 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
612 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "J");
613 OpContext
*pContext
= NULL
;
614 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
619 if ( contextField
!= 0)
620 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
621 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
622 return kDNSServiceErr_BadParam
;
624 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
625 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
627 err
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
);
628 if ( err
== kDNSServiceErr_NoError
)
630 (*pEnv
)->SetLongField(pEnv
, destObj
, recField
, (long) recRef
);
634 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
639 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv
*pEnv
, jobject pThis
,
640 jint flags
, jbyteArray rData
, jint ttl
)
642 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
643 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
644 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "J");
645 OpContext
*pContext
= NULL
;
646 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
649 DNSRecordRef recRef
= NULL
;
651 if ( ownerField
!= 0)
653 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
654 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
655 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "J");
656 if ( contextField
!= 0)
657 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, ownerObj
, contextField
);
660 recRef
= (DNSRecordRef
) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, recField
);
661 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
662 return kDNSServiceErr_BadParam
;
664 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
665 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
667 err
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
);
670 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
675 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv
*pEnv
, jobject pThis
)
677 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
678 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
679 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "J");
680 OpContext
*pContext
= NULL
;
681 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
682 DNSRecordRef recRef
= NULL
;
684 if ( ownerField
!= 0)
686 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
687 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
688 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "J");
689 if ( contextField
!= 0)
690 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, ownerObj
, contextField
);
693 recRef
= (DNSRecordRef
) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, recField
);
694 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
695 return kDNSServiceErr_BadParam
;
697 err
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0);
703 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv
*pEnv
, jobject pThis
)
705 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
706 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
707 OpContext
*pContext
= NULL
;
708 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
710 if ( contextField
!= 0)
711 pContext
= NewContext( pEnv
, pThis
, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
713 err
= kDNSServiceErr_BadParam
;
715 if ( pContext
!= NULL
)
717 err
= DNSServiceCreateConnection( &pContext
->ServiceRef
);
718 if ( err
== kDNSServiceErr_NoError
)
720 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
724 err
= kDNSServiceErr_NoMemory
;
729 struct RecordRegistrationRef
734 typedef struct RecordRegistrationRef RecordRegistrationRef
;
736 static void DNSSD_API
RegisterRecordReply( DNSServiceRef sdRef _UNUSED
,
737 DNSRecordRef recordRef _UNUSED
, DNSServiceFlags flags
,
738 DNSServiceErrorType errorCode
, void *context
)
740 RecordRegistrationRef
*regEnvelope
= (RecordRegistrationRef
*) context
;
741 OpContext
*pContext
= regEnvelope
->Context
;
743 SetupCallbackState( &pContext
->Env
);
745 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
747 if ( errorCode
== kDNSServiceErr_NoError
)
749 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
750 regEnvelope
->RecordObj
, flags
);
753 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
756 (*pContext
->Env
)->DeleteWeakGlobalRef( pContext
->Env
, regEnvelope
->RecordObj
);
759 TeardownCallbackState();
762 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv
*pEnv
, jobject pThis
,
763 jint flags
, jint ifIndex
, jstring fullname
, jint rrType
, jint rrClass
,
764 jbyteArray rData
, jint ttl
, jobject destObj
)
766 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
767 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
768 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
769 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "J");
770 const char *nameStr
= SafeGetUTFChars( pEnv
, fullname
);
771 OpContext
*pContext
= NULL
;
772 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
776 RecordRegistrationRef
*regEnvelope
;
778 if ( contextField
!= 0)
779 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
780 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
|| nameStr
== NULL
)
781 return kDNSServiceErr_BadParam
;
783 regEnvelope
= calloc( 1, sizeof *regEnvelope
);
784 if ( regEnvelope
== NULL
)
785 return kDNSServiceErr_NoMemory
;
786 regEnvelope
->Context
= pContext
;
787 regEnvelope
->RecordObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, destObj
); // must convert local ref to global to cache
789 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
790 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
792 err
= DNSServiceRegisterRecord( pContext
->ServiceRef
, &recRef
, flags
, ifIndex
,
793 nameStr
, rrType
, rrClass
, numBytes
, pBytes
, ttl
,
794 RegisterRecordReply
, regEnvelope
);
796 if ( err
== kDNSServiceErr_NoError
)
798 (*pEnv
)->SetLongField(pEnv
, destObj
, recField
, (long) recRef
);
802 if ( regEnvelope
->RecordObj
!= NULL
)
803 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, regEnvelope
->RecordObj
);
808 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
810 SafeReleaseUTFChars( pEnv
, fullname
, nameStr
);
816 static void DNSSD_API
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
817 DNSServiceErrorType errorCode
, const char *serviceName
,
818 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
,
819 const void *rdata
, uint32_t ttl
, void *context
)
821 OpContext
*pContext
= (OpContext
*) context
;
825 SetupCallbackState( &pContext
->Env
);
827 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&&
828 NULL
!= ( rDataObj
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
)))
830 if ( errorCode
== kDNSServiceErr_NoError
)
832 // Initialize rDataObj with contents of rdata
833 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
);
834 memcpy( pBytes
, rdata
, rdlen
);
835 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
);
837 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
838 pContext
->JavaObj
, flags
, interfaceIndex
,
839 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
840 rrtype
, rrclass
, rDataObj
, ttl
);
843 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
845 TeardownCallbackState();
848 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv
*pEnv
, jobject pThis
,
849 jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
)
851 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
852 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
853 OpContext
*pContext
= NULL
;
854 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
856 if ( contextField
!= 0)
857 pContext
= NewContext( pEnv
, pThis
, "queryAnswered",
858 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
860 err
= kDNSServiceErr_BadParam
;
862 if ( pContext
!= NULL
)
864 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
866 err
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,
867 rrtype
, rrclass
, ServiceQueryReply
, pContext
);
868 if ( err
== kDNSServiceErr_NoError
)
870 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
873 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
876 err
= kDNSServiceErr_NoMemory
;
882 static void DNSSD_API
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
883 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
885 OpContext
*pContext
= (OpContext
*) context
;
887 SetupCallbackState( &pContext
->Env
);
889 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
891 if ( errorCode
== kDNSServiceErr_NoError
)
893 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
894 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
895 pContext
->JavaObj
, flags
, interfaceIndex
,
896 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
899 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
901 TeardownCallbackState();
904 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv
*pEnv
, jobject pThis
,
905 jint flags
, jint ifIndex
)
907 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
908 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
909 OpContext
*pContext
= NULL
;
910 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
912 if ( contextField
!= 0)
913 pContext
= NewContext( pEnv
, pThis
, "domainFound",
914 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
916 err
= kDNSServiceErr_BadParam
;
918 if ( pContext
!= NULL
)
920 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
921 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
922 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
924 err
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,
925 DomainEnumReply
, pContext
);
926 if ( err
== kDNSServiceErr_NoError
)
928 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
932 err
= kDNSServiceErr_NoMemory
;
938 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
939 jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
)
941 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
942 const char *nameStr
= SafeGetUTFChars( pEnv
, serviceName
);
943 const char *regStr
= SafeGetUTFChars( pEnv
, regtype
);
944 const char *domStr
= SafeGetUTFChars( pEnv
, domain
);
945 char buff
[ kDNSServiceMaxDomainName
+ 1];
947 err
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
);
949 if ( err
== kDNSServiceErr_NoError
)
951 // pOut is expected to be a String[1] array.
952 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
));
955 SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
);
956 SafeReleaseUTFChars( pEnv
, regtype
, regStr
);
957 SafeReleaseUTFChars( pEnv
, domain
, domStr
);
962 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
963 jint flags
, jint ifIndex
, jstring fullName
,
964 jint rrtype
, jint rrclass
, jbyteArray rdata
)
968 const char *nameStr
= SafeGetUTFChars( pEnv
, fullName
);
970 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
);
971 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rdata
);
973 DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
);
976 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0);
978 SafeReleaseUTFChars( pEnv
, fullName
, nameStr
);
981 #define LOCAL_ONLY_NAME "loo"
983 JNIEXPORT jstring JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
986 char *p
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
];
988 if (ifIndex
!= (jint
) kDNSServiceInterfaceIndexLocalOnly
)
989 p
= if_indextoname( ifIndex
, nameBuff
);
991 return (*pEnv
)->NewStringUTF( pEnv
, p
);
995 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
998 uint32_t ifIndex
= kDNSServiceInterfaceIndexLocalOnly
;
999 const char *nameStr
= SafeGetUTFChars( pEnv
, ifName
);
1001 if (strcmp(nameStr
, LOCAL_ONLY_NAME
))
1002 ifIndex
= if_nametoindex( nameStr
);
1004 SafeReleaseUTFChars( pEnv
, ifName
, nameStr
);
1012 if_indextoname( DWORD ifIndex
, char * nameBuff
)
1014 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
1015 PIP_ADAPTER_INFO pAdapter
= NULL
;
1017 char * ifName
= NULL
;
1018 ULONG ulOutBufLen
= 0;
1020 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
1025 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
1027 if (pAdapterInfo
== NULL
)
1032 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
1034 if (dwRetVal
!= NO_ERROR
)
1039 pAdapter
= pAdapterInfo
;
1042 if (pAdapter
->Index
== ifIndex
)
1044 // It would be better if we passed in the length of nameBuff to this
1045 // function, so we would have absolute certainty that no buffer
1046 // overflows would occur. Buffer overflows *shouldn't* occur because
1047 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
1048 strcpy( nameBuff
, pAdapter
->AdapterName
);
1053 pAdapter
= pAdapter
->Next
;
1058 if (pAdapterInfo
!= NULL
)
1060 free( pAdapterInfo
);
1061 pAdapterInfo
= NULL
;
1069 if_nametoindex( const char * nameStr
)
1071 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
1072 PIP_ADAPTER_INFO pAdapter
= NULL
;
1075 ULONG ulOutBufLen
= 0;
1077 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
1082 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
1084 if (pAdapterInfo
== NULL
)
1089 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
1091 if (dwRetVal
!= NO_ERROR
)
1096 pAdapter
= pAdapterInfo
;
1099 if (strcmp(pAdapter
->AdapterName
, nameStr
) == 0)
1101 ifIndex
= pAdapter
->Index
;
1105 pAdapter
= pAdapter
->Next
;
1110 if (pAdapterInfo
!= NULL
)
1112 free( pAdapterInfo
);
1113 pAdapterInfo
= NULL
;
1121 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
1122 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
1123 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
1124 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
1125 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
1127 // NOT static -- otherwise the compiler may optimize it out
1128 // The "@(#) " pattern is a special prefix the "what" command looks for
1129 const char VersionString_SCCS
[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";