]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/Java/JNISupport.c
mDNSResponder-333.10.tar.gz
[apple/mdnsresponder.git] / mDNSShared / Java / JNISupport.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16
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.
19 */
20
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
31
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
40
41 #include <dns_sd.h>
42
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
58
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
66
67 //#include <syslog.h>
68
69 // convenience definition
70 #ifdef __GNUC__
71 #define _UNUSED __attribute__ ((unused))
72 #else
73 #define _UNUSED
74 #endif
75
76 enum {
77 kInterfaceVersionOne = 1,
78 kInterfaceVersionCurrent // Must match version in .jar file
79 };
80
81 typedef struct OpContext OpContext;
82
83 struct OpContext
84 {
85 DNSServiceRef ServiceRef;
86 JNIEnv *Env;
87 jobject JavaObj;
88 jobject ClientObj;
89 jmethodID Callback;
90 jmethodID Callback2;
91 };
92
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
97
98
99 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv *pEnv, jclass cls,
100 jint callerVersion)
101 {
102 /* Ensure that caller & interface versions match. */
103 if ( callerVersion != kInterfaceVersionCurrent)
104 return kDNSServiceErr_Incompatible;
105
106 #if AUTO_CALLBACKS
107 {
108 jsize numVMs;
109
110 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM, 1, &numVMs))
111 return kDNSServiceErr_BadState;
112 }
113 #endif
114
115 // Set AppleDNSSD.hasAutoCallbacks
116 {
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);
124 }
125
126 return kDNSServiceErr_NoError;
127 }
128
129
130 static const char* SafeGetUTFChars( JNIEnv *pEnv, jstring str)
131 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
132 {
133 return str != NULL ? (*pEnv)->GetStringUTFChars( pEnv, str, 0) : NULL;
134 }
135
136 static void SafeReleaseUTFChars( JNIEnv *pEnv, jstring str, const char *buff)
137 // Wrapper for JNI GetStringUTFChars() that handles null str.
138 {
139 if ( str != NULL)
140 (*pEnv)->ReleaseStringUTFChars( pEnv, str, buff);
141 }
142
143
144 #if AUTO_CALLBACKS
145 static void SetupCallbackState( JNIEnv **ppEnv)
146 {
147 (*gJavaVM)->AttachCurrentThread( gJavaVM, (void**) ppEnv, NULL);
148 }
149
150 static void TeardownCallbackState( void )
151 {
152 (*gJavaVM)->DetachCurrentThread( gJavaVM);
153 }
154
155 #else // AUTO_CALLBACKS
156
157 static void SetupCallbackState( JNIEnv **ppEnv _UNUSED)
158 {
159 // No setup necessary if ProcessResults() has been called
160 }
161
162 static void TeardownCallbackState( void )
163 {
164 // No teardown necessary if ProcessResults() has been called
165 }
166 #endif // AUTO_CALLBACKS
167
168
169 static OpContext *NewContext( JNIEnv *pEnv, jobject owner,
170 const char *callbackName, const char *callbackSig)
171 // Create and initialize a new OpContext.
172 {
173 OpContext *pContext = (OpContext*) malloc( sizeof *pContext);
174
175 if ( pContext != NULL)
176 {
177 jfieldID clientField = (*pEnv)->GetFieldID( pEnv, (*pEnv)->GetObjectClass( pEnv, owner),
178 "fListener", "Lcom/apple/dnssd/BaseListener;");
179
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
187 }
188
189 return pContext;
190 }
191
192
193 static void ReportError( JNIEnv *pEnv, jobject target, jobject service, DNSServiceErrorType err)
194 // Invoke operationFailed() method on target with err.
195 {
196 jclass cls = (*pEnv)->GetObjectClass( pEnv, target);
197 jmethodID opFailed = (*pEnv)->GetMethodID( pEnv, cls, "operationFailed",
198 "(Lcom/apple/dnssd/DNSSDService;I)V");
199
200 (*pEnv)->CallVoidMethod( pEnv, target, opFailed, service, err);
201 }
202
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. */
205 {
206 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
207 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
208
209 if ( contextField != 0)
210 {
211 OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
212 if ( pContext != NULL)
213 {
214 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
215 (*pEnv)->SetLongField(pEnv, pThis, contextField, 0);
216 if ( pContext->ServiceRef != NULL)
217 DNSServiceRefDeallocate( pContext->ServiceRef);
218
219 (*pEnv)->DeleteWeakGlobalRef( pEnv, pContext->JavaObj);
220 (*pEnv)->DeleteWeakGlobalRef( pEnv, pContext->ClientObj);
221 free( pContext);
222 }
223 }
224 }
225
226
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. */
229 {
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");
234
235 if ( contextField != 0)
236 {
237 OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
238 if ( pContext != NULL)
239 {
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);
245
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.
262
263 if (select( sd + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout) == 1) return(1);
264 }
265 }
266 #endif // !AUTO_CALLBACKS
267 return(0);
268 }
269
270
271 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv *pEnv, jobject pThis)
272 /* Call through to DNSServiceProcessResult() while data remains on socket. */
273 {
274 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
275
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;
280
281 if ( pContext != NULL)
282 {
283 int sd = DNSServiceRefSockFD( pContext->ServiceRef);
284 fd_set readFDs;
285 struct timeval zeroTimeout = { 0, 0 };
286
287 pContext->Env = pEnv;
288
289 FD_ZERO( &readFDs);
290 FD_SET( sd, &readFDs);
291
292 err = kDNSServiceErr_NoError;
293 if (0 < select(sd + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout))
294 {
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.
304 }
305 }
306 return err;
307 #endif // AUTO_CALLBACKS
308 }
309
310
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)
314 {
315 OpContext *pContext = (OpContext*) context;
316
317 SetupCallbackState( &pContext->Env);
318
319 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
320 {
321 if ( errorCode == kDNSServiceErr_NoError)
322 {
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));
329 }
330 else
331 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
332 }
333
334 TeardownCallbackState();
335 }
336
337 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *pEnv, jobject pThis,
338 jint flags, jint ifIndex, jstring regType, jstring domain)
339 {
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;
344
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;
350
351 if ( pContext != NULL)
352 {
353 const char *regStr = SafeGetUTFChars( pEnv, regType);
354 const char *domainStr = SafeGetUTFChars( pEnv, domain);
355
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");
359
360 err = DNSServiceBrowse( &pContext->ServiceRef, flags, ifIndex, regStr, domainStr, ServiceBrowseReply, pContext);
361 if ( err == kDNSServiceErr_NoError)
362 {
363 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
364 }
365
366 SafeReleaseUTFChars( pEnv, regType, regStr);
367 SafeReleaseUTFChars( pEnv, domain, domainStr);
368 }
369 else
370 err = kDNSServiceErr_NoMemory;
371
372 return err;
373 }
374
375
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)
379 {
380 OpContext *pContext = (OpContext*) context;
381 jclass txtCls;
382 jmethodID txtCtor;
383 jbyteArray txtBytes;
384 jobject txtObj;
385 jbyte *pBytes;
386
387 SetupCallbackState( &pContext->Env);
388
389 txtCls = (*pContext->Env)->FindClass( pContext->Env, "com/apple/dnssd/TXTRecord");
390 txtCtor = (*pContext->Env)->GetMethodID( pContext->Env, txtCls, "<init>", "([B)V");
391
392 if ( pContext->ClientObj != NULL && pContext->Callback != NULL && txtCtor != NULL &&
393 NULL != ( txtBytes = (*pContext->Env)->NewByteArray( pContext->Env, txtLen)))
394 {
395 if ( errorCode == kDNSServiceErr_NoError)
396 {
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];
400
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);
405
406 // Construct txtObj with txtBytes
407 txtObj = (*pContext->Env)->NewObject( pContext->Env, txtCls, txtCtor, txtBytes);
408 (*pContext->Env)->DeleteLocalRef( pContext->Env, txtBytes);
409
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);
415 }
416 else
417 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
418 }
419
420 TeardownCallbackState();
421 }
422
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)
425 {
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;
430
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;
436
437 if ( pContext != NULL)
438 {
439 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
440 const char *regStr = SafeGetUTFChars( pEnv, regType);
441 const char *domainStr = SafeGetUTFChars( pEnv, domain);
442
443 err = DNSServiceResolve( &pContext->ServiceRef, flags, ifIndex,
444 servStr, regStr, domainStr, ServiceResolveReply, pContext);
445 if ( err == kDNSServiceErr_NoError)
446 {
447 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
448 }
449
450 SafeReleaseUTFChars( pEnv, serviceName, servStr);
451 SafeReleaseUTFChars( pEnv, regType, regStr);
452 SafeReleaseUTFChars( pEnv, domain, domainStr);
453 }
454 else
455 err = kDNSServiceErr_NoMemory;
456
457 return err;
458 }
459
460
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)
464 {
465 OpContext *pContext = (OpContext*) context;
466
467 SetupCallbackState( &pContext->Env);
468
469 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
470 {
471 if ( errorCode == kDNSServiceErr_NoError)
472 {
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));
478 }
479 else
480 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
481 }
482 TeardownCallbackState();
483 }
484
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)
488 {
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;
496
497 //syslog(LOG_ERR, "BR: contextField %d", contextField);
498
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;
504
505 if ( pContext != NULL)
506 {
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);
511
512 //syslog(LOG_ERR, "BR: regStr %s", regStr);
513
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];
518
519 pBytes = txtRecord ? (*pEnv)->GetByteArrayElements( pEnv, txtRecord, NULL) : NULL;
520 numBytes = txtRecord ? (*pEnv)->GetArrayLength( pEnv, txtRecord) : 0;
521
522 err = DNSServiceRegister( &pContext->ServiceRef, flags, ifIndex, servStr, regStr,
523 domainStr, hostStr, portBits,
524 numBytes, pBytes, ServiceRegisterReply, pContext);
525 if ( err == kDNSServiceErr_NoError)
526 {
527 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
528 }
529
530 if ( pBytes != NULL)
531 (*pEnv)->ReleaseByteArrayElements( pEnv, txtRecord, pBytes, 0);
532
533 SafeReleaseUTFChars( pEnv, serviceName, servStr);
534 SafeReleaseUTFChars( pEnv, regType, regStr);
535 SafeReleaseUTFChars( pEnv, domain, domainStr);
536 SafeReleaseUTFChars( pEnv, host, hostStr);
537 }
538 else
539 err = kDNSServiceErr_NoMemory;
540
541 return err;
542 }
543
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)
546 {
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;
556
557 if ( contextField != 0)
558 pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
559 if ( pContext == NULL || pContext->ServiceRef == NULL)
560 return kDNSServiceErr_BadParam;
561
562 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
563 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
564
565 err = DNSServiceAddRecord( pContext->ServiceRef, &recRef, flags, rrType, numBytes, pBytes, ttl);
566 if ( err == kDNSServiceErr_NoError)
567 {
568 (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
569 }
570
571 if ( pBytes != NULL)
572 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
573
574 return err;
575 }
576
577 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv, jobject pThis,
578 jint flags, jbyteArray rData, jint ttl)
579 {
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;
588
589 if ( ownerField != 0)
590 {
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);
596 }
597 if ( recField != 0)
598 recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
599 if ( pContext == NULL || pContext->ServiceRef == NULL)
600 return kDNSServiceErr_BadParam;
601
602 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
603 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
604
605 err = DNSServiceUpdateRecord( pContext->ServiceRef, recRef, flags, numBytes, pBytes, ttl);
606
607 if ( pBytes != NULL)
608 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
609
610 return err;
611 }
612
613 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv, jobject pThis)
614 {
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;
621
622 if ( ownerField != 0)
623 {
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);
629 }
630 if ( recField != 0)
631 recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
632 if ( pContext == NULL || pContext->ServiceRef == NULL)
633 return kDNSServiceErr_BadParam;
634
635 err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, 0);
636
637 return err;
638 }
639
640
641 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv *pEnv, jobject pThis)
642 {
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;
647
648 if ( contextField != 0)
649 pContext = NewContext( pEnv, pThis, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
650 else
651 err = kDNSServiceErr_BadParam;
652
653 if ( pContext != NULL)
654 {
655 err = DNSServiceCreateConnection( &pContext->ServiceRef);
656 if ( err == kDNSServiceErr_NoError)
657 {
658 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
659 }
660 }
661 else
662 err = kDNSServiceErr_NoMemory;
663
664 return err;
665 }
666
667 struct RecordRegistrationRef
668 {
669 OpContext *Context;
670 jobject RecordObj;
671 };
672 typedef struct RecordRegistrationRef RecordRegistrationRef;
673
674 static void DNSSD_API RegisterRecordReply( DNSServiceRef sdRef _UNUSED,
675 DNSRecordRef recordRef _UNUSED, DNSServiceFlags flags,
676 DNSServiceErrorType errorCode, void *context)
677 {
678 RecordRegistrationRef *regEnvelope = (RecordRegistrationRef*) context;
679 OpContext *pContext = regEnvelope->Context;
680
681 SetupCallbackState( &pContext->Env);
682
683 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
684 {
685 if ( errorCode == kDNSServiceErr_NoError)
686 {
687 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback,
688 regEnvelope->RecordObj, flags);
689 }
690 else
691 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
692 }
693
694 (*pContext->Env)->DeleteWeakGlobalRef( pContext->Env, regEnvelope->RecordObj);
695 free( regEnvelope);
696
697 TeardownCallbackState();
698 }
699
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)
703 {
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;
715
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;
720
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
726
727 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
728 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
729
730 err = DNSServiceRegisterRecord( pContext->ServiceRef, &recRef, flags, ifIndex,
731 nameStr, rrType, rrClass, numBytes, pBytes, ttl,
732 RegisterRecordReply, regEnvelope);
733
734 if ( err == kDNSServiceErr_NoError)
735 {
736 (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
737 }
738 else
739 {
740 if ( regEnvelope->RecordObj != NULL)
741 (*pEnv)->DeleteWeakGlobalRef( pEnv, regEnvelope->RecordObj);
742 free( regEnvelope);
743 }
744
745 if ( pBytes != NULL)
746 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
747
748 SafeReleaseUTFChars( pEnv, fullname, nameStr);
749
750 return err;
751 }
752
753
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)
758 {
759 OpContext *pContext = (OpContext*) context;
760 jbyteArray rDataObj;
761 jbyte *pBytes;
762
763 SetupCallbackState( &pContext->Env);
764
765 if ( pContext->ClientObj != NULL && pContext->Callback != NULL &&
766 NULL != ( rDataObj = (*pContext->Env)->NewByteArray( pContext->Env, rdlen)))
767 {
768 if ( errorCode == kDNSServiceErr_NoError)
769 {
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);
774
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);
779 }
780 else
781 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
782 }
783 TeardownCallbackState();
784 }
785
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)
788 {
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;
793
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;
799
800 if ( pContext != NULL)
801 {
802 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
803
804 err = DNSServiceQueryRecord( &pContext->ServiceRef, flags, ifIndex, servStr,
805 rrtype, rrclass, ServiceQueryReply, pContext);
806 if ( err == kDNSServiceErr_NoError)
807 {
808 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
809 }
810
811 SafeReleaseUTFChars( pEnv, serviceName, servStr);
812 }
813 else
814 err = kDNSServiceErr_NoMemory;
815
816 return err;
817 }
818
819
820 static void DNSSD_API DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
821 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
822 {
823 OpContext *pContext = (OpContext*) context;
824
825 SetupCallbackState( &pContext->Env);
826
827 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
828 {
829 if ( errorCode == kDNSServiceErr_NoError)
830 {
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));
835 }
836 else
837 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
838 }
839 TeardownCallbackState();
840 }
841
842 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv *pEnv, jobject pThis,
843 jint flags, jint ifIndex)
844 {
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;
849
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;
855
856 if ( pContext != NULL)
857 {
858 pContext->Callback2 = (*pEnv)->GetMethodID( pEnv,
859 (*pEnv)->GetObjectClass( pEnv, pContext->ClientObj),
860 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
861
862 err = DNSServiceEnumerateDomains( &pContext->ServiceRef, flags, ifIndex,
863 DomainEnumReply, pContext);
864 if ( err == kDNSServiceErr_NoError)
865 {
866 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
867 }
868 }
869 else
870 err = kDNSServiceErr_NoMemory;
871
872 return err;
873 }
874
875
876 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv *pEnv, jobject pThis _UNUSED,
877 jstring serviceName, jstring regtype, jstring domain, jobjectArray pOut)
878 {
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];
884
885 err = DNSServiceConstructFullName( buff, nameStr, regStr, domStr);
886
887 if ( err == kDNSServiceErr_NoError)
888 {
889 // pOut is expected to be a String[1] array.
890 (*pEnv)->SetObjectArrayElement( pEnv, pOut, 0, (*pEnv)->NewStringUTF( pEnv, buff));
891 }
892
893 SafeReleaseUTFChars( pEnv, serviceName, nameStr);
894 SafeReleaseUTFChars( pEnv, regtype, regStr);
895 SafeReleaseUTFChars( pEnv, domain, domStr);
896
897 return err;
898 }
899
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)
903 {
904 jbyte *pBytes;
905 jsize numBytes;
906 const char *nameStr = SafeGetUTFChars( pEnv, fullName);
907
908 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rdata, NULL);
909 numBytes = (*pEnv)->GetArrayLength( pEnv, rdata);
910
911 DNSServiceReconfirmRecord( flags, ifIndex, nameStr, rrtype, rrclass, numBytes, pBytes);
912
913 if ( pBytes != NULL)
914 (*pEnv)->ReleaseByteArrayElements( pEnv, rdata, pBytes, 0);
915
916 SafeReleaseUTFChars( pEnv, fullName, nameStr);
917 }
918
919 #define LOCAL_ONLY_NAME "loo"
920 #define P2P_NAME "p2p"
921
922 JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv *pEnv, jobject pThis _UNUSED,
923 jint ifIndex)
924 {
925 char *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
926
927 if (ifIndex == (jint) kDNSServiceInterfaceIndexP2P)
928 p = P2P_NAME;
929 else if (ifIndex != (jint) kDNSServiceInterfaceIndexLocalOnly)
930 p = if_indextoname( ifIndex, nameBuff );
931
932 return (*pEnv)->NewStringUTF( pEnv, p);
933 }
934
935
936 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv *pEnv, jobject pThis _UNUSED,
937 jstring ifName)
938 {
939 uint32_t ifIndex = kDNSServiceInterfaceIndexLocalOnly;
940 const char *nameStr = SafeGetUTFChars( pEnv, ifName);
941
942 if (strcmp(nameStr, P2P_NAME) == 0)
943 ifIndex = kDNSServiceInterfaceIndexP2P;
944 else if (strcmp(nameStr, LOCAL_ONLY_NAME))
945 ifIndex = if_nametoindex( nameStr);
946
947 SafeReleaseUTFChars( pEnv, ifName, nameStr);
948
949 return ifIndex;
950 }
951
952
953 #if defined(_WIN32)
954 static char*
955 win32_if_indextoname( DWORD ifIndex, char * nameBuff)
956 {
957 PIP_ADAPTER_INFO pAdapterInfo = NULL;
958 PIP_ADAPTER_INFO pAdapter = NULL;
959 DWORD dwRetVal = 0;
960 char * ifName = NULL;
961 ULONG ulOutBufLen = 0;
962
963 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
964 {
965 goto exit;
966 }
967
968 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
969
970 if (pAdapterInfo == NULL)
971 {
972 goto exit;
973 }
974
975 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
976
977 if (dwRetVal != NO_ERROR)
978 {
979 goto exit;
980 }
981
982 pAdapter = pAdapterInfo;
983 while (pAdapter)
984 {
985 if (pAdapter->Index == ifIndex)
986 {
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;
994 }
995
996 pAdapter = pAdapter->Next;
997 }
998
999 exit:
1000
1001 if (pAdapterInfo != NULL)
1002 {
1003 free( pAdapterInfo );
1004 pAdapterInfo = NULL;
1005 }
1006
1007 return ifName;
1008 }
1009
1010
1011 static DWORD
1012 win32_if_nametoindex( const char * nameStr )
1013 {
1014 PIP_ADAPTER_INFO pAdapterInfo = NULL;
1015 PIP_ADAPTER_INFO pAdapter = NULL;
1016 DWORD dwRetVal = 0;
1017 DWORD ifIndex = 0;
1018 ULONG ulOutBufLen = 0;
1019
1020 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
1021 {
1022 goto exit;
1023 }
1024
1025 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
1026
1027 if (pAdapterInfo == NULL)
1028 {
1029 goto exit;
1030 }
1031
1032 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
1033
1034 if (dwRetVal != NO_ERROR)
1035 {
1036 goto exit;
1037 }
1038
1039 pAdapter = pAdapterInfo;
1040 while (pAdapter)
1041 {
1042 if (strcmp(pAdapter->AdapterName, nameStr) == 0)
1043 {
1044 ifIndex = pAdapter->Index;
1045 break;
1046 }
1047
1048 pAdapter = pAdapter->Next;
1049 }
1050
1051 exit:
1052
1053 if (pAdapterInfo != NULL)
1054 {
1055 free( pAdapterInfo );
1056 pAdapterInfo = NULL;
1057 }
1058
1059 return ifIndex;
1060 }
1061 #endif
1062
1063
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)
1069
1070 // NOT static -- otherwise the compiler may optimize it out
1071 // The "@(#) " pattern is a special prefix the "what" command looks for
1072 const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";