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 This file contains the platform support for DNSSD and related Java classes.
18 It is used to shim through to the underlying <dns_sd.h> API.
21 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
22 // callbacks automatically (as in the early Windows prototypes).
23 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
24 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
25 // (Invoking callbacks automatically on a different thread sounds attractive, but while
26 // the client gains by not needing to add an event source to its main event loop, it loses
27 // by being forced to deal with concurrency and locking, which can be a bigger burden.)
28 #ifndef AUTO_CALLBACKS
29 #define AUTO_CALLBACKS 0
36 #include <sys/types.h>
37 #include <sys/select.h>
39 #endif // AUTO_CALLBACKS
49 static char * win32_if_indextoname( DWORD ifIndex
, char * nameBuff
);
50 static DWORD
win32_if_nametoindex( const char * nameStr
);
51 #define if_indextoname win32_if_indextoname
52 #define if_nametoindex win32_if_nametoindex
53 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
55 #include <sys/socket.h>
59 // When compiling with "-Wshadow" set, including jni.h produces the following error:
60 // /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration
61 // To work around this, we use the preprocessor to map the identifier 'index', which appears harmlessly in function prototype declarations,
62 // to something 'jni_index', which doesn't conflict
63 #define index jni_index
64 #include "DNSSD.java.h"
69 // convenience definition
71 #define _UNUSED __attribute__ ((unused))
77 kInterfaceVersionOne
= 1,
78 kInterfaceVersionCurrent
// Must match version in .jar file
81 typedef struct OpContext OpContext
;
85 DNSServiceRef ServiceRef
;
93 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
95 JavaVM
*gJavaVM
= NULL
;
99 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv
*pEnv
, jclass cls
,
102 /* Ensure that caller & interface versions match. */
103 if ( callerVersion
!= kInterfaceVersionCurrent
)
104 return kDNSServiceErr_Incompatible
;
110 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
))
111 return kDNSServiceErr_BadState
;
115 // Set AppleDNSSD.hasAutoCallbacks
118 jboolean hasAutoC
= JNI_TRUE
;
120 jboolean hasAutoC
= JNI_FALSE
;
122 jfieldID hasAutoCField
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z");
123 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
);
126 return kDNSServiceErr_NoError
;
130 static const char* SafeGetUTFChars( JNIEnv
*pEnv
, jstring str
)
131 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
133 return str
!= NULL
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
;
136 static void SafeReleaseUTFChars( JNIEnv
*pEnv
, jstring str
, const char *buff
)
137 // Wrapper for JNI GetStringUTFChars() that handles null str.
140 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
);
145 static void SetupCallbackState( JNIEnv
**ppEnv
)
147 (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
);
150 static void TeardownCallbackState( void )
152 (*gJavaVM
)->DetachCurrentThread( gJavaVM
);
155 #else // AUTO_CALLBACKS
157 static void SetupCallbackState( JNIEnv
**ppEnv _UNUSED
)
159 // No setup necessary if ProcessResults() has been called
162 static void TeardownCallbackState( void )
164 // No teardown necessary if ProcessResults() has been called
166 #endif // AUTO_CALLBACKS
169 static OpContext
*NewContext( JNIEnv
*pEnv
, jobject owner
,
170 const char *callbackName
, const char *callbackSig
)
171 // Create and initialize a new OpContext.
173 OpContext
*pContext
= (OpContext
*) malloc( sizeof *pContext
);
175 if ( pContext
!= NULL
)
177 jfieldID clientField
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),
178 "fListener", "Lcom/apple/dnssd/BaseListener;");
180 pContext
->JavaObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
); // must convert local ref to global to cache;
181 pContext
->ClientObj
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
);
182 pContext
->ClientObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
); // must convert local ref to global to cache
183 pContext
->Callback
= (*pEnv
)->GetMethodID( pEnv
,
184 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
185 callbackName
, callbackSig
);
186 pContext
->Callback2
= NULL
; // not always used
193 static void ReportError( JNIEnv
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
)
194 // Invoke operationFailed() method on target with err.
196 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, target
);
197 jmethodID opFailed
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",
198 "(Lcom/apple/dnssd/DNSSDService;I)V");
200 (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
);
203 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv
*pEnv
, jobject pThis
)
204 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
206 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
207 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
209 if ( contextField
!= 0)
211 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
212 if ( pContext
!= NULL
)
214 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
215 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, 0);
216 if ( pContext
->ServiceRef
!= NULL
)
217 DNSServiceRefDeallocate( pContext
->ServiceRef
);
219 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
);
220 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
);
227 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv
*pEnv
, jobject pThis
)
228 /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
230 // BlockForData() not supported with AUTO_CALLBACKS
232 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
233 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
235 if ( contextField
!= 0)
237 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
238 if ( pContext
!= NULL
)
241 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
242 struct timeval timeout
= { 1, 0 };
244 FD_SET( sd
, &readFDs
);
246 // Q: Why do we poll here?
247 // A: Because there's no other thread-safe way to do it.
248 // Mac OS X terminates a select() call if you close one of the sockets it's listening on, but Linux does not,
249 // and arguably Linux is correct (See <http://www.ussg.iu.edu/hypermail/linux/kernel/0405.1/0418.html>)
250 // The problem is that the Mac OS X behaviour assumes that it's okay for one thread to close a socket while
251 // some other thread is monitoring that socket in select(), but the difficulty is that there's no general way
252 // to make that thread-safe, because there's no atomic way to enter select() and release a lock simultaneously.
253 // If we try to do this without holding any lock, then right as we jump to the select() routine,
254 // some other thread could stop our operation (thereby closing the socket),
255 // and then that thread (or even some third, unrelated thread)
256 // could do some other DNS-SD operation (or some other operation that opens a new file descriptor)
257 // and then we'd blindly resume our fall into the select() call, now blocking on a file descriptor
258 // that may coincidentally have the same numerical value, but is semantically unrelated
259 // to the true file descriptor we thought we were blocking on.
260 // We can't stop this race condition from happening, but at least if we wake up once a second we can detect
261 // when fNativeContext has gone to zero, and thereby discover that we were blocking on the wrong fd.
263 if (select( sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
) == 1) return(1);
266 #endif // !AUTO_CALLBACKS
271 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
*pEnv
, jobject pThis
)
272 /* Call through to DNSServiceProcessResult() while data remains on socket. */
274 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
276 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
277 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
278 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
279 DNSServiceErrorType err
= kDNSServiceErr_BadState
;
281 if ( pContext
!= NULL
)
283 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
285 struct timeval zeroTimeout
= { 0, 0 };
287 pContext
->Env
= pEnv
;
290 FD_SET( sd
, &readFDs
);
292 err
= kDNSServiceErr_NoError
;
293 if (0 < select(sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
))
295 err
= DNSServiceProcessResult(pContext
->ServiceRef
);
297 // We cannot touch any data structures associated with this operation!
298 // The DNSServiceProcessResult() routine should have invoked our callback,
299 // and our callback could have terminated the operation with op.stop();
300 // and that means HaltOperation() will have been called, which frees pContext.
301 // Basically, from here we just have to get out without touching any stale
302 // data structures that could blow up on us! Particularly, any attempt
303 // to loop here reading more results from the file descriptor is unsafe.
307 #endif // AUTO_CALLBACKS
311 static void DNSSD_API
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
312 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,
313 const char *replyDomain
, void *context
)
315 OpContext
*pContext
= (OpContext
*) context
;
317 SetupCallbackState( &pContext
->Env
);
319 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
321 if ( errorCode
== kDNSServiceErr_NoError
)
323 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
324 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
325 pContext
->JavaObj
, flags
, interfaceIndex
,
326 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
327 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
),
328 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
331 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
334 TeardownCallbackState();
337 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv
*pEnv
, jobject pThis
,
338 jint flags
, jint ifIndex
, jstring regType
, jstring domain
)
340 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
341 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
342 OpContext
*pContext
= NULL
;
343 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
345 if ( contextField
!= 0)
346 pContext
= NewContext( pEnv
, pThis
, "serviceFound",
347 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
349 err
= kDNSServiceErr_BadParam
;
351 if ( pContext
!= NULL
)
353 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
354 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
356 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
357 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
358 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
360 err
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
);
361 if ( err
== kDNSServiceErr_NoError
)
363 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
366 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
367 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
370 err
= kDNSServiceErr_NoMemory
;
376 static void DNSSD_API
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
377 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,
378 uint16_t port
, uint16_t txtLen
, const unsigned char *txtRecord
, void *context
)
380 OpContext
*pContext
= (OpContext
*) context
;
387 SetupCallbackState( &pContext
->Env
);
389 txtCls
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord");
390 txtCtor
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V");
392 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&& txtCtor
!= NULL
&&
393 NULL
!= ( txtBytes
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
)))
395 if ( errorCode
== kDNSServiceErr_NoError
)
397 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
398 // pattern into a number here.
399 port
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1];
401 // Initialize txtBytes with contents of txtRecord
402 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
);
403 memcpy( pBytes
, txtRecord
, txtLen
);
404 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
);
406 // Construct txtObj with txtBytes
407 txtObj
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
);
408 (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
);
410 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
411 pContext
->JavaObj
, flags
, interfaceIndex
,
412 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
),
413 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
),
417 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
420 TeardownCallbackState();
423 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
*pEnv
, jobject pThis
,
424 jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
)
426 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
427 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
428 OpContext
*pContext
= NULL
;
429 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
431 if ( contextField
!= 0)
432 pContext
= NewContext( pEnv
, pThis
, "serviceResolved",
433 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
435 err
= kDNSServiceErr_BadParam
;
437 if ( pContext
!= NULL
)
439 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
440 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
441 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
443 err
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,
444 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
);
445 if ( err
== kDNSServiceErr_NoError
)
447 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
450 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
451 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
452 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
455 err
= kDNSServiceErr_NoMemory
;
461 static void DNSSD_API
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,
462 DNSServiceErrorType errorCode
, const char *serviceName
,
463 const char *regType
, const char *domain
, void *context
)
465 OpContext
*pContext
= (OpContext
*) context
;
467 SetupCallbackState( &pContext
->Env
);
469 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
471 if ( errorCode
== kDNSServiceErr_NoError
)
473 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
474 pContext
->JavaObj
, flags
,
475 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
476 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
),
477 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
));
480 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
482 TeardownCallbackState();
485 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv
*pEnv
, jobject pThis
,
486 jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,
487 jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
)
489 //syslog(LOG_ERR, "BR");
490 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
491 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
492 OpContext
*pContext
= NULL
;
493 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
497 //syslog(LOG_ERR, "BR: contextField %d", contextField);
499 if ( contextField
!= 0)
500 pContext
= NewContext( pEnv
, pThis
, "serviceRegistered",
501 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
503 err
= kDNSServiceErr_BadParam
;
505 if ( pContext
!= NULL
)
507 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
508 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
509 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
510 const char *hostStr
= SafeGetUTFChars( pEnv
, host
);
512 //syslog(LOG_ERR, "BR: regStr %s", regStr);
514 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
515 // big-endian number into a 16-bit pattern here.
516 uint16_t portBits
= port
;
517 portBits
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1];
519 pBytes
= txtRecord
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
;
520 numBytes
= txtRecord
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0;
522 err
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,
523 domainStr
, hostStr
, portBits
,
524 numBytes
, pBytes
, ServiceRegisterReply
, pContext
);
525 if ( err
== kDNSServiceErr_NoError
)
527 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
531 (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0);
533 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
534 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
535 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
536 SafeReleaseUTFChars( pEnv
, host
, hostStr
);
539 err
= kDNSServiceErr_NoMemory
;
544 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
*pEnv
, jobject pThis
,
545 jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
)
547 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
548 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
549 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
550 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "J");
551 OpContext
*pContext
= NULL
;
552 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
557 if ( contextField
!= 0)
558 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
559 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
560 return kDNSServiceErr_BadParam
;
562 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
563 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
565 err
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
);
566 if ( err
== kDNSServiceErr_NoError
)
568 (*pEnv
)->SetLongField(pEnv
, destObj
, recField
, (long) recRef
);
572 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
577 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv
*pEnv
, jobject pThis
,
578 jint flags
, jbyteArray rData
, jint ttl
)
580 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
581 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
582 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "J");
583 OpContext
*pContext
= NULL
;
584 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
587 DNSRecordRef recRef
= NULL
;
589 if ( ownerField
!= 0)
591 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
592 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
593 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "J");
594 if ( contextField
!= 0)
595 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, ownerObj
, contextField
);
598 recRef
= (DNSRecordRef
) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, recField
);
599 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
600 return kDNSServiceErr_BadParam
;
602 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
603 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
605 err
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
);
608 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
613 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv
*pEnv
, jobject pThis
)
615 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
616 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
617 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "J");
618 OpContext
*pContext
= NULL
;
619 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
620 DNSRecordRef recRef
= NULL
;
622 if ( ownerField
!= 0)
624 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
625 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
626 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "J");
627 if ( contextField
!= 0)
628 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, ownerObj
, contextField
);
631 recRef
= (DNSRecordRef
) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, recField
);
632 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
633 return kDNSServiceErr_BadParam
;
635 err
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0);
641 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv
*pEnv
, jobject pThis
)
643 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
644 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
645 OpContext
*pContext
= NULL
;
646 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
648 if ( contextField
!= 0)
649 pContext
= NewContext( pEnv
, pThis
, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
651 err
= kDNSServiceErr_BadParam
;
653 if ( pContext
!= NULL
)
655 err
= DNSServiceCreateConnection( &pContext
->ServiceRef
);
656 if ( err
== kDNSServiceErr_NoError
)
658 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
662 err
= kDNSServiceErr_NoMemory
;
667 struct RecordRegistrationRef
672 typedef struct RecordRegistrationRef RecordRegistrationRef
;
674 static void DNSSD_API
RegisterRecordReply( DNSServiceRef sdRef _UNUSED
,
675 DNSRecordRef recordRef _UNUSED
, DNSServiceFlags flags
,
676 DNSServiceErrorType errorCode
, void *context
)
678 RecordRegistrationRef
*regEnvelope
= (RecordRegistrationRef
*) context
;
679 OpContext
*pContext
= regEnvelope
->Context
;
681 SetupCallbackState( &pContext
->Env
);
683 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
685 if ( errorCode
== kDNSServiceErr_NoError
)
687 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
688 regEnvelope
->RecordObj
, flags
);
691 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
694 (*pContext
->Env
)->DeleteWeakGlobalRef( pContext
->Env
, regEnvelope
->RecordObj
);
697 TeardownCallbackState();
700 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv
*pEnv
, jobject pThis
,
701 jint flags
, jint ifIndex
, jstring fullname
, jint rrType
, jint rrClass
,
702 jbyteArray rData
, jint ttl
, jobject destObj
)
704 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
705 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
706 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
707 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "J");
708 const char *nameStr
= SafeGetUTFChars( pEnv
, fullname
);
709 OpContext
*pContext
= NULL
;
710 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
714 RecordRegistrationRef
*regEnvelope
;
716 if ( contextField
!= 0)
717 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
718 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
|| nameStr
== NULL
)
719 return kDNSServiceErr_BadParam
;
721 regEnvelope
= calloc( 1, sizeof *regEnvelope
);
722 if ( regEnvelope
== NULL
)
723 return kDNSServiceErr_NoMemory
;
724 regEnvelope
->Context
= pContext
;
725 regEnvelope
->RecordObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, destObj
); // must convert local ref to global to cache
727 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
728 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
730 err
= DNSServiceRegisterRecord( pContext
->ServiceRef
, &recRef
, flags
, ifIndex
,
731 nameStr
, rrType
, rrClass
, numBytes
, pBytes
, ttl
,
732 RegisterRecordReply
, regEnvelope
);
734 if ( err
== kDNSServiceErr_NoError
)
736 (*pEnv
)->SetLongField(pEnv
, destObj
, recField
, (long) recRef
);
740 if ( regEnvelope
->RecordObj
!= NULL
)
741 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, regEnvelope
->RecordObj
);
746 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
748 SafeReleaseUTFChars( pEnv
, fullname
, nameStr
);
754 static void DNSSD_API
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
755 DNSServiceErrorType errorCode
, const char *serviceName
,
756 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
,
757 const void *rdata
, uint32_t ttl
, void *context
)
759 OpContext
*pContext
= (OpContext
*) context
;
763 SetupCallbackState( &pContext
->Env
);
765 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&&
766 NULL
!= ( rDataObj
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
)))
768 if ( errorCode
== kDNSServiceErr_NoError
)
770 // Initialize rDataObj with contents of rdata
771 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
);
772 memcpy( pBytes
, rdata
, rdlen
);
773 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
);
775 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
776 pContext
->JavaObj
, flags
, interfaceIndex
,
777 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
778 rrtype
, rrclass
, rDataObj
, ttl
);
781 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
783 TeardownCallbackState();
786 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv
*pEnv
, jobject pThis
,
787 jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
)
789 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
790 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
791 OpContext
*pContext
= NULL
;
792 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
794 if ( contextField
!= 0)
795 pContext
= NewContext( pEnv
, pThis
, "queryAnswered",
796 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
798 err
= kDNSServiceErr_BadParam
;
800 if ( pContext
!= NULL
)
802 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
804 err
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,
805 rrtype
, rrclass
, ServiceQueryReply
, pContext
);
806 if ( err
== kDNSServiceErr_NoError
)
808 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
811 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
814 err
= kDNSServiceErr_NoMemory
;
820 static void DNSSD_API
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
821 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
823 OpContext
*pContext
= (OpContext
*) context
;
825 SetupCallbackState( &pContext
->Env
);
827 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
829 if ( errorCode
== kDNSServiceErr_NoError
)
831 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
832 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
833 pContext
->JavaObj
, flags
, interfaceIndex
,
834 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
837 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
839 TeardownCallbackState();
842 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv
*pEnv
, jobject pThis
,
843 jint flags
, jint ifIndex
)
845 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
846 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
847 OpContext
*pContext
= NULL
;
848 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
850 if ( contextField
!= 0)
851 pContext
= NewContext( pEnv
, pThis
, "domainFound",
852 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
854 err
= kDNSServiceErr_BadParam
;
856 if ( pContext
!= NULL
)
858 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
859 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
860 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
862 err
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,
863 DomainEnumReply
, pContext
);
864 if ( err
== kDNSServiceErr_NoError
)
866 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
870 err
= kDNSServiceErr_NoMemory
;
876 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
877 jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
)
879 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
880 const char *nameStr
= SafeGetUTFChars( pEnv
, serviceName
);
881 const char *regStr
= SafeGetUTFChars( pEnv
, regtype
);
882 const char *domStr
= SafeGetUTFChars( pEnv
, domain
);
883 char buff
[ kDNSServiceMaxDomainName
+ 1];
885 err
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
);
887 if ( err
== kDNSServiceErr_NoError
)
889 // pOut is expected to be a String[1] array.
890 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
));
893 SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
);
894 SafeReleaseUTFChars( pEnv
, regtype
, regStr
);
895 SafeReleaseUTFChars( pEnv
, domain
, domStr
);
900 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
901 jint flags
, jint ifIndex
, jstring fullName
,
902 jint rrtype
, jint rrclass
, jbyteArray rdata
)
906 const char *nameStr
= SafeGetUTFChars( pEnv
, fullName
);
908 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
);
909 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rdata
);
911 DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
);
914 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0);
916 SafeReleaseUTFChars( pEnv
, fullName
, nameStr
);
919 #define LOCAL_ONLY_NAME "loo"
920 #define P2P_NAME "p2p"
922 JNIEXPORT jstring JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
925 char *p
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
];
927 if (ifIndex
== (jint
) kDNSServiceInterfaceIndexP2P
)
929 else if (ifIndex
!= (jint
) kDNSServiceInterfaceIndexLocalOnly
)
930 p
= if_indextoname( ifIndex
, nameBuff
);
932 return (*pEnv
)->NewStringUTF( pEnv
, p
);
936 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
939 uint32_t ifIndex
= kDNSServiceInterfaceIndexLocalOnly
;
940 const char *nameStr
= SafeGetUTFChars( pEnv
, ifName
);
942 if (strcmp(nameStr
, P2P_NAME
) == 0)
943 ifIndex
= kDNSServiceInterfaceIndexP2P
;
944 else if (strcmp(nameStr
, LOCAL_ONLY_NAME
))
945 ifIndex
= if_nametoindex( nameStr
);
947 SafeReleaseUTFChars( pEnv
, ifName
, nameStr
);
955 win32_if_indextoname( DWORD ifIndex
, char * nameBuff
)
957 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
958 PIP_ADAPTER_INFO pAdapter
= NULL
;
960 char * ifName
= NULL
;
961 ULONG ulOutBufLen
= 0;
963 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
968 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
970 if (pAdapterInfo
== NULL
)
975 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
977 if (dwRetVal
!= NO_ERROR
)
982 pAdapter
= pAdapterInfo
;
985 if (pAdapter
->Index
== ifIndex
)
987 // It would be better if we passed in the length of nameBuff to this
988 // function, so we would have absolute certainty that no buffer
989 // overflows would occur. Buffer overflows *shouldn't* occur because
990 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
991 strcpy( nameBuff
, pAdapter
->AdapterName
);
996 pAdapter
= pAdapter
->Next
;
1001 if (pAdapterInfo
!= NULL
)
1003 free( pAdapterInfo
);
1004 pAdapterInfo
= NULL
;
1012 win32_if_nametoindex( const char * nameStr
)
1014 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
1015 PIP_ADAPTER_INFO pAdapter
= 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 (strcmp(pAdapter
->AdapterName
, nameStr
) == 0)
1044 ifIndex
= pAdapter
->Index
;
1048 pAdapter
= pAdapter
->Next
;
1053 if (pAdapterInfo
!= NULL
)
1055 free( pAdapterInfo
);
1056 pAdapterInfo
= NULL
;
1064 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
1065 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
1066 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
1067 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
1068 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
1070 // NOT static -- otherwise the compiler may optimize it out
1071 // The "@(#) " pattern is a special prefix the "what" command looks for
1072 #ifndef MDNS_VERSIONSTR_NODTS
1073 const char VersionString_SCCS
[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
1075 const char VersionString_SCCS
[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion
);