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