]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/Java/JNISupport.c
mDNSResponder-258.13.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 * if_indextoname( DWORD ifIndex, char * nameBuff);
50 static DWORD if_nametoindex( const char * nameStr );
51 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
52 #else // _WIN32
53 #include <sys/socket.h>
54 #include <net/if.h>
55 #endif // _WIN32
56
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"
63 #undef index
64
65 //#include <syslog.h>
66
67 // convenience definition
68 #ifdef __GNUC__
69 #define _UNUSED __attribute__ ((unused))
70 #else
71 #define _UNUSED
72 #endif
73
74 enum {
75 kInterfaceVersionOne = 1,
76 kInterfaceVersionCurrent // Must match version in .jar file
77 };
78
79 typedef struct OpContext OpContext;
80
81 struct OpContext
82 {
83 DNSServiceRef ServiceRef;
84 JNIEnv *Env;
85 jobject JavaObj;
86 jobject ClientObj;
87 jmethodID Callback;
88 jmethodID Callback2;
89 };
90
91 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
92 #if AUTO_CALLBACKS
93 JavaVM *gJavaVM = NULL;
94 #endif
95
96
97 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv *pEnv, jclass cls,
98 jint callerVersion)
99 {
100 /* Ensure that caller & interface versions match. */
101 if ( callerVersion != kInterfaceVersionCurrent)
102 return kDNSServiceErr_Incompatible;
103
104 #if AUTO_CALLBACKS
105 {
106 jsize numVMs;
107
108 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM, 1, &numVMs))
109 return kDNSServiceErr_BadState;
110 }
111 #endif
112
113 // Set AppleDNSSD.hasAutoCallbacks
114 {
115 #if AUTO_CALLBACKS
116 jboolean hasAutoC = JNI_TRUE;
117 #else
118 jboolean hasAutoC = JNI_FALSE;
119 #endif
120 jfieldID hasAutoCField = (*pEnv)->GetStaticFieldID( pEnv, cls, "hasAutoCallbacks", "Z");
121 (*pEnv)->SetStaticBooleanField( pEnv, cls, hasAutoCField, hasAutoC);
122 }
123
124 return kDNSServiceErr_NoError;
125 }
126
127
128 static const char* SafeGetUTFChars( JNIEnv *pEnv, jstring str)
129 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
130 {
131 return str != NULL ? (*pEnv)->GetStringUTFChars( pEnv, str, 0) : NULL;
132 }
133
134 static void SafeReleaseUTFChars( JNIEnv *pEnv, jstring str, const char *buff)
135 // Wrapper for JNI GetStringUTFChars() that handles null str.
136 {
137 if ( str != NULL)
138 (*pEnv)->ReleaseStringUTFChars( pEnv, str, buff);
139 }
140
141
142 #if AUTO_CALLBACKS
143 static void SetupCallbackState( JNIEnv **ppEnv)
144 {
145 (*gJavaVM)->AttachCurrentThread( gJavaVM, (void**) ppEnv, NULL);
146 }
147
148 static void TeardownCallbackState( void )
149 {
150 (*gJavaVM)->DetachCurrentThread( gJavaVM);
151 }
152
153 #else // AUTO_CALLBACKS
154
155 static void SetupCallbackState( JNIEnv **ppEnv _UNUSED)
156 {
157 // No setup necessary if ProcessResults() has been called
158 }
159
160 static void TeardownCallbackState( void )
161 {
162 // No teardown necessary if ProcessResults() has been called
163 }
164 #endif // AUTO_CALLBACKS
165
166
167 static OpContext *NewContext( JNIEnv *pEnv, jobject owner,
168 const char *callbackName, const char *callbackSig)
169 // Create and initialize a new OpContext.
170 {
171 OpContext *pContext = (OpContext*) malloc( sizeof *pContext);
172
173 if ( pContext != NULL)
174 {
175 jfieldID clientField = (*pEnv)->GetFieldID( pEnv, (*pEnv)->GetObjectClass( pEnv, owner),
176 "fListener", "Lcom/apple/dnssd/BaseListener;");
177
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
185 }
186
187 return pContext;
188 }
189
190
191 static void ReportError( JNIEnv *pEnv, jobject target, jobject service, DNSServiceErrorType err)
192 // Invoke operationFailed() method on target with err.
193 {
194 jclass cls = (*pEnv)->GetObjectClass( pEnv, target);
195 jmethodID opFailed = (*pEnv)->GetMethodID( pEnv, cls, "operationFailed",
196 "(Lcom/apple/dnssd/DNSSDService;I)V");
197
198 (*pEnv)->CallVoidMethod( pEnv, target, opFailed, service, err);
199 }
200
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. */
203 {
204 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
205 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
206
207 if ( contextField != 0)
208 {
209 OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
210 if ( pContext != NULL)
211 {
212 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
213 (*pEnv)->SetLongField(pEnv, pThis, contextField, 0);
214 if ( pContext->ServiceRef != NULL)
215 DNSServiceRefDeallocate( pContext->ServiceRef);
216
217 (*pEnv)->DeleteWeakGlobalRef( pEnv, pContext->JavaObj);
218 (*pEnv)->DeleteWeakGlobalRef( pEnv, pContext->ClientObj);
219 free( pContext);
220 }
221 }
222 }
223
224
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. */
227 {
228 // BlockForData() not supported with AUTO_CALLBACKS
229 #if !AUTO_CALLBACKS
230 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
231 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "J");
232
233 if ( contextField != 0)
234 {
235 OpContext *pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
236 if ( pContext != NULL)
237 {
238 fd_set readFDs;
239 int sd = DNSServiceRefSockFD( pContext->ServiceRef);
240 struct timeval timeout = { 1, 0 };
241 FD_ZERO( &readFDs);
242 FD_SET( sd, &readFDs);
243
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.
260
261 if (select( sd + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout) == 1) return(1);
262 }
263 }
264 #endif // !AUTO_CALLBACKS
265 return(0);
266 }
267
268
269 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv *pEnv, jobject pThis)
270 /* Call through to DNSServiceProcessResult() while data remains on socket. */
271 {
272 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
273
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;
278
279 if ( pContext != NULL)
280 {
281 int sd = DNSServiceRefSockFD( pContext->ServiceRef);
282 fd_set readFDs;
283 struct timeval zeroTimeout = { 0, 0 };
284
285 pContext->Env = pEnv;
286
287 FD_ZERO( &readFDs);
288 FD_SET( sd, &readFDs);
289
290 err = kDNSServiceErr_NoError;
291 if (0 < select(sd + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout))
292 {
293 err = DNSServiceProcessResult(pContext->ServiceRef);
294 // Use caution here!
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.
302 }
303 }
304 return err;
305 #endif // AUTO_CALLBACKS
306 }
307
308
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)
312 {
313 OpContext *pContext = (OpContext*) context;
314
315 SetupCallbackState( &pContext->Env);
316
317 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
318 {
319 if ( errorCode == kDNSServiceErr_NoError)
320 {
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));
327 }
328 else
329 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
330 }
331
332 TeardownCallbackState();
333 }
334
335 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *pEnv, jobject pThis,
336 jint flags, jint ifIndex, jstring regType, jstring domain)
337 {
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;
342
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");
346 else
347 err = kDNSServiceErr_BadParam;
348
349 if ( pContext != NULL)
350 {
351 const char *regStr = SafeGetUTFChars( pEnv, regType);
352 const char *domainStr = SafeGetUTFChars( pEnv, domain);
353
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");
357
358 err = DNSServiceBrowse( &pContext->ServiceRef, flags, ifIndex, regStr, domainStr, ServiceBrowseReply, pContext);
359 if ( err == kDNSServiceErr_NoError)
360 {
361 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
362 }
363
364 SafeReleaseUTFChars( pEnv, regType, regStr);
365 SafeReleaseUTFChars( pEnv, domain, domainStr);
366 }
367 else
368 err = kDNSServiceErr_NoMemory;
369
370 return err;
371 }
372
373
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)
377 {
378 OpContext *pContext = (OpContext*) context;
379 jclass txtCls;
380 jmethodID txtCtor;
381 jbyteArray txtBytes;
382 jobject txtObj;
383 jbyte *pBytes;
384
385 SetupCallbackState( &pContext->Env);
386
387 txtCls = (*pContext->Env)->FindClass( pContext->Env, "com/apple/dnssd/TXTRecord");
388 txtCtor = (*pContext->Env)->GetMethodID( pContext->Env, txtCls, "<init>", "([B)V");
389
390 if ( pContext->ClientObj != NULL && pContext->Callback != NULL && txtCtor != NULL &&
391 NULL != ( txtBytes = (*pContext->Env)->NewByteArray( pContext->Env, txtLen)))
392 {
393 if ( errorCode == kDNSServiceErr_NoError)
394 {
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];
398
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);
403
404 // Construct txtObj with txtBytes
405 txtObj = (*pContext->Env)->NewObject( pContext->Env, txtCls, txtCtor, txtBytes);
406 (*pContext->Env)->DeleteLocalRef( pContext->Env, txtBytes);
407
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),
412 port, txtObj);
413 }
414 else
415 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
416 }
417
418 TeardownCallbackState();
419 }
420
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)
423 {
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;
428
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");
432 else
433 err = kDNSServiceErr_BadParam;
434
435 if ( pContext != NULL)
436 {
437 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
438 const char *regStr = SafeGetUTFChars( pEnv, regType);
439 const char *domainStr = SafeGetUTFChars( pEnv, domain);
440
441 err = DNSServiceResolve( &pContext->ServiceRef, flags, ifIndex,
442 servStr, regStr, domainStr, ServiceResolveReply, pContext);
443 if ( err == kDNSServiceErr_NoError)
444 {
445 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
446 }
447
448 SafeReleaseUTFChars( pEnv, serviceName, servStr);
449 SafeReleaseUTFChars( pEnv, regType, regStr);
450 SafeReleaseUTFChars( pEnv, domain, domainStr);
451 }
452 else
453 err = kDNSServiceErr_NoMemory;
454
455 return err;
456 }
457
458
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)
462 {
463 OpContext *pContext = (OpContext*) context;
464
465 SetupCallbackState( &pContext->Env);
466
467 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
468 {
469 if ( errorCode == kDNSServiceErr_NoError)
470 {
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));
476 }
477 else
478 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
479 }
480 TeardownCallbackState();
481 }
482
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)
486 {
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;
492 jbyte *pBytes;
493 jsize numBytes;
494
495 //syslog(LOG_ERR, "BR: contextField %d", contextField);
496
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");
500 else
501 err = kDNSServiceErr_BadParam;
502
503 if ( pContext != NULL)
504 {
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);
509
510 //syslog(LOG_ERR, "BR: regStr %s", regStr);
511
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];
516
517 pBytes = txtRecord ? (*pEnv)->GetByteArrayElements( pEnv, txtRecord, NULL) : NULL;
518 numBytes = txtRecord ? (*pEnv)->GetArrayLength( pEnv, txtRecord) : 0;
519
520 err = DNSServiceRegister( &pContext->ServiceRef, flags, ifIndex, servStr, regStr,
521 domainStr, hostStr, portBits,
522 numBytes, pBytes, ServiceRegisterReply, pContext);
523 if ( err == kDNSServiceErr_NoError)
524 {
525 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
526 }
527
528 if ( pBytes != NULL)
529 (*pEnv)->ReleaseByteArrayElements( pEnv, txtRecord, pBytes, 0);
530
531 SafeReleaseUTFChars( pEnv, serviceName, servStr);
532 SafeReleaseUTFChars( pEnv, regType, regStr);
533 SafeReleaseUTFChars( pEnv, domain, domainStr);
534 SafeReleaseUTFChars( pEnv, host, hostStr);
535 }
536 else
537 err = kDNSServiceErr_NoMemory;
538
539 return err;
540 }
541
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)
544 {
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;
551 jbyte *pBytes;
552 jsize numBytes;
553 DNSRecordRef recRef;
554
555 if ( contextField != 0)
556 pContext = (OpContext*) (long) (*pEnv)->GetLongField(pEnv, pThis, contextField);
557 if ( pContext == NULL || pContext->ServiceRef == NULL)
558 return kDNSServiceErr_BadParam;
559
560 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
561 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
562
563 err = DNSServiceAddRecord( pContext->ServiceRef, &recRef, flags, rrType, numBytes, pBytes, ttl);
564 if ( err == kDNSServiceErr_NoError)
565 {
566 (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
567 }
568
569 if ( pBytes != NULL)
570 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
571
572 return err;
573 }
574
575 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv, jobject pThis,
576 jint flags, jbyteArray rData, jint ttl)
577 {
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;
583 jbyte *pBytes;
584 jsize numBytes;
585 DNSRecordRef recRef = NULL;
586
587 if ( ownerField != 0)
588 {
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);
594 }
595 if ( recField != 0)
596 recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
597 if ( pContext == NULL || pContext->ServiceRef == NULL)
598 return kDNSServiceErr_BadParam;
599
600 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
601 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
602
603 err = DNSServiceUpdateRecord( pContext->ServiceRef, recRef, flags, numBytes, pBytes, ttl);
604
605 if ( pBytes != NULL)
606 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
607
608 return err;
609 }
610
611 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv, jobject pThis)
612 {
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;
619
620 if ( ownerField != 0)
621 {
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);
627 }
628 if ( recField != 0)
629 recRef = (DNSRecordRef) (long) (*pEnv)->GetLongField(pEnv, pThis, recField);
630 if ( pContext == NULL || pContext->ServiceRef == NULL)
631 return kDNSServiceErr_BadParam;
632
633 err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, 0);
634
635 return err;
636 }
637
638
639 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv *pEnv, jobject pThis)
640 {
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;
645
646 if ( contextField != 0)
647 pContext = NewContext( pEnv, pThis, "recordRegistered", "(Lcom/apple/dnssd/DNSRecord;I)V");
648 else
649 err = kDNSServiceErr_BadParam;
650
651 if ( pContext != NULL)
652 {
653 err = DNSServiceCreateConnection( &pContext->ServiceRef);
654 if ( err == kDNSServiceErr_NoError)
655 {
656 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
657 }
658 }
659 else
660 err = kDNSServiceErr_NoMemory;
661
662 return err;
663 }
664
665 struct RecordRegistrationRef
666 {
667 OpContext *Context;
668 jobject RecordObj;
669 };
670 typedef struct RecordRegistrationRef RecordRegistrationRef;
671
672 static void DNSSD_API RegisterRecordReply( DNSServiceRef sdRef _UNUSED,
673 DNSRecordRef recordRef _UNUSED, DNSServiceFlags flags,
674 DNSServiceErrorType errorCode, void *context)
675 {
676 RecordRegistrationRef *regEnvelope = (RecordRegistrationRef*) context;
677 OpContext *pContext = regEnvelope->Context;
678
679 SetupCallbackState( &pContext->Env);
680
681 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
682 {
683 if ( errorCode == kDNSServiceErr_NoError)
684 {
685 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback,
686 regEnvelope->RecordObj, flags);
687 }
688 else
689 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
690 }
691
692 (*pContext->Env)->DeleteWeakGlobalRef( pContext->Env, regEnvelope->RecordObj);
693 free( regEnvelope);
694
695 TeardownCallbackState();
696 }
697
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)
701 {
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;
709 jbyte *pBytes;
710 jsize numBytes;
711 DNSRecordRef recRef;
712 RecordRegistrationRef *regEnvelope;
713
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;
718
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
724
725 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
726 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
727
728 err = DNSServiceRegisterRecord( pContext->ServiceRef, &recRef, flags, ifIndex,
729 nameStr, rrType, rrClass, numBytes, pBytes, ttl,
730 RegisterRecordReply, regEnvelope);
731
732 if ( err == kDNSServiceErr_NoError)
733 {
734 (*pEnv)->SetLongField(pEnv, destObj, recField, (long) recRef);
735 }
736 else
737 {
738 if ( regEnvelope->RecordObj != NULL)
739 (*pEnv)->DeleteWeakGlobalRef( pEnv, regEnvelope->RecordObj);
740 free( regEnvelope);
741 }
742
743 if ( pBytes != NULL)
744 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
745
746 SafeReleaseUTFChars( pEnv, fullname, nameStr);
747
748 return err;
749 }
750
751
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)
756 {
757 OpContext *pContext = (OpContext*) context;
758 jbyteArray rDataObj;
759 jbyte *pBytes;
760
761 SetupCallbackState( &pContext->Env);
762
763 if ( pContext->ClientObj != NULL && pContext->Callback != NULL &&
764 NULL != ( rDataObj = (*pContext->Env)->NewByteArray( pContext->Env, rdlen)))
765 {
766 if ( errorCode == kDNSServiceErr_NoError)
767 {
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);
772
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);
777 }
778 else
779 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
780 }
781 TeardownCallbackState();
782 }
783
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)
786 {
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;
791
792 if ( contextField != 0)
793 pContext = NewContext( pEnv, pThis, "queryAnswered",
794 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
795 else
796 err = kDNSServiceErr_BadParam;
797
798 if ( pContext != NULL)
799 {
800 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
801
802 err = DNSServiceQueryRecord( &pContext->ServiceRef, flags, ifIndex, servStr,
803 rrtype, rrclass, ServiceQueryReply, pContext);
804 if ( err == kDNSServiceErr_NoError)
805 {
806 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
807 }
808
809 SafeReleaseUTFChars( pEnv, serviceName, servStr);
810 }
811 else
812 err = kDNSServiceErr_NoMemory;
813
814 return err;
815 }
816
817
818 static void DNSSD_API DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
819 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
820 {
821 OpContext *pContext = (OpContext*) context;
822
823 SetupCallbackState( &pContext->Env);
824
825 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
826 {
827 if ( errorCode == kDNSServiceErr_NoError)
828 {
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));
833 }
834 else
835 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
836 }
837 TeardownCallbackState();
838 }
839
840 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv *pEnv, jobject pThis,
841 jint flags, jint ifIndex)
842 {
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;
847
848 if ( contextField != 0)
849 pContext = NewContext( pEnv, pThis, "domainFound",
850 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
851 else
852 err = kDNSServiceErr_BadParam;
853
854 if ( pContext != NULL)
855 {
856 pContext->Callback2 = (*pEnv)->GetMethodID( pEnv,
857 (*pEnv)->GetObjectClass( pEnv, pContext->ClientObj),
858 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
859
860 err = DNSServiceEnumerateDomains( &pContext->ServiceRef, flags, ifIndex,
861 DomainEnumReply, pContext);
862 if ( err == kDNSServiceErr_NoError)
863 {
864 (*pEnv)->SetLongField(pEnv, pThis, contextField, (long) pContext);
865 }
866 }
867 else
868 err = kDNSServiceErr_NoMemory;
869
870 return err;
871 }
872
873
874 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv *pEnv, jobject pThis _UNUSED,
875 jstring serviceName, jstring regtype, jstring domain, jobjectArray pOut)
876 {
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];
882
883 err = DNSServiceConstructFullName( buff, nameStr, regStr, domStr);
884
885 if ( err == kDNSServiceErr_NoError)
886 {
887 // pOut is expected to be a String[1] array.
888 (*pEnv)->SetObjectArrayElement( pEnv, pOut, 0, (*pEnv)->NewStringUTF( pEnv, buff));
889 }
890
891 SafeReleaseUTFChars( pEnv, serviceName, nameStr);
892 SafeReleaseUTFChars( pEnv, regtype, regStr);
893 SafeReleaseUTFChars( pEnv, domain, domStr);
894
895 return err;
896 }
897
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)
901 {
902 jbyte *pBytes;
903 jsize numBytes;
904 const char *nameStr = SafeGetUTFChars( pEnv, fullName);
905
906 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rdata, NULL);
907 numBytes = (*pEnv)->GetArrayLength( pEnv, rdata);
908
909 DNSServiceReconfirmRecord( flags, ifIndex, nameStr, rrtype, rrclass, numBytes, pBytes);
910
911 if ( pBytes != NULL)
912 (*pEnv)->ReleaseByteArrayElements( pEnv, rdata, pBytes, 0);
913
914 SafeReleaseUTFChars( pEnv, fullName, nameStr);
915 }
916
917 #define LOCAL_ONLY_NAME "loo"
918 #define P2P_NAME "p2p"
919
920 JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv *pEnv, jobject pThis _UNUSED,
921 jint ifIndex)
922 {
923 char *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
924
925 if (ifIndex == (jint) kDNSServiceInterfaceIndexP2P)
926 p = P2P_NAME;
927 else if (ifIndex != (jint) kDNSServiceInterfaceIndexLocalOnly)
928 p = if_indextoname( ifIndex, nameBuff );
929
930 return (*pEnv)->NewStringUTF( pEnv, p);
931 }
932
933
934 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv *pEnv, jobject pThis _UNUSED,
935 jstring ifName)
936 {
937 uint32_t ifIndex = kDNSServiceInterfaceIndexLocalOnly;
938 const char *nameStr = SafeGetUTFChars( pEnv, ifName);
939
940 if (strcmp(nameStr, P2P_NAME) == 0)
941 ifIndex = kDNSServiceInterfaceIndexP2P;
942 else if (strcmp(nameStr, LOCAL_ONLY_NAME))
943 ifIndex = if_nametoindex( nameStr);
944
945 SafeReleaseUTFChars( pEnv, ifName, nameStr);
946
947 return ifIndex;
948 }
949
950
951 #if defined(_WIN32)
952 static char*
953 if_indextoname( DWORD ifIndex, char * nameBuff)
954 {
955 PIP_ADAPTER_INFO pAdapterInfo = NULL;
956 PIP_ADAPTER_INFO pAdapter = NULL;
957 DWORD dwRetVal = 0;
958 char * ifName = NULL;
959 ULONG ulOutBufLen = 0;
960
961 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
962 {
963 goto exit;
964 }
965
966 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
967
968 if (pAdapterInfo == NULL)
969 {
970 goto exit;
971 }
972
973 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
974
975 if (dwRetVal != NO_ERROR)
976 {
977 goto exit;
978 }
979
980 pAdapter = pAdapterInfo;
981 while (pAdapter)
982 {
983 if (pAdapter->Index == ifIndex)
984 {
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 );
990 ifName = nameBuff;
991 break;
992 }
993
994 pAdapter = pAdapter->Next;
995 }
996
997 exit:
998
999 if (pAdapterInfo != NULL)
1000 {
1001 free( pAdapterInfo );
1002 pAdapterInfo = NULL;
1003 }
1004
1005 return ifName;
1006 }
1007
1008
1009 static DWORD
1010 if_nametoindex( const char * nameStr )
1011 {
1012 PIP_ADAPTER_INFO pAdapterInfo = NULL;
1013 PIP_ADAPTER_INFO pAdapter = NULL;
1014 DWORD dwRetVal = 0;
1015 DWORD ifIndex = 0;
1016 ULONG ulOutBufLen = 0;
1017
1018 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
1019 {
1020 goto exit;
1021 }
1022
1023 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
1024
1025 if (pAdapterInfo == NULL)
1026 {
1027 goto exit;
1028 }
1029
1030 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
1031
1032 if (dwRetVal != NO_ERROR)
1033 {
1034 goto exit;
1035 }
1036
1037 pAdapter = pAdapterInfo;
1038 while (pAdapter)
1039 {
1040 if (strcmp(pAdapter->AdapterName, nameStr) == 0)
1041 {
1042 ifIndex = pAdapter->Index;
1043 break;
1044 }
1045
1046 pAdapter = pAdapter->Next;
1047 }
1048
1049 exit:
1050
1051 if (pAdapterInfo != NULL)
1052 {
1053 free( pAdapterInfo );
1054 pAdapterInfo = NULL;
1055 }
1056
1057 return ifIndex;
1058 }
1059 #endif
1060
1061
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)
1067
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__ ")";