]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/Java/JNISupport.c
mDNSResponder-107.3.tar.gz
[apple/mdnsresponder.git] / mDNSShared / Java / JNISupport.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: JNISupport.c,v $
26 Revision 1.12 2005/07/13 19:20:32 cheshire
27 <rdar://problem/4175511> Race condition in Java API
28 Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
29
30 Revision 1.11 2005/07/11 01:55:21 cheshire
31 <rdar://problem/4175511> Race condition in Java API
32
33 Revision 1.10 2005/07/05 13:01:52 cheshire
34 <rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
35
36 Revision 1.9 2004/12/11 03:01:00 rpantos
37 <rdar://problem/3907498> Java DNSRecord API should be cleaned up
38
39 Revision 1.8 2004/11/30 23:51:05 cheshire
40 Remove double semicolons
41
42 Revision 1.7 2004/11/23 08:12:04 shersche
43 Implement if_nametoindex and if_indextoname for Win32 platforms
44
45 Revision 1.6 2004/11/23 03:41:14 cheshire
46 Change JNISupport.c to call if_indextoname & if_nametoindex directly.
47 (May require some additional glue code to work on Windows.)
48
49 Revision 1.5 2004/11/17 17:07:44 cheshire
50 Updated comment about AUTO_CALLBACKS
51
52 Revision 1.4 2004/11/12 03:23:09 rpantos
53 rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
54
55 Revision 1.3 2004/06/18 04:44:17 rpantos
56 Adapt to API unification on Windows
57
58 Revision 1.2 2004/05/28 23:34:42 ksekar
59 <rdar://problem/3672903>: Java project build errors
60
61 Revision 1.1 2004/04/30 16:29:35 rpantos
62 First checked in.
63
64
65 This file contains the platform support for DNSSD and related Java classes.
66 It is used to shim through to the underlying <dns_sd.h> API.
67 */
68
69 // AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
70 // callbacks automatically (as in the early Windows prototypes).
71 // AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
72 // invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
73 // (Invoking callbacks automatically on a different thread sounds attractive, but while
74 // the client gains by not needing to add an event source to its main event loop, it loses
75 // by being forced to deal with concurrency and locking, which can be a bigger burden.)
76 #ifndef AUTO_CALLBACKS
77 #define AUTO_CALLBACKS 0
78 #endif
79
80 #if !AUTO_CALLBACKS
81 #ifdef _WIN32
82 #include <winsock2.h>
83 #else //_WIN32
84 #include <sys/types.h>
85 #include <sys/select.h>
86 #endif // _WIN32
87 #endif // AUTO_CALLBACKS
88
89 #include <dns_sd.h>
90
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #ifdef _WIN32
95 #include <winsock2.h>
96 #include <iphlpapi.h>
97 static char * if_indextoname( DWORD ifIndex, char * nameBuff);
98 static DWORD if_nametoindex( const char * nameStr );
99 #define IF_NAMESIZE MAX_ADAPTER_NAME_LENGTH
100 #else // _WIN32
101 #include <sys/socket.h>
102 #include <net/if.h>
103 #endif // _WIN32
104 #include <jni.h>
105
106 #include "DNSSD.java.h"
107
108 // convenience definition
109 #ifdef __GNUC__
110 #define _UNUSED __attribute__ ((unused))
111 #else
112 #define _UNUSED
113 #endif
114
115 enum {
116 kInterfaceVersion = 1 // Must match version in .jar file
117 };
118
119 typedef struct OpContext OpContext;
120
121 struct OpContext
122 {
123 DNSServiceRef ServiceRef;
124 JNIEnv *Env;
125 jobject JavaObj;
126 jobject ClientObj;
127 jmethodID Callback;
128 jmethodID Callback2;
129 };
130
131 // For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
132 #if AUTO_CALLBACKS
133 JavaVM *gJavaVM = NULL;
134 #endif
135
136
137 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_InitLibrary( JNIEnv *pEnv, jclass cls,
138 jint callerVersion)
139 {
140 /* Ensure that caller & interface versions match. */
141 if ( callerVersion != kInterfaceVersion)
142 return kDNSServiceErr_Incompatible;
143
144 #if AUTO_CALLBACKS
145 {
146 jsize numVMs;
147
148 if ( 0 != JNI_GetCreatedJavaVMs( &gJavaVM, 1, &numVMs))
149 return kDNSServiceErr_BadState;
150 }
151 #endif
152
153 // Set AppleDNSSD.hasAutoCallbacks
154 {
155 #if AUTO_CALLBACKS
156 jboolean hasAutoC = JNI_TRUE;
157 #else
158 jboolean hasAutoC = JNI_FALSE;
159 #endif
160 jfieldID hasAutoCField = (*pEnv)->GetStaticFieldID( pEnv, cls, "hasAutoCallbacks", "Z");
161 (*pEnv)->SetStaticBooleanField( pEnv, cls, hasAutoCField, hasAutoC);
162 }
163
164 return kDNSServiceErr_NoError;
165 }
166
167
168 static const char* SafeGetUTFChars( JNIEnv *pEnv, jstring str)
169 // Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
170 {
171 return str != NULL ? (*pEnv)->GetStringUTFChars( pEnv, str, 0) : NULL;
172 }
173
174 static void SafeReleaseUTFChars( JNIEnv *pEnv, jstring str, const char *buff)
175 // Wrapper for JNI GetStringUTFChars() that handles null str.
176 {
177 if ( str != NULL)
178 (*pEnv)->ReleaseStringUTFChars( pEnv, str, buff);
179 }
180
181
182 #if AUTO_CALLBACKS
183 static void SetupCallbackState( JNIEnv **ppEnv)
184 {
185 (*gJavaVM)->AttachCurrentThread( gJavaVM, (void**) ppEnv, NULL);
186 }
187
188 static void TeardownCallbackState( void )
189 {
190 (*gJavaVM)->DetachCurrentThread( gJavaVM);
191 }
192
193 #else // AUTO_CALLBACKS
194
195 static void SetupCallbackState( JNIEnv **ppEnv _UNUSED)
196 {
197 // No setup necessary if ProcessResults() has been called
198 }
199
200 static void TeardownCallbackState( void )
201 {
202 // No teardown necessary if ProcessResults() has been called
203 }
204 #endif // AUTO_CALLBACKS
205
206
207 static OpContext *NewContext( JNIEnv *pEnv, jobject owner,
208 const char *callbackName, const char *callbackSig)
209 // Create and initialize a new OpContext.
210 {
211 OpContext *pContext = (OpContext*) malloc( sizeof *pContext);
212
213 if ( pContext != NULL)
214 {
215 jfieldID clientField = (*pEnv)->GetFieldID( pEnv, (*pEnv)->GetObjectClass( pEnv, owner),
216 "fListener", "Lcom/apple/dnssd/BaseListener;");
217
218 pContext->JavaObj = (*pEnv)->NewWeakGlobalRef( pEnv, owner); // must convert local ref to global to cache;
219 pContext->ClientObj = (*pEnv)->GetObjectField( pEnv, owner, clientField);
220 pContext->ClientObj = (*pEnv)->NewWeakGlobalRef( pEnv, pContext->ClientObj); // must convert local ref to global to cache
221 pContext->Callback = (*pEnv)->GetMethodID( pEnv,
222 (*pEnv)->GetObjectClass( pEnv, pContext->ClientObj),
223 callbackName, callbackSig);
224 pContext->Callback2 = NULL; // not always used
225 }
226
227 return pContext;
228 }
229
230
231 static void ReportError( JNIEnv *pEnv, jobject target, jobject service, DNSServiceErrorType err)
232 // Invoke operationFailed() method on target with err.
233 {
234 jclass cls = (*pEnv)->GetObjectClass( pEnv, target);
235 jmethodID opFailed = (*pEnv)->GetMethodID( pEnv, cls, "operationFailed",
236 "(Lcom/apple/dnssd/DNSSDService;I)V");
237
238 (*pEnv)->CallVoidMethod( pEnv, target, opFailed, service, err);
239 }
240
241 JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv *pEnv, jobject pThis)
242 /* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
243 {
244 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
245 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
246
247 if ( contextField != 0)
248 {
249 OpContext *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
250 if ( pContext != NULL)
251 {
252 // MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
253 (*pEnv)->SetIntField( pEnv, pThis, contextField, 0);
254 if ( pContext->ServiceRef != NULL)
255 DNSServiceRefDeallocate( pContext->ServiceRef);
256
257 (*pEnv)->DeleteWeakGlobalRef( pEnv, pContext->JavaObj);
258 (*pEnv)->DeleteWeakGlobalRef( pEnv, pContext->ClientObj);
259 free( pContext);
260 }
261 }
262 }
263
264
265 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_BlockForData( JNIEnv *pEnv, jobject pThis, jint msTimeout)
266 /* Block for timeout ms (or forever if -1). Returns 1 if data present, 0 if timed out, -1 if not browsing. */
267 {
268 #if AUTO_CALLBACKS
269 return -1; // BlockForData() not supported with AUTO_CALLBACKS
270 #else // AUTO_CALLBACKS
271 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
272 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
273 jint rc = -1;
274
275 if ( contextField != 0)
276 {
277 OpContext *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
278 if ( pContext != NULL)
279 {
280 fd_set readFDs;
281 int sd = DNSServiceRefSockFD( pContext->ServiceRef);
282 struct timeval timeout = { msTimeout / 1000, 10 * (msTimeout % 1000) };
283 struct timeval *pTimeout = msTimeout == -1 ? NULL : &timeout;
284
285 FD_ZERO( &readFDs);
286 FD_SET( sd, &readFDs);
287
288 rc = select( sd + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, pTimeout);
289 }
290 }
291
292 return rc;
293 #endif // AUTO_CALLBACKS
294 }
295
296
297 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv *pEnv, jobject pThis)
298 /* Call through to DNSServiceProcessResult() while data remains on socket. */
299 {
300 #if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
301
302 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
303 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
304 OpContext *pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
305 DNSServiceErrorType err = kDNSServiceErr_BadState;
306
307 if ( pContext != NULL)
308 {
309 int sd = DNSServiceRefSockFD( pContext->ServiceRef);
310 fd_set readFDs;
311 struct timeval zeroTimeout = { 0, 0 };
312
313 pContext->Env = pEnv;
314
315 FD_ZERO( &readFDs);
316 FD_SET( sd, &readFDs);
317
318 err = kDNSServiceErr_NoError;
319 if (0 < select(sd + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout))
320 {
321 err = DNSServiceProcessResult(pContext->ServiceRef);
322 // Use caution here!
323 // We cannot touch any data structures associated with this operation!
324 // The DNSServiceProcessResult() routine should have invoked our callback,
325 // and our callback could have terminated the operation with op.stop();
326 // and that means HaltOperation() will have been called, which frees pContext.
327 // Basically, from here we just have to get out without touching any stale
328 // data structures that could blow up on us! Particularly, any attempt
329 // to loop here reading more results from the file descriptor is unsafe.
330 }
331 }
332 return err;
333 #endif // AUTO_CALLBACKS
334 }
335
336
337 static void DNSSD_API ServiceBrowseReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
338 DNSServiceErrorType errorCode, const char *serviceName, const char *regtype,
339 const char *replyDomain, void *context)
340 {
341 OpContext *pContext = (OpContext*) context;
342
343 SetupCallbackState( &pContext->Env);
344
345 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
346 {
347 if ( errorCode == kDNSServiceErr_NoError)
348 {
349 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj,
350 ( flags & kDNSServiceFlagsAdd) != 0 ? pContext->Callback : pContext->Callback2,
351 pContext->JavaObj, flags, interfaceIndex,
352 (*pContext->Env)->NewStringUTF( pContext->Env, serviceName),
353 (*pContext->Env)->NewStringUTF( pContext->Env, regtype),
354 (*pContext->Env)->NewStringUTF( pContext->Env, replyDomain));
355 }
356 else
357 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
358 }
359
360 TeardownCallbackState();
361 }
362
363 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *pEnv, jobject pThis,
364 jint flags, jint ifIndex, jstring regType, jstring domain)
365 {
366 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
367 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
368 OpContext *pContext = NULL;
369 DNSServiceErrorType err = kDNSServiceErr_NoError;
370
371 if ( contextField != 0)
372 pContext = NewContext( pEnv, pThis, "serviceFound",
373 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
374 else
375 err = kDNSServiceErr_BadParam;
376
377 if ( pContext != NULL)
378 {
379 const char *regStr = SafeGetUTFChars( pEnv, regType);
380 const char *domainStr = SafeGetUTFChars( pEnv, domain);
381
382 pContext->Callback2 = (*pEnv)->GetMethodID( pEnv,
383 (*pEnv)->GetObjectClass( pEnv, pContext->ClientObj),
384 "serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
385
386 err = DNSServiceBrowse( &pContext->ServiceRef, flags, ifIndex, regStr, domainStr, ServiceBrowseReply, pContext);
387 if ( err == kDNSServiceErr_NoError)
388 {
389 (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
390 }
391
392 SafeReleaseUTFChars( pEnv, regType, regStr);
393 SafeReleaseUTFChars( pEnv, domain, domainStr);
394 }
395 else
396 err = kDNSServiceErr_NoMemory;
397
398 return err;
399 }
400
401
402 static void DNSSD_API ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
403 DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget,
404 uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
405 {
406 OpContext *pContext = (OpContext*) context;
407 jclass txtCls;
408 jmethodID txtCtor;
409 jbyteArray txtBytes;
410 jobject txtObj;
411 jbyte *pBytes;
412
413 SetupCallbackState( &pContext->Env);
414
415 txtCls = (*pContext->Env)->FindClass( pContext->Env, "com/apple/dnssd/TXTRecord");
416 txtCtor = (*pContext->Env)->GetMethodID( pContext->Env, txtCls, "<init>", "([B)V");
417
418 if ( pContext->ClientObj != NULL && pContext->Callback != NULL && txtCtor != NULL &&
419 NULL != ( txtBytes = (*pContext->Env)->NewByteArray( pContext->Env, txtLen)))
420 {
421 if ( errorCode == kDNSServiceErr_NoError)
422 {
423 // Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
424 // pattern into a number here.
425 port = ( ((unsigned char*) &port)[0] << 8) | ((unsigned char*) &port)[1];
426
427 // Initialize txtBytes with contents of txtRecord
428 pBytes = (*pContext->Env)->GetByteArrayElements( pContext->Env, txtBytes, NULL);
429 memcpy( pBytes, txtRecord, txtLen);
430 (*pContext->Env)->ReleaseByteArrayElements( pContext->Env, txtBytes, pBytes, JNI_COMMIT);
431
432 // Construct txtObj with txtBytes
433 txtObj = (*pContext->Env)->NewObject( pContext->Env, txtCls, txtCtor, txtBytes);
434 (*pContext->Env)->DeleteLocalRef( pContext->Env, txtBytes);
435
436 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback,
437 pContext->JavaObj, flags, interfaceIndex,
438 (*pContext->Env)->NewStringUTF( pContext->Env, fullname),
439 (*pContext->Env)->NewStringUTF( pContext->Env, hosttarget),
440 port, txtObj);
441 }
442 else
443 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
444 }
445
446 TeardownCallbackState();
447 }
448
449 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv *pEnv, jobject pThis,
450 jint flags, jint ifIndex, jstring serviceName, jstring regType, jstring domain)
451 {
452 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
453 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
454 OpContext *pContext = NULL;
455 DNSServiceErrorType err = kDNSServiceErr_NoError;
456
457 if ( contextField != 0)
458 pContext = NewContext( pEnv, pThis, "serviceResolved",
459 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
460 else
461 err = kDNSServiceErr_BadParam;
462
463 if ( pContext != NULL)
464 {
465 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
466 const char *regStr = SafeGetUTFChars( pEnv, regType);
467 const char *domainStr = SafeGetUTFChars( pEnv, domain);
468
469 err = DNSServiceResolve( &pContext->ServiceRef, flags, ifIndex,
470 servStr, regStr, domainStr, ServiceResolveReply, pContext);
471 if ( err == kDNSServiceErr_NoError)
472 {
473 (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
474 }
475
476 SafeReleaseUTFChars( pEnv, serviceName, servStr);
477 SafeReleaseUTFChars( pEnv, regType, regStr);
478 SafeReleaseUTFChars( pEnv, domain, domainStr);
479 }
480 else
481 err = kDNSServiceErr_NoMemory;
482
483 return err;
484 }
485
486
487 static void DNSSD_API ServiceRegisterReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags,
488 DNSServiceErrorType errorCode, const char *serviceName,
489 const char *regType, const char *domain, void *context)
490 {
491 OpContext *pContext = (OpContext*) context;
492
493 SetupCallbackState( &pContext->Env);
494
495 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
496 {
497 if ( errorCode == kDNSServiceErr_NoError)
498 {
499 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback,
500 pContext->JavaObj, flags,
501 (*pContext->Env)->NewStringUTF( pContext->Env, serviceName),
502 (*pContext->Env)->NewStringUTF( pContext->Env, regType),
503 (*pContext->Env)->NewStringUTF( pContext->Env, domain));
504 }
505 else
506 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
507 }
508 TeardownCallbackState();
509 }
510
511 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv *pEnv, jobject pThis,
512 jint ifIndex, jint flags, jstring serviceName, jstring regType,
513 jstring domain, jstring host, jint port, jbyteArray txtRecord)
514 {
515 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
516 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
517 OpContext *pContext = NULL;
518 DNSServiceErrorType err = kDNSServiceErr_NoError;
519 jbyte *pBytes;
520 jsize numBytes;
521
522 if ( contextField != 0)
523 pContext = NewContext( pEnv, pThis, "serviceRegistered",
524 "(Lcom/apple/dnssd/DNSSDRegistration;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
525 else
526 err = kDNSServiceErr_BadParam;
527
528 if ( pContext != NULL)
529 {
530 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
531 const char *regStr = SafeGetUTFChars( pEnv, regType);
532 const char *domainStr = SafeGetUTFChars( pEnv, domain);
533 const char *hostStr = SafeGetUTFChars( pEnv, host);
534
535 // Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
536 // big-endian number into a 16-bit pattern here.
537 uint16_t portBits = port;
538 portBits = ( ((unsigned char*) &portBits)[0] << 8) | ((unsigned char*) &portBits)[1];
539
540 pBytes = txtRecord ? (*pEnv)->GetByteArrayElements( pEnv, txtRecord, NULL) : NULL;
541 numBytes = txtRecord ? (*pEnv)->GetArrayLength( pEnv, txtRecord) : 0;
542
543 err = DNSServiceRegister( &pContext->ServiceRef, flags, ifIndex, servStr, regStr,
544 domainStr, hostStr, portBits,
545 numBytes, pBytes, ServiceRegisterReply, pContext);
546 if ( err == kDNSServiceErr_NoError)
547 {
548 (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
549 }
550
551 if ( pBytes != NULL)
552 (*pEnv)->ReleaseByteArrayElements( pEnv, txtRecord, pBytes, 0);
553
554 SafeReleaseUTFChars( pEnv, serviceName, servStr);
555 SafeReleaseUTFChars( pEnv, regType, regStr);
556 SafeReleaseUTFChars( pEnv, domain, domainStr);
557 SafeReleaseUTFChars( pEnv, host, hostStr);
558 }
559 else
560 err = kDNSServiceErr_NoMemory;
561
562 return err;
563 }
564
565 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv *pEnv, jobject pThis,
566 jint flags, jint rrType, jbyteArray rData, jint ttl, jobject destObj)
567 {
568 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
569 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
570 jclass destCls = (*pEnv)->GetObjectClass( pEnv, destObj);
571 jfieldID recField = (*pEnv)->GetFieldID( pEnv, destCls, "fRecord", "I");
572 OpContext *pContext = NULL;
573 DNSServiceErrorType err = kDNSServiceErr_NoError;
574 jbyte *pBytes;
575 jsize numBytes;
576 DNSRecordRef recRef;
577
578 if ( contextField != 0)
579 pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, pThis, contextField);
580 if ( pContext == NULL || pContext->ServiceRef == NULL)
581 return kDNSServiceErr_BadParam;
582
583 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
584 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
585
586 err = DNSServiceAddRecord( pContext->ServiceRef, &recRef, flags, rrType, numBytes, pBytes, ttl);
587 if ( err == kDNSServiceErr_NoError)
588 {
589 (*pEnv)->SetIntField( pEnv, destObj, recField, (jint) recRef);
590 }
591
592 if ( pBytes != NULL)
593 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
594
595 return err;
596 }
597
598 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Update( JNIEnv *pEnv, jobject pThis,
599 jint flags, jbyteArray rData, jint ttl)
600 {
601 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
602 jfieldID ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
603 jfieldID recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
604 OpContext *pContext = NULL;
605 DNSServiceErrorType err = kDNSServiceErr_NoError;
606 jbyte *pBytes;
607 jsize numBytes;
608 DNSRecordRef recRef = NULL;
609
610 if ( ownerField != 0)
611 {
612 jobject ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
613 jclass ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
614 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
615 if ( contextField != 0)
616 pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
617 }
618 if ( recField != 0)
619 recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
620 if ( pContext == NULL || pContext->ServiceRef == NULL)
621 return kDNSServiceErr_BadParam;
622
623 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rData, NULL);
624 numBytes = (*pEnv)->GetArrayLength( pEnv, rData);
625
626 err = DNSServiceUpdateRecord( pContext->ServiceRef, recRef, flags, numBytes, pBytes, ttl);
627
628 if ( pBytes != NULL)
629 (*pEnv)->ReleaseByteArrayElements( pEnv, rData, pBytes, 0);
630
631 return err;
632 }
633
634 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSRecord_Remove( JNIEnv *pEnv, jobject pThis)
635 {
636 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
637 jfieldID ownerField = (*pEnv)->GetFieldID( pEnv, cls, "fOwner", "Lcom/apple/dnssd/AppleService;");
638 jfieldID recField = (*pEnv)->GetFieldID( pEnv, cls, "fRecord", "I");
639 OpContext *pContext = NULL;
640 DNSServiceErrorType err = kDNSServiceErr_NoError;
641 DNSRecordRef recRef = NULL;
642
643 if ( ownerField != 0)
644 {
645 jobject ownerObj = (*pEnv)->GetObjectField( pEnv, pThis, ownerField);
646 jclass ownerClass = (*pEnv)->GetObjectClass( pEnv, ownerObj);
647 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, ownerClass, "fNativeContext", "I");
648 if ( contextField != 0)
649 pContext = (OpContext*) (*pEnv)->GetIntField( pEnv, ownerObj, contextField);
650 }
651 if ( recField != 0)
652 recRef = (DNSRecordRef) (*pEnv)->GetIntField( pEnv, pThis, recField);
653 if ( pContext == NULL || pContext->ServiceRef == NULL)
654 return kDNSServiceErr_BadParam;
655
656 err = DNSServiceRemoveRecord( pContext->ServiceRef, recRef, 0);
657
658 return err;
659 }
660
661
662 static void DNSSD_API ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
663 DNSServiceErrorType errorCode, const char *serviceName,
664 uint16_t rrtype, uint16_t rrclass, uint16_t rdlen,
665 const void *rdata, uint32_t ttl, void *context)
666 {
667 OpContext *pContext = (OpContext*) context;
668 jbyteArray rDataObj;
669 jbyte *pBytes;
670
671 SetupCallbackState( &pContext->Env);
672
673 if ( pContext->ClientObj != NULL && pContext->Callback != NULL &&
674 NULL != ( rDataObj = (*pContext->Env)->NewByteArray( pContext->Env, rdlen)))
675 {
676 if ( errorCode == kDNSServiceErr_NoError)
677 {
678 // Initialize rDataObj with contents of rdata
679 pBytes = (*pContext->Env)->GetByteArrayElements( pContext->Env, rDataObj, NULL);
680 memcpy( pBytes, rdata, rdlen);
681 (*pContext->Env)->ReleaseByteArrayElements( pContext->Env, rDataObj, pBytes, JNI_COMMIT);
682
683 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj, pContext->Callback,
684 pContext->JavaObj, flags, interfaceIndex,
685 (*pContext->Env)->NewStringUTF( pContext->Env, serviceName),
686 rrtype, rrclass, rDataObj, ttl);
687 }
688 else
689 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
690 }
691 TeardownCallbackState();
692 }
693
694 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleQuery_CreateQuery( JNIEnv *pEnv, jobject pThis,
695 jint flags, jint ifIndex, jstring serviceName, jint rrtype, jint rrclass)
696 {
697 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
698 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
699 OpContext *pContext = NULL;
700 DNSServiceErrorType err = kDNSServiceErr_NoError;
701
702 if ( contextField != 0)
703 pContext = NewContext( pEnv, pThis, "queryAnswered",
704 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;II[BI)V");
705 else
706 err = kDNSServiceErr_BadParam;
707
708 if ( pContext != NULL)
709 {
710 const char *servStr = SafeGetUTFChars( pEnv, serviceName);
711
712 err = DNSServiceQueryRecord( &pContext->ServiceRef, flags, ifIndex, servStr,
713 rrtype, rrclass, ServiceQueryReply, pContext);
714 if ( err == kDNSServiceErr_NoError)
715 {
716 (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
717 }
718
719 SafeReleaseUTFChars( pEnv, serviceName, servStr);
720 }
721 else
722 err = kDNSServiceErr_NoMemory;
723
724 return err;
725 }
726
727
728 static void DNSSD_API DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
729 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
730 {
731 OpContext *pContext = (OpContext*) context;
732
733 SetupCallbackState( &pContext->Env);
734
735 if ( pContext->ClientObj != NULL && pContext->Callback != NULL)
736 {
737 if ( errorCode == kDNSServiceErr_NoError)
738 {
739 (*pContext->Env)->CallVoidMethod( pContext->Env, pContext->ClientObj,
740 ( flags & kDNSServiceFlagsAdd) != 0 ? pContext->Callback : pContext->Callback2,
741 pContext->JavaObj, flags, interfaceIndex,
742 (*pContext->Env)->NewStringUTF( pContext->Env, replyDomain));
743 }
744 else
745 ReportError( pContext->Env, pContext->ClientObj, pContext->JavaObj, errorCode);
746 }
747 TeardownCallbackState();
748 }
749
750 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDomainEnum_BeginEnum( JNIEnv *pEnv, jobject pThis,
751 jint flags, jint ifIndex)
752 {
753 jclass cls = (*pEnv)->GetObjectClass( pEnv, pThis);
754 jfieldID contextField = (*pEnv)->GetFieldID( pEnv, cls, "fNativeContext", "I");
755 OpContext *pContext = NULL;
756 DNSServiceErrorType err = kDNSServiceErr_NoError;
757
758 if ( contextField != 0)
759 pContext = NewContext( pEnv, pThis, "domainFound",
760 "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
761 else
762 err = kDNSServiceErr_BadParam;
763
764 if ( pContext != NULL)
765 {
766 pContext->Callback2 = (*pEnv)->GetMethodID( pEnv,
767 (*pEnv)->GetObjectClass( pEnv, pContext->ClientObj),
768 "domainLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;)V");
769
770 err = DNSServiceEnumerateDomains( &pContext->ServiceRef, flags, ifIndex,
771 DomainEnumReply, pContext);
772 if ( err == kDNSServiceErr_NoError)
773 {
774 (*pEnv)->SetIntField( pEnv, pThis, contextField, (jint) pContext);
775 }
776 }
777 else
778 err = kDNSServiceErr_NoMemory;
779
780 return err;
781 }
782
783
784 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv *pEnv, jobject pThis _UNUSED,
785 jstring serviceName, jstring regtype, jstring domain, jobjectArray pOut)
786 {
787 DNSServiceErrorType err = kDNSServiceErr_NoError;
788 const char *nameStr = SafeGetUTFChars( pEnv, serviceName);
789 const char *regStr = SafeGetUTFChars( pEnv, regtype);
790 const char *domStr = SafeGetUTFChars( pEnv, domain);
791 char buff[ kDNSServiceMaxDomainName + 1];
792
793 err = DNSServiceConstructFullName( buff, nameStr, regStr, domStr);
794
795 if ( err == kDNSServiceErr_NoError)
796 {
797 // pOut is expected to be a String[1] array.
798 (*pEnv)->SetObjectArrayElement( pEnv, pOut, 0, (*pEnv)->NewStringUTF( pEnv, buff));
799 }
800
801 SafeReleaseUTFChars( pEnv, serviceName, nameStr);
802 SafeReleaseUTFChars( pEnv, regtype, regStr);
803 SafeReleaseUTFChars( pEnv, domain, domStr);
804
805 return err;
806 }
807
808 JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv *pEnv, jobject pThis _UNUSED,
809 jint flags, jint ifIndex, jstring fullName,
810 jint rrtype, jint rrclass, jbyteArray rdata)
811 {
812 jbyte *pBytes;
813 jsize numBytes;
814 const char *nameStr = SafeGetUTFChars( pEnv, fullName);
815
816 pBytes = (*pEnv)->GetByteArrayElements( pEnv, rdata, NULL);
817 numBytes = (*pEnv)->GetArrayLength( pEnv, rdata);
818
819 DNSServiceReconfirmRecord( flags, ifIndex, nameStr, rrtype, rrclass, numBytes, pBytes);
820
821 if ( pBytes != NULL)
822 (*pEnv)->ReleaseByteArrayElements( pEnv, rdata, pBytes, 0);
823
824 SafeReleaseUTFChars( pEnv, fullName, nameStr);
825 }
826
827 #define LOCAL_ONLY_NAME "loo"
828
829 JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv *pEnv, jobject pThis _UNUSED,
830 jint ifIndex)
831 {
832 char *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
833
834 if (ifIndex != kDNSServiceInterfaceIndexLocalOnly)
835 p = if_indextoname( ifIndex, nameBuff );
836
837 return (*pEnv)->NewStringUTF( pEnv, p);
838 }
839
840
841 JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv *pEnv, jobject pThis _UNUSED,
842 jstring ifName)
843 {
844 uint32_t ifIndex = kDNSServiceInterfaceIndexLocalOnly;
845 const char *nameStr = SafeGetUTFChars( pEnv, ifName);
846
847 if (strcmp(nameStr, LOCAL_ONLY_NAME))
848 ifIndex = if_nametoindex( nameStr);
849
850 SafeReleaseUTFChars( pEnv, ifName, nameStr);
851
852 return ifIndex;
853 }
854
855
856 #if defined(_WIN32)
857 static char*
858 if_indextoname( DWORD ifIndex, char * nameBuff)
859 {
860 PIP_ADAPTER_INFO pAdapterInfo = NULL;
861 PIP_ADAPTER_INFO pAdapter = NULL;
862 DWORD dwRetVal = 0;
863 char * ifName = NULL;
864 ULONG ulOutBufLen = 0;
865
866 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
867 {
868 goto exit;
869 }
870
871 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
872
873 if (pAdapterInfo == NULL)
874 {
875 goto exit;
876 }
877
878 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
879
880 if (dwRetVal != NO_ERROR)
881 {
882 goto exit;
883 }
884
885 pAdapter = pAdapterInfo;
886 while (pAdapter)
887 {
888 if (pAdapter->Index == ifIndex)
889 {
890 // It would be better if we passed in the length of nameBuff to this
891 // function, so we would have absolute certainty that no buffer
892 // overflows would occur. Buffer overflows *shouldn't* occur because
893 // nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
894 strcpy( nameBuff, pAdapter->AdapterName );
895 ifName = nameBuff;
896 break;
897 }
898
899 pAdapter = pAdapter->Next;
900 }
901
902 exit:
903
904 if (pAdapterInfo != NULL)
905 {
906 free( pAdapterInfo );
907 pAdapterInfo = NULL;
908 }
909
910 return ifName;
911 }
912
913
914 static DWORD
915 if_nametoindex( const char * nameStr )
916 {
917 PIP_ADAPTER_INFO pAdapterInfo = NULL;
918 PIP_ADAPTER_INFO pAdapter = NULL;
919 DWORD dwRetVal = 0;
920 DWORD ifIndex = 0;
921 ULONG ulOutBufLen = 0;
922
923 if (GetAdaptersInfo( NULL, &ulOutBufLen) != ERROR_BUFFER_OVERFLOW)
924 {
925 goto exit;
926 }
927
928 pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
929
930 if (pAdapterInfo == NULL)
931 {
932 goto exit;
933 }
934
935 dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen );
936
937 if (dwRetVal != NO_ERROR)
938 {
939 goto exit;
940 }
941
942 pAdapter = pAdapterInfo;
943 while (pAdapter)
944 {
945 if (strcmp(pAdapter->AdapterName, nameStr) == 0)
946 {
947 ifIndex = pAdapter->Index;
948 break;
949 }
950
951 pAdapter = pAdapter->Next;
952 }
953
954 exit:
955
956 if (pAdapterInfo != NULL)
957 {
958 free( pAdapterInfo );
959 pAdapterInfo = NULL;
960 }
961
962 return ifIndex;
963 }
964 #endif