7120 mDNS resync was not wsdiff safe
[unleashed.git] / usr / src / lib / libdns_sd / java / common / JNISupport.c
blobaf4de19912fee78fa86ff1d04be9ee8881e1dd12
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
30 #endif
32 #if !AUTO_CALLBACKS
33 #ifdef _WIN32
34 #include <winsock2.h>
35 #else //_WIN32
36 #include <sys/types.h>
37 #include <sys/select.h>
38 #endif // _WIN32
39 #endif // AUTO_CALLBACKS
41 #include <dns_sd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #ifdef _WIN32
47 #include <winsock2.h>
48 #include <iphlpapi.h>
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
54 #else // _WIN32
55 #include <sys/socket.h>
56 #include <net/if.h>
57 #endif // _WIN32
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"
65 #undef index
67 //#include <syslog.h>
69 // convenience definition
70 #ifdef __GNUC__
71 #define _UNUSED __attribute__ ((unused))
72 #else
73 #define _UNUSED
74 #endif
76 enum {
77 kInterfaceVersionOne = 1,
78 kInterfaceVersionCurrent // Must match version in .jar file
81 typedef struct OpContext OpContext;
83 struct OpContext
85 DNSServiceRef ServiceRef;
86 JNIEnv *Env;
87 jobject JavaObj;
88 jobject ClientObj;
89 jmethodID Callback;
90 jmethodID Callback2;
93 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
94 #if AUTO_CALLBACKS
95 JavaVM *gJavaVM = NULL;
96 #endif
99 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv *pEnv, jclass cls,
100 jint callerVersion)
102 /* Ensure that caller & interface versions match. */
103 if ( callerVersion != kInterfaceVersionCurrent)
104 return kDNSServiceErr_Incompatible;
106 #if AUTO_CALLBACKS
108 jsize numVMs;
110 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM, 1, &numVMs))
111 return kDNSServiceErr_BadState;
113 #endif
115 // Set AppleDNSSD.hasAutoCallbacks
117 #if AUTO_CALLBACKS
118 jboolean hasAutoC = JNI_TRUE;
119 #else
120 jboolean hasAutoC = JNI_FALSE;
121 #endif
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.
139 if ( str != NULL)
140 (*pEnv)->ReleaseStringUTFChars( pEnv, str, buff);
144 #if AUTO_CALLBACKS
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
189 return pContext;
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);
221 free( pContext);
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
231 #if !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)
240 fd_set readFDs;
241 int sd = DNSServiceRefSockFD( pContext->ServiceRef);
242 struct timeval timeout = { 1, 0 };
243 FD_ZERO( &readFDs);
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
267 return(0);
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);
284 fd_set readFDs;
285 struct timeval zeroTimeout = { 0, 0 };
287 pContext->Env = pEnv;
289 FD_ZERO( &readFDs);
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);
296 // Use caution here!
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.
306 return err;
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));
330 else
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");
348 else
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);
369 else
370 err = kDNSServiceErr_NoMemory;
372 return err;
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;
381 jclass txtCls;
382 jmethodID txtCtor;
383 jbyteArray txtBytes;
384 jobject txtObj;
385 jbyte *pBytes;
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),
414 port, txtObj);
416 else
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");
434 else
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);
454 else
455 err = kDNSServiceErr_NoMemory;
457 return err;
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));
479 else
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;
494 jbyte *pBytes;
495 jsize numBytes;
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");
502 else
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);
530 if ( pBytes != NULL)
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);
538 else
539 err = kDNSServiceErr_NoMemory;
541 return err;
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;
553 jbyte *pBytes;
554 jsize numBytes;
555 DNSRecordRef recRef;
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);
571 if ( pBytes != NULL)
572 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
574 return err;
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;
585 jbyte *pBytes;
586 jsize numBytes;
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);
597 if ( recField != 0)
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);
607 if ( pBytes != NULL)
608 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
610 return err;
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);
630 if ( recField != 0)
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);
637 return err;
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");
650 else
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);
661 else
662 err = kDNSServiceErr_NoMemory;
664 return err;
667 struct RecordRegistrationRef
669 OpContext *Context;
670 jobject RecordObj;
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);
690 else
691 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
694 (*pContext->Env)->DeleteWeakGlobalRef( pContext->Env, regEnvelope->RecordObj);
695 free( regEnvelope);
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;
711 jbyte *pBytes;
712 jsize numBytes;
713 DNSRecordRef recRef;
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);
738 else
740 if ( regEnvelope->RecordObj != NULL)
741 (*pEnv)->DeleteWeakGlobalRef( pEnv, regEnvelope->RecordObj);
742 free( regEnvelope);
745 if ( pBytes != NULL)
746 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
748 SafeReleaseUTFChars( pEnv, fullname, nameStr);
750 return err;
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;
760 jbyteArray rDataObj;
761 jbyte *pBytes;
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);
780 else
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");
797 else
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);
813 else
814 err = kDNSServiceErr_NoMemory;
816 return err;
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));
836 else
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");
853 else
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);
869 else
870 err = kDNSServiceErr_NoMemory;
872 return err;
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);
897 return err;
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)
904 jbyte *pBytes;
905 jsize numBytes;
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);
913 if ( pBytes != NULL)
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,
923 jint ifIndex)
925 char *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
927 if (ifIndex == (jint) kDNSServiceInterfaceIndexP2P)
928 p = P2P_NAME;
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,
937 jstring ifName)
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);
949 return ifIndex;
953 #if defined(_WIN32)
954 static char*
955 win32_if_indextoname( DWORD ifIndex, char * nameBuff)
957 PIP_ADAPTER_INFO pAdapterInfo = NULL;
958 PIP_ADAPTER_INFO pAdapter = NULL;
959 DWORD dwRetVal = 0;
960 char * ifName = NULL;
961 ULONG ulOutBufLen = 0;
963 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
965 goto exit;
968 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
970 if (pAdapterInfo == NULL)
972 goto exit;
975 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
977 if (dwRetVal != NO_ERROR)
979 goto exit;
982 pAdapter = pAdapterInfo;
983 while (pAdapter)
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 );
992 ifName = nameBuff;
993 break;
996 pAdapter = pAdapter->Next;
999 exit:
1001 if (pAdapterInfo != NULL)
1003 free( pAdapterInfo );
1004 pAdapterInfo = NULL;
1007 return ifName;
1011 static DWORD
1012 win32_if_nametoindex( const char * nameStr )
1014 PIP_ADAPTER_INFO pAdapterInfo = NULL;
1015 PIP_ADAPTER_INFO pAdapter = NULL;
1016 DWORD dwRetVal = 0;
1017 DWORD ifIndex = 0;
1018 ULONG ulOutBufLen = 0;
1020 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
1022 goto exit;
1025 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
1027 if (pAdapterInfo == NULL)
1029 goto exit;
1032 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
1034 if (dwRetVal != NO_ERROR)
1036 goto exit;
1039 pAdapter = pAdapterInfo;
1040 while (pAdapter)
1042 if (strcmp(pAdapter->AdapterName, nameStr) == 0)
1044 ifIndex = pAdapter->Index;
1045 break;
1048 pAdapter = pAdapter->Next;
1051 exit:
1053 if (pAdapterInfo != NULL)
1055 free( pAdapterInfo );
1056 pAdapterInfo = NULL;
1059 return ifIndex;
1061 #endif
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__ ")";
1074 #else
1075 const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion);
1076 #endif