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 
  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 
 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 
 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
 145 static void SetupCallbackState( JNIEnv **ppEnv)
 146 {
 147     (*gJavaVM)->AttachCurrentThread( gJavaVM, (void**) ppEnv, NULL);
 148 }
 149 
 150 static void TeardownCallbackState( void )
 151 {
 152     (*gJavaVM)->DetachCurrentThread( gJavaVM);
 153 }
 154 
 155 #else   // AUTO_CALLBACKS
 156 
 157 static void SetupCallbackState( JNIEnv **ppEnv _UNUSED)
 158 {
 159     // No setup necessary if ProcessResults() has been called
 160 }
 161 
 162 static void TeardownCallbackState( void )
 163 {
 164     // No teardown necessary if ProcessResults() has been called
 165 }
 166 #endif  // AUTO_CALLBACKS
 167 
 168 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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*
 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
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 #ifndef MDNS_VERSIONSTR_NODTS
1073 const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
1074 #else
1075 const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion);
1076 #endif