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