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 * if_indextoname( DWORD ifIndex
, char * nameBuff
);
50 static DWORD
if_nametoindex( const char * nameStr
);
51 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
53 #include <sys/socket.h>
57 // When compiling with "-Wshadow" set, including jni.h produces the following error:
58 // /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration
59 // To work around this, we use the preprocessor to map the identifier 'index', which appears harmlessly in function prototype declarations,
60 // to something 'jni_index', which doesn't conflict
61 #define index jni_index
62 #include "DNSSD.java.h"
67 // convenience definition
69 #define _UNUSED __attribute__ ((unused))
75 kInterfaceVersionOne
= 1,
76 kInterfaceVersionCurrent
// Must match version in .jar file
79 typedef struct OpContext OpContext
;
83 DNSServiceRef ServiceRef
;
91 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
93 JavaVM
*gJavaVM
= NULL
;
97 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv
*pEnv
, jclass cls
,
100 /* Ensure that caller & interface versions match. */
101 if ( callerVersion
!= kInterfaceVersionCurrent
)
102 return kDNSServiceErr_Incompatible
;
108 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM
, 1, &numVMs
))
109 return kDNSServiceErr_BadState
;
113 // Set AppleDNSSD.hasAutoCallbacks
116 jboolean hasAutoC
= JNI_TRUE
;
118 jboolean hasAutoC
= JNI_FALSE
;
120 jfieldID hasAutoCField
= (*pEnv
)->GetStaticFieldID( pEnv
, cls
, "hasAutoCallbacks", "Z");
121 (*pEnv
)->SetStaticBooleanField( pEnv
, cls
, hasAutoCField
, hasAutoC
);
124 return kDNSServiceErr_NoError
;
128 static const char* SafeGetUTFChars( JNIEnv
*pEnv
, jstring str
)
129 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
131 return str
!= NULL
? (*pEnv
)->GetStringUTFChars( pEnv
, str
, 0) : NULL
;
134 static void SafeReleaseUTFChars( JNIEnv
*pEnv
, jstring str
, const char *buff
)
135 // Wrapper for JNI GetStringUTFChars() that handles null str.
138 (*pEnv
)->ReleaseStringUTFChars( pEnv
, str
, buff
);
143 static void SetupCallbackState( JNIEnv
**ppEnv
)
145 (*gJavaVM
)->AttachCurrentThread( gJavaVM
, (void**) ppEnv
, NULL
);
148 static void TeardownCallbackState( void )
150 (*gJavaVM
)->DetachCurrentThread( gJavaVM
);
153 #else // AUTO_CALLBACKS
155 static void SetupCallbackState( JNIEnv
**ppEnv _UNUSED
)
157 // No setup necessary if ProcessResults() has been called
160 static void TeardownCallbackState( void )
162 // No teardown necessary if ProcessResults() has been called
164 #endif // AUTO_CALLBACKS
167 static OpContext
*NewContext( JNIEnv
*pEnv
, jobject owner
,
168 const char *callbackName
, const char *callbackSig
)
169 // Create and initialize a new OpContext.
171 OpContext
*pContext
= (OpContext
*) malloc( sizeof *pContext
);
173 if ( pContext
!= NULL
)
175 jfieldID clientField
= (*pEnv
)->GetFieldID( pEnv
, (*pEnv
)->GetObjectClass( pEnv
, owner
),
176 "fListener", "Lcom/apple/dnssd/BaseListener;");
178 pContext
->JavaObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, owner
); // must convert local ref to global to cache;
179 pContext
->ClientObj
= (*pEnv
)->GetObjectField( pEnv
, owner
, clientField
);
180 pContext
->ClientObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, pContext
->ClientObj
); // must convert local ref to global to cache
181 pContext
->Callback
= (*pEnv
)->GetMethodID( pEnv
,
182 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
183 callbackName
, callbackSig
);
184 pContext
->Callback2
= NULL
; // not always used
191 static void ReportError( JNIEnv
*pEnv
, jobject target
, jobject service
, DNSServiceErrorType err
)
192 // Invoke operationFailed() method on target with err.
194 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, target
);
195 jmethodID opFailed
= (*pEnv
)->GetMethodID( pEnv
, cls
, "operationFailed",
196 "(Lcom/apple/dnssd/DNSSDService;I)V");
198 (*pEnv
)->CallVoidMethod( pEnv
, target
, opFailed
, service
, err
);
201 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv
*pEnv
, jobject pThis
)
202 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
204 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
205 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
207 if ( contextField
!= 0)
209 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
210 if ( pContext
!= NULL
)
212 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
213 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, 0);
214 if ( pContext
->ServiceRef
!= NULL
)
215 DNSServiceRefDeallocate( pContext
->ServiceRef
);
217 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->JavaObj
);
218 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, pContext
->ClientObj
);
225 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv
*pEnv
, jobject pThis
)
226 /* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
228 // BlockForData() not supported with AUTO_CALLBACKS
230 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
231 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
233 if ( contextField
!= 0)
235 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
236 if ( pContext
!= NULL
)
239 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
240 struct timeval timeout
= { 1, 0 };
242 FD_SET( sd
, &readFDs
);
244 // Q: Why do we poll here?
245 // A: Because there's no other thread-safe way to do it.
246 // Mac OS X terminates a select() call if you close one of the sockets it's listening on, but Linux does not,
247 // and arguably Linux is correct (See <http://www.ussg.iu.edu/hypermail/linux/kernel/0405.1/0418.html>)
248 // The problem is that the Mac OS X behaviour assumes that it's okay for one thread to close a socket while
249 // some other thread is monitoring that socket in select(), but the difficulty is that there's no general way
250 // to make that thread-safe, because there's no atomic way to enter select() and release a lock simultaneously.
251 // If we try to do this without holding any lock, then right as we jump to the select() routine,
252 // some other thread could stop our operation (thereby closing the socket),
253 // and then that thread (or even some third, unrelated thread)
254 // could do some other DNS-SD operation (or some other operation that opens a new file descriptor)
255 // and then we'd blindly resume our fall into the select() call, now blocking on a file descriptor
256 // that may coincidentally have the same numerical value, but is semantically unrelated
257 // to the true file descriptor we thought we were blocking on.
258 // We can't stop this race condition from happening, but at least if we wake up once a second we can detect
259 // when fNativeContext has gone to zero, and thereby discover that we were blocking on the wrong fd.
261 if (select( sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &timeout
) == 1) return(1);
264 #endif // !AUTO_CALLBACKS
269 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv
*pEnv
, jobject pThis
)
270 /* Call through to DNSServiceProcessResult() while data remains on socket. */
272 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
274 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
275 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
276 OpContext
*pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
277 DNSServiceErrorType err
= kDNSServiceErr_BadState
;
279 if ( pContext
!= NULL
)
281 int sd
= DNSServiceRefSockFD( pContext
->ServiceRef
);
283 struct timeval zeroTimeout
= { 0, 0 };
285 pContext
->Env
= pEnv
;
288 FD_SET( sd
, &readFDs
);
290 err
= kDNSServiceErr_NoError
;
291 if (0 < select(sd
+ 1, &readFDs
, (fd_set
*) NULL
, (fd_set
*) NULL
, &zeroTimeout
))
293 err
= DNSServiceProcessResult(pContext
->ServiceRef
);
295 // We cannot touch any data structures associated with this operation!
296 // The DNSServiceProcessResult() routine should have invoked our callback,
297 // and our callback could have terminated the operation with op.stop();
298 // and that means HaltOperation() will have been called, which frees pContext.
299 // Basically, from here we just have to get out without touching any stale
300 // data structures that could blow up on us! Particularly, any attempt
301 // to loop here reading more results from the file descriptor is unsafe.
305 #endif // AUTO_CALLBACKS
309 static void DNSSD_API
ServiceBrowseReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
310 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
,
311 const char *replyDomain
, void *context
)
313 OpContext
*pContext
= (OpContext
*) context
;
315 SetupCallbackState( &pContext
->Env
);
317 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
319 if ( errorCode
== kDNSServiceErr_NoError
)
321 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
322 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
323 pContext
->JavaObj
, flags
, interfaceIndex
,
324 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
325 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regtype
),
326 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
329 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
332 TeardownCallbackState();
335 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv
*pEnv
, jobject pThis
,
336 jint flags
, jint ifIndex
, jstring regType
, jstring domain
)
338 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
339 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
340 OpContext
*pContext
= NULL
;
341 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
343 if ( contextField
!= 0)
344 pContext
= NewContext( pEnv
, pThis
, "serviceFound",
345 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
347 err
= kDNSServiceErr_BadParam
;
349 if ( pContext
!= NULL
)
351 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
352 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
354 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
355 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
356 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
358 err
= DNSServiceBrowse( &pContext
->ServiceRef
, flags
, ifIndex
, regStr
, domainStr
, ServiceBrowseReply
, pContext
);
359 if ( err
== kDNSServiceErr_NoError
)
361 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
364 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
365 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
368 err
= kDNSServiceErr_NoMemory
;
374 static void DNSSD_API
ServiceResolveReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
375 DNSServiceErrorType errorCode
, const char *fullname
, const char *hosttarget
,
376 uint16_t port
, uint16_t txtLen
, const unsigned char *txtRecord
, void *context
)
378 OpContext
*pContext
= (OpContext
*) context
;
385 SetupCallbackState( &pContext
->Env
);
387 txtCls
= (*pContext
->Env
)->FindClass( pContext
->Env
, "com/apple/dnssd/TXTRecord");
388 txtCtor
= (*pContext
->Env
)->GetMethodID( pContext
->Env
, txtCls
, "<init>", "([B)V");
390 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&& txtCtor
!= NULL
&&
391 NULL
!= ( txtBytes
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, txtLen
)))
393 if ( errorCode
== kDNSServiceErr_NoError
)
395 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
396 // pattern into a number here.
397 port
= ( ((unsigned char*) &port
)[0] << 8) | ((unsigned char*) &port
)[1];
399 // Initialize txtBytes with contents of txtRecord
400 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, txtBytes
, NULL
);
401 memcpy( pBytes
, txtRecord
, txtLen
);
402 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, txtBytes
, pBytes
, JNI_COMMIT
);
404 // Construct txtObj with txtBytes
405 txtObj
= (*pContext
->Env
)->NewObject( pContext
->Env
, txtCls
, txtCtor
, txtBytes
);
406 (*pContext
->Env
)->DeleteLocalRef( pContext
->Env
, txtBytes
);
408 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
409 pContext
->JavaObj
, flags
, interfaceIndex
,
410 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, fullname
),
411 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, hosttarget
),
415 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
418 TeardownCallbackState();
421 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv
*pEnv
, jobject pThis
,
422 jint flags
, jint ifIndex
, jstring serviceName
, jstring regType
, jstring domain
)
424 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
425 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
426 OpContext
*pContext
= NULL
;
427 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
429 if ( contextField
!= 0)
430 pContext
= NewContext( pEnv
, pThis
, "serviceResolved",
431 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
433 err
= kDNSServiceErr_BadParam
;
435 if ( pContext
!= NULL
)
437 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
438 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
439 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
441 err
= DNSServiceResolve( &pContext
->ServiceRef
, flags
, ifIndex
,
442 servStr
, regStr
, domainStr
, ServiceResolveReply
, pContext
);
443 if ( err
== kDNSServiceErr_NoError
)
445 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
448 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
449 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
450 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
453 err
= kDNSServiceErr_NoMemory
;
459 static void DNSSD_API
ServiceRegisterReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
,
460 DNSServiceErrorType errorCode
, const char *serviceName
,
461 const char *regType
, const char *domain
, void *context
)
463 OpContext
*pContext
= (OpContext
*) context
;
465 SetupCallbackState( &pContext
->Env
);
467 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
469 if ( errorCode
== kDNSServiceErr_NoError
)
471 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
472 pContext
->JavaObj
, flags
,
473 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
474 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, regType
),
475 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, domain
));
478 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
480 TeardownCallbackState();
483 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv
*pEnv
, jobject pThis
,
484 jint ifIndex
, jint flags
, jstring serviceName
, jstring regType
,
485 jstring domain
, jstring host
, jint port
, jbyteArray txtRecord
)
487 //syslog(LOG_ERR, "BR");
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
;
495 //syslog(LOG_ERR, "BR: contextField %d", contextField);
497 if ( contextField
!= 0)
498 pContext
= NewContext( pEnv
, pThis
, "serviceRegistered",
499 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
501 err
= kDNSServiceErr_BadParam
;
503 if ( pContext
!= NULL
)
505 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
506 const char *regStr
= SafeGetUTFChars( pEnv
, regType
);
507 const char *domainStr
= SafeGetUTFChars( pEnv
, domain
);
508 const char *hostStr
= SafeGetUTFChars( pEnv
, host
);
510 //syslog(LOG_ERR, "BR: regStr %s", regStr);
512 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
513 // big-endian number into a 16-bit pattern here.
514 uint16_t portBits
= port
;
515 portBits
= ( ((unsigned char*) &portBits
)[0] << 8) | ((unsigned char*) &portBits
)[1];
517 pBytes
= txtRecord
? (*pEnv
)->GetByteArrayElements( pEnv
, txtRecord
, NULL
) : NULL
;
518 numBytes
= txtRecord
? (*pEnv
)->GetArrayLength( pEnv
, txtRecord
) : 0;
520 err
= DNSServiceRegister( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
, regStr
,
521 domainStr
, hostStr
, portBits
,
522 numBytes
, pBytes
, ServiceRegisterReply
, pContext
);
523 if ( err
== kDNSServiceErr_NoError
)
525 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
529 (*pEnv
)->ReleaseByteArrayElements( pEnv
, txtRecord
, pBytes
, 0);
531 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
532 SafeReleaseUTFChars( pEnv
, regType
, regStr
);
533 SafeReleaseUTFChars( pEnv
, domain
, domainStr
);
534 SafeReleaseUTFChars( pEnv
, host
, hostStr
);
537 err
= kDNSServiceErr_NoMemory
;
542 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv
*pEnv
, jobject pThis
,
543 jint flags
, jint rrType
, jbyteArray rData
, jint ttl
, jobject destObj
)
545 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
546 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
547 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
548 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "J");
549 OpContext
*pContext
= NULL
;
550 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
555 if ( contextField
!= 0)
556 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
557 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
558 return kDNSServiceErr_BadParam
;
560 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
561 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
563 err
= DNSServiceAddRecord( pContext
->ServiceRef
, &recRef
, flags
, rrType
, numBytes
, pBytes
, ttl
);
564 if ( err
== kDNSServiceErr_NoError
)
566 (*pEnv
)->SetLongField(pEnv
, destObj
, recField
, (long) recRef
);
570 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
575 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv
*pEnv
, jobject pThis
,
576 jint flags
, jbyteArray rData
, jint ttl
)
578 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
579 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
580 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "J");
581 OpContext
*pContext
= NULL
;
582 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
585 DNSRecordRef recRef
= NULL
;
587 if ( ownerField
!= 0)
589 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
590 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
591 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "J");
592 if ( contextField
!= 0)
593 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, ownerObj
, contextField
);
596 recRef
= (DNSRecordRef
) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, recField
);
597 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
598 return kDNSServiceErr_BadParam
;
600 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
601 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
603 err
= DNSServiceUpdateRecord( pContext
->ServiceRef
, recRef
, flags
, numBytes
, pBytes
, ttl
);
606 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
611 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv
*pEnv
, jobject pThis
)
613 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
614 jfieldID ownerField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fOwner", "Lcom/apple/dnssd/AppleService;");
615 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fRecord", "J");
616 OpContext
*pContext
= NULL
;
617 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
618 DNSRecordRef recRef
= NULL
;
620 if ( ownerField
!= 0)
622 jobject ownerObj
= (*pEnv
)->GetObjectField( pEnv
, pThis
, ownerField
);
623 jclass ownerClass
= (*pEnv
)->GetObjectClass( pEnv
, ownerObj
);
624 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, ownerClass
, "fNativeContext", "J");
625 if ( contextField
!= 0)
626 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, ownerObj
, contextField
);
629 recRef
= (DNSRecordRef
) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, recField
);
630 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
)
631 return kDNSServiceErr_BadParam
;
633 err
= DNSServiceRemoveRecord( pContext
->ServiceRef
, recRef
, 0);
639 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv
*pEnv
, jobject pThis
)
641 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
642 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
643 OpContext
*pContext
= NULL
;
644 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
646 if ( contextField
!= 0)
647 pContext
= NewContext( pEnv
, pThis
, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
649 err
= kDNSServiceErr_BadParam
;
651 if ( pContext
!= NULL
)
653 err
= DNSServiceCreateConnection( &pContext
->ServiceRef
);
654 if ( err
== kDNSServiceErr_NoError
)
656 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
660 err
= kDNSServiceErr_NoMemory
;
665 struct RecordRegistrationRef
670 typedef struct RecordRegistrationRef RecordRegistrationRef
;
672 static void DNSSD_API
RegisterRecordReply( DNSServiceRef sdRef _UNUSED
,
673 DNSRecordRef recordRef _UNUSED
, DNSServiceFlags flags
,
674 DNSServiceErrorType errorCode
, void *context
)
676 RecordRegistrationRef
*regEnvelope
= (RecordRegistrationRef
*) context
;
677 OpContext
*pContext
= regEnvelope
->Context
;
679 SetupCallbackState( &pContext
->Env
);
681 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
683 if ( errorCode
== kDNSServiceErr_NoError
)
685 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
686 regEnvelope
->RecordObj
, flags
);
689 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
692 (*pContext
->Env
)->DeleteWeakGlobalRef( pContext
->Env
, regEnvelope
->RecordObj
);
695 TeardownCallbackState();
698 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv
*pEnv
, jobject pThis
,
699 jint flags
, jint ifIndex
, jstring fullname
, jint rrType
, jint rrClass
,
700 jbyteArray rData
, jint ttl
, jobject destObj
)
702 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
703 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
704 jclass destCls
= (*pEnv
)->GetObjectClass( pEnv
, destObj
);
705 jfieldID recField
= (*pEnv
)->GetFieldID( pEnv
, destCls
, "fRecord", "J");
706 const char *nameStr
= SafeGetUTFChars( pEnv
, fullname
);
707 OpContext
*pContext
= NULL
;
708 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
712 RecordRegistrationRef
*regEnvelope
;
714 if ( contextField
!= 0)
715 pContext
= (OpContext
*) (long) (*pEnv
)->GetLongField(pEnv
, pThis
, contextField
);
716 if ( pContext
== NULL
|| pContext
->ServiceRef
== NULL
|| nameStr
== NULL
)
717 return kDNSServiceErr_BadParam
;
719 regEnvelope
= calloc( 1, sizeof *regEnvelope
);
720 if ( regEnvelope
== NULL
)
721 return kDNSServiceErr_NoMemory
;
722 regEnvelope
->Context
= pContext
;
723 regEnvelope
->RecordObj
= (*pEnv
)->NewWeakGlobalRef( pEnv
, destObj
); // must convert local ref to global to cache
725 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rData
, NULL
);
726 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rData
);
728 err
= DNSServiceRegisterRecord( pContext
->ServiceRef
, &recRef
, flags
, ifIndex
,
729 nameStr
, rrType
, rrClass
, numBytes
, pBytes
, ttl
,
730 RegisterRecordReply
, regEnvelope
);
732 if ( err
== kDNSServiceErr_NoError
)
734 (*pEnv
)->SetLongField(pEnv
, destObj
, recField
, (long) recRef
);
738 if ( regEnvelope
->RecordObj
!= NULL
)
739 (*pEnv
)->DeleteWeakGlobalRef( pEnv
, regEnvelope
->RecordObj
);
744 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rData
, pBytes
, 0);
746 SafeReleaseUTFChars( pEnv
, fullname
, nameStr
);
752 static void DNSSD_API
ServiceQueryReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
753 DNSServiceErrorType errorCode
, const char *serviceName
,
754 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
,
755 const void *rdata
, uint32_t ttl
, void *context
)
757 OpContext
*pContext
= (OpContext
*) context
;
761 SetupCallbackState( &pContext
->Env
);
763 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
&&
764 NULL
!= ( rDataObj
= (*pContext
->Env
)->NewByteArray( pContext
->Env
, rdlen
)))
766 if ( errorCode
== kDNSServiceErr_NoError
)
768 // Initialize rDataObj with contents of rdata
769 pBytes
= (*pContext
->Env
)->GetByteArrayElements( pContext
->Env
, rDataObj
, NULL
);
770 memcpy( pBytes
, rdata
, rdlen
);
771 (*pContext
->Env
)->ReleaseByteArrayElements( pContext
->Env
, rDataObj
, pBytes
, JNI_COMMIT
);
773 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
, pContext
->Callback
,
774 pContext
->JavaObj
, flags
, interfaceIndex
,
775 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, serviceName
),
776 rrtype
, rrclass
, rDataObj
, ttl
);
779 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
781 TeardownCallbackState();
784 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv
*pEnv
, jobject pThis
,
785 jint flags
, jint ifIndex
, jstring serviceName
, jint rrtype
, jint rrclass
)
787 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
788 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
789 OpContext
*pContext
= NULL
;
790 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
792 if ( contextField
!= 0)
793 pContext
= NewContext( pEnv
, pThis
, "queryAnswered",
794 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
796 err
= kDNSServiceErr_BadParam
;
798 if ( pContext
!= NULL
)
800 const char *servStr
= SafeGetUTFChars( pEnv
, serviceName
);
802 err
= DNSServiceQueryRecord( &pContext
->ServiceRef
, flags
, ifIndex
, servStr
,
803 rrtype
, rrclass
, ServiceQueryReply
, pContext
);
804 if ( err
== kDNSServiceErr_NoError
)
806 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
809 SafeReleaseUTFChars( pEnv
, serviceName
, servStr
);
812 err
= kDNSServiceErr_NoMemory
;
818 static void DNSSD_API
DomainEnumReply( DNSServiceRef sdRef _UNUSED
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
819 DNSServiceErrorType errorCode
, const char *replyDomain
, void *context
)
821 OpContext
*pContext
= (OpContext
*) context
;
823 SetupCallbackState( &pContext
->Env
);
825 if ( pContext
->ClientObj
!= NULL
&& pContext
->Callback
!= NULL
)
827 if ( errorCode
== kDNSServiceErr_NoError
)
829 (*pContext
->Env
)->CallVoidMethod( pContext
->Env
, pContext
->ClientObj
,
830 ( flags
& kDNSServiceFlagsAdd
) != 0 ? pContext
->Callback
: pContext
->Callback2
,
831 pContext
->JavaObj
, flags
, interfaceIndex
,
832 (*pContext
->Env
)->NewStringUTF( pContext
->Env
, replyDomain
));
835 ReportError( pContext
->Env
, pContext
->ClientObj
, pContext
->JavaObj
, errorCode
);
837 TeardownCallbackState();
840 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv
*pEnv
, jobject pThis
,
841 jint flags
, jint ifIndex
)
843 jclass cls
= (*pEnv
)->GetObjectClass( pEnv
, pThis
);
844 jfieldID contextField
= (*pEnv
)->GetFieldID( pEnv
, cls
, "fNativeContext", "J");
845 OpContext
*pContext
= NULL
;
846 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
848 if ( contextField
!= 0)
849 pContext
= NewContext( pEnv
, pThis
, "domainFound",
850 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
852 err
= kDNSServiceErr_BadParam
;
854 if ( pContext
!= NULL
)
856 pContext
->Callback2
= (*pEnv
)->GetMethodID( pEnv
,
857 (*pEnv
)->GetObjectClass( pEnv
, pContext
->ClientObj
),
858 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
860 err
= DNSServiceEnumerateDomains( &pContext
->ServiceRef
, flags
, ifIndex
,
861 DomainEnumReply
, pContext
);
862 if ( err
== kDNSServiceErr_NoError
)
864 (*pEnv
)->SetLongField(pEnv
, pThis
, contextField
, (long) pContext
);
868 err
= kDNSServiceErr_NoMemory
;
874 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
875 jstring serviceName
, jstring regtype
, jstring domain
, jobjectArray pOut
)
877 DNSServiceErrorType err
= kDNSServiceErr_NoError
;
878 const char *nameStr
= SafeGetUTFChars( pEnv
, serviceName
);
879 const char *regStr
= SafeGetUTFChars( pEnv
, regtype
);
880 const char *domStr
= SafeGetUTFChars( pEnv
, domain
);
881 char buff
[ kDNSServiceMaxDomainName
+ 1];
883 err
= DNSServiceConstructFullName( buff
, nameStr
, regStr
, domStr
);
885 if ( err
== kDNSServiceErr_NoError
)
887 // pOut is expected to be a String[1] array.
888 (*pEnv
)->SetObjectArrayElement( pEnv
, pOut
, 0, (*pEnv
)->NewStringUTF( pEnv
, buff
));
891 SafeReleaseUTFChars( pEnv
, serviceName
, nameStr
);
892 SafeReleaseUTFChars( pEnv
, regtype
, regStr
);
893 SafeReleaseUTFChars( pEnv
, domain
, domStr
);
898 JNIEXPORT
void JNICALL
Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
899 jint flags
, jint ifIndex
, jstring fullName
,
900 jint rrtype
, jint rrclass
, jbyteArray rdata
)
904 const char *nameStr
= SafeGetUTFChars( pEnv
, fullName
);
906 pBytes
= (*pEnv
)->GetByteArrayElements( pEnv
, rdata
, NULL
);
907 numBytes
= (*pEnv
)->GetArrayLength( pEnv
, rdata
);
909 DNSServiceReconfirmRecord( flags
, ifIndex
, nameStr
, rrtype
, rrclass
, numBytes
, pBytes
);
912 (*pEnv
)->ReleaseByteArrayElements( pEnv
, rdata
, pBytes
, 0);
914 SafeReleaseUTFChars( pEnv
, fullName
, nameStr
);
917 #define LOCAL_ONLY_NAME "loo"
918 #define P2P_NAME "p2p"
920 JNIEXPORT jstring JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
923 char *p
= LOCAL_ONLY_NAME
, nameBuff
[IF_NAMESIZE
];
925 if (ifIndex
== (jint
) kDNSServiceInterfaceIndexP2P
)
927 else if (ifIndex
!= (jint
) kDNSServiceInterfaceIndexLocalOnly
)
928 p
= if_indextoname( ifIndex
, nameBuff
);
930 return (*pEnv
)->NewStringUTF( pEnv
, p
);
934 JNIEXPORT jint JNICALL
Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
*pEnv
, jobject pThis _UNUSED
,
937 uint32_t ifIndex
= kDNSServiceInterfaceIndexLocalOnly
;
938 const char *nameStr
= SafeGetUTFChars( pEnv
, ifName
);
940 if (strcmp(nameStr
, P2P_NAME
) == 0)
941 ifIndex
= kDNSServiceInterfaceIndexP2P
;
942 else if (strcmp(nameStr
, LOCAL_ONLY_NAME
))
943 ifIndex
= if_nametoindex( nameStr
);
945 SafeReleaseUTFChars( pEnv
, ifName
, nameStr
);
953 if_indextoname( DWORD ifIndex
, char * nameBuff
)
955 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
956 PIP_ADAPTER_INFO pAdapter
= NULL
;
958 char * ifName
= NULL
;
959 ULONG ulOutBufLen
= 0;
961 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
966 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
968 if (pAdapterInfo
== NULL
)
973 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
975 if (dwRetVal
!= NO_ERROR
)
980 pAdapter
= pAdapterInfo
;
983 if (pAdapter
->Index
== ifIndex
)
985 // It would be better if we passed in the length of nameBuff to this
986 // function, so we would have absolute certainty that no buffer
987 // overflows would occur. Buffer overflows *shouldn't* occur because
988 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
989 strcpy( nameBuff
, pAdapter
->AdapterName
);
994 pAdapter
= pAdapter
->Next
;
999 if (pAdapterInfo
!= NULL
)
1001 free( pAdapterInfo
);
1002 pAdapterInfo
= NULL
;
1010 if_nametoindex( const char * nameStr
)
1012 PIP_ADAPTER_INFO pAdapterInfo
= NULL
;
1013 PIP_ADAPTER_INFO pAdapter
= NULL
;
1016 ULONG ulOutBufLen
= 0;
1018 if (GetAdaptersInfo( NULL
, &ulOutBufLen
) != ERROR_BUFFER_OVERFLOW
)
1023 pAdapterInfo
= (IP_ADAPTER_INFO
*) malloc(ulOutBufLen
);
1025 if (pAdapterInfo
== NULL
)
1030 dwRetVal
= GetAdaptersInfo( pAdapterInfo
, &ulOutBufLen
);
1032 if (dwRetVal
!= NO_ERROR
)
1037 pAdapter
= pAdapterInfo
;
1040 if (strcmp(pAdapter
->AdapterName
, nameStr
) == 0)
1042 ifIndex
= pAdapter
->Index
;
1046 pAdapter
= pAdapter
->Next
;
1051 if (pAdapterInfo
!= NULL
)
1053 free( pAdapterInfo
);
1054 pAdapterInfo
= NULL
;
1062 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
1063 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
1064 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
1065 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
1066 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
1068 // NOT static -- otherwise the compiler may optimize it out
1069 // The "@(#) " pattern is a special prefix the "what" command looks for
1070 const char VersionString_SCCS
[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";