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