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