/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
Change History (most recent first):
$Log: JNISupport.c,v $
Revision 1.17 2006/08/14 23:25:08 cheshire
Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
Revision 1.16 2006/07/14 02:35:47 cheshire
Added (commented out) syslog debugging messages
Revision 1.15 2006/06/27 19:34:43 cheshire
<rdar://problem/4430023> txtRecord parameter of DNSServiceResolveReply() should be unsigned char *
Revision 1.14 2006/06/20 23:03:35 rpantos
<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
Revision 1.13 2005/10/26 01:52:24 cheshire
<rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
Revision 1.12 2005/07/13 19:20:32 cheshire
<rdar://problem/4175511> Race condition in Java API
Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
Revision 1.11 2005/07/11 01:55:21 cheshire
<rdar://problem/4175511> Race condition in Java API
Revision 1.10 2005/07/05 13:01:52 cheshire
<rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
Revision 1.9 2004/12/11 03:01:00 rpantos
<rdar://problem/3907498> Java DNSRecord API should be cleaned up
Revision 1.8 2004/11/30 23:51:05 cheshire
Remove double semicolons
Revision 1.7 2004/11/23 08:12:04 shersche
Implement if_nametoindex and if_indextoname for Win32 platforms
Revision 1.6 2004/11/23 03:41:14 cheshire
Change JNISupport.c to call if_indextoname & if_nametoindex directly.
(May require some additional glue code to work on Windows.)
Revision 1.5 2004/11/17 17:07:44 cheshire
Updated comment about AUTO_CALLBACKS
Revision 1.4 2004/11/12 03:23:09 rpantos
rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
Revision 1.3 2004/06/18 04:44:17 rpantos
Adapt to API unification on Windows
Revision 1.2 2004/05/28 23:34:42 ksekar
<rdar://problem/3672903>: Java project build errors
Revision 1.1 2004/04/30 16:29:35 rpantos
First checked in.
This file contains the platform support for DNSSD and related Java classes.
It is used to shim through to the underlying <dns_sd.h> API.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
// AUTO_CALLBACKS should be set to 1 if the underlying mDNS implementation fires response
// callbacks automatically (as in the early Windows prototypes).
// AUTO_CALLBACKS should be set to 0 if the client must call DNSServiceProcessResult() to
// invoke response callbacks (as is true on Mac OS X, Posix, Windows, etc.).
// (Invoking callbacks automatically on a different thread sounds attractive, but while
// the client gains by not needing to add an event source to its main event loop, it loses
// by being forced to deal with concurrency and locking, which can be a bigger burden.)
#ifndef AUTO_CALLBACKS
#define AUTO_CALLBACKS 0
#endif
#if !AUTO_CALLBACKS
#ifdef _WIN32
#include <winsock2.h>
#else //_WIN32
#endif // _WIN32
#endif // AUTO_CALLBACKS
#include <dns_sd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#else // _WIN32
#endif // _WIN32
#include <jni.h>
#include "DNSSD.java.h"
//#include <syslog.h>
// convenience definition
#ifdef __GNUC__
#else
#define _UNUSED
#endif
enum {
};
struct OpContext
{
};
// For AUTO_CALLBACKS, we must attach the callback thread to the Java VM prior to upcall.
#if AUTO_CALLBACKS
#endif
{
/* Ensure that caller & interface versions match. */
if ( callerVersion != kInterfaceVersion)
return kDNSServiceErr_Incompatible;
#if AUTO_CALLBACKS
{
return kDNSServiceErr_BadState;
}
#endif
// Set AppleDNSSD.hasAutoCallbacks
{
#if AUTO_CALLBACKS
#else
#endif
}
return kDNSServiceErr_NoError;
}
// Wrapper for JNI GetStringUTFChars() that returns NULL for null str.
{
}
// Wrapper for JNI GetStringUTFChars() that handles null str.
{
}
#if AUTO_CALLBACKS
{
}
static void TeardownCallbackState( void )
{
}
#else // AUTO_CALLBACKS
{
// No setup necessary if ProcessResults() has been called
}
static void TeardownCallbackState( void )
{
// No teardown necessary if ProcessResults() has been called
}
#endif // AUTO_CALLBACKS
const char *callbackName, const char *callbackSig)
// Create and initialize a new OpContext.
{
{
"fListener", "Lcom/apple/dnssd/BaseListener;");
pContext->JavaObj = (*pEnv)->NewWeakGlobalRef( pEnv, owner); // must convert local ref to global to cache;
pContext->ClientObj = (*pEnv)->NewWeakGlobalRef( pEnv, pContext->ClientObj); // must convert local ref to global to cache
}
return pContext;
}
// Invoke operationFailed() method on target with err.
{
"(Lcom/apple/dnssd/DNSSDService;I)V");
}
JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleService_HaltOperation( JNIEnv *pEnv, jobject pThis)
/* Deallocate the dns_sd service browser and set the Java object's fNativeContext field to 0. */
{
if ( contextField != 0)
{
{
// MUST clear fNativeContext first, BEFORE calling DNSServiceRefDeallocate()
}
}
}
/* Block until data arrives, or one second passes. Returns 1 if data present, 0 otherwise. */
{
// BlockForData() not supported with AUTO_CALLBACKS
#if !AUTO_CALLBACKS
if ( contextField != 0)
{
{
// Q: Why do we poll here?
// A: Because there's no other thread-safe way to do it.
// Mac OS X terminates a select() call if you close one of the sockets it's listening on, but Linux does not,
// and arguably Linux is correct (See <http://www.ussg.iu.edu/hypermail/linux/kernel/0405.1/0418.html>)
// The problem is that the Mac OS X behaviour assumes that it's okay for one thread to close a socket while
// some other thread is monitoring that socket in select(), but the difficulty is that there's no general way
// to make that thread-safe, because there's no atomic way to enter select() and release a lock simultaneously.
// If we try to do this without holding any lock, then right as we jump to the select() routine,
// some other thread could stop our operation (thereby closing the socket),
// and then that thread (or even some third, unrelated thread)
// could do some other DNS-SD operation (or some other operation that opens a new file descriptor)
// and then we'd blindly resume our fall into the select() call, now blocking on a file descriptor
// that may coincidentally have the same numerical value, but is semantically unrelated
// to the true file descriptor we thought we were blocking on.
// We can't stop this race condition from happening, but at least if we wake up once a second we can detect
// when fNativeContext has gone to zero, and thereby discover that we were blocking on the wrong fd.
}
}
#endif // !AUTO_CALLBACKS
return(0);
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleService_ProcessResults( JNIEnv *pEnv, jobject pThis)
/* Call through to DNSServiceProcessResult() while data remains on socket. */
{
#if !AUTO_CALLBACKS // ProcessResults() not supported with AUTO_CALLBACKS
{
{
// Use caution here!
// We cannot touch any data structures associated with this operation!
// The DNSServiceProcessResult() routine should have invoked our callback,
// and our callback could have terminated the operation with op.stop();
// and that means HaltOperation() will have been called, which frees pContext.
// Basically, from here we just have to get out without touching any stale
// data structures that could blow up on us! Particularly, any attempt
// to loop here reading more results from the file descriptor is unsafe.
}
}
return err;
#endif // AUTO_CALLBACKS
}
static void DNSSD_API ServiceBrowseReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
const char *replyDomain, void *context)
{
{
if ( errorCode == kDNSServiceErr_NoError)
{
}
else
}
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleBrowser_CreateBrowser( JNIEnv *pEnv, jobject pThis,
{
if ( contextField != 0)
else
{
"serviceLost", "(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
err = DNSServiceBrowse( &pContext->ServiceRef, flags, ifIndex, regStr, domainStr, ServiceBrowseReply, pContext);
if ( err == kDNSServiceErr_NoError)
{
}
}
else
return err;
}
static void DNSSD_API ServiceResolveReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
{
{
if ( errorCode == kDNSServiceErr_NoError)
{
// Since Java ints are defined to be big-endian, we canonicalize 'port' from a 16-bit
// pattern into a number here.
// Initialize txtBytes with contents of txtRecord
// Construct txtObj with txtBytes
}
else
}
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleResolver_CreateResolver( JNIEnv *pEnv, jobject pThis,
{
if ( contextField != 0)
"(Lcom/apple/dnssd/DNSSDService;IILjava/lang/String;Ljava/lang/String;ILcom/apple/dnssd/TXTRecord;)V");
else
{
if ( err == kDNSServiceErr_NoError)
{
}
}
else
return err;
}
{
{
if ( errorCode == kDNSServiceErr_NoError)
{
}
else
}
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_BeginRegister( JNIEnv *pEnv, jobject pThis,
{
//syslog(LOG_ERR, "BR");
//syslog(LOG_ERR, "BR: contextField %d", contextField);
if ( contextField != 0)
else
{
//syslog(LOG_ERR, "BR: regStr %s", regStr);
// Since Java ints are defined to be big-endian, we de-canonicalize 'port' from a
// big-endian number into a 16-bit pattern here.
if ( err == kDNSServiceErr_NoError)
{
}
}
else
return err;
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRegistration_AddRecord( JNIEnv *pEnv, jobject pThis,
{
if ( contextField != 0)
return kDNSServiceErr_BadParam;
if ( err == kDNSServiceErr_NoError)
{
}
return err;
}
{
if ( ownerField != 0)
{
if ( contextField != 0)
}
if ( recField != 0)
return kDNSServiceErr_BadParam;
return err;
}
{
if ( ownerField != 0)
{
if ( contextField != 0)
}
if ( recField != 0)
return kDNSServiceErr_BadParam;
return err;
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_CreateConnection( JNIEnv *pEnv, jobject pThis)
{
if ( contextField != 0)
else
{
if ( err == kDNSServiceErr_NoError)
{
}
}
else
return err;
}
struct RecordRegistrationRef
{
};
{
{
if ( errorCode == kDNSServiceErr_NoError)
{
}
else
}
free( regEnvelope);
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleRecordRegistrar_RegisterRecord( JNIEnv *pEnv, jobject pThis,
{
if ( contextField != 0)
return kDNSServiceErr_BadParam;
if ( regEnvelope == NULL)
return kDNSServiceErr_NoMemory;
regEnvelope->RecordObj = (*pEnv)->NewWeakGlobalRef( pEnv, destObj); // must convert local ref to global to cache
if ( err == kDNSServiceErr_NoError)
{
}
else
{
free( regEnvelope);
}
return err;
}
static void DNSSD_API ServiceQueryReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
{
{
if ( errorCode == kDNSServiceErr_NoError)
{
// Initialize rDataObj with contents of rdata
}
else
}
}
{
if ( contextField != 0)
else
{
if ( err == kDNSServiceErr_NoError)
{
}
}
else
return err;
}
static void DNSSD_API DomainEnumReply( DNSServiceRef sdRef _UNUSED, DNSServiceFlags flags, uint32_t interfaceIndex,
{
{
if ( errorCode == kDNSServiceErr_NoError)
{
}
else
}
}
{
if ( contextField != 0)
else
{
if ( err == kDNSServiceErr_NoError)
{
}
}
else
return err;
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_ConstructName( JNIEnv *pEnv, jobject pThis _UNUSED,
{
if ( err == kDNSServiceErr_NoError)
{
// pOut is expected to be a String[1] array.
}
return err;
}
JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv *pEnv, jobject pThis _UNUSED,
{
}
JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv *pEnv, jobject pThis _UNUSED,
{
}
JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv *pEnv, jobject pThis _UNUSED,
{
return ifIndex;
}
#if defined(_WIN32)
static char*
{
{
goto exit;
}
if (pAdapterInfo == NULL)
{
goto exit;
}
{
goto exit;
}
while (pAdapter)
{
{
// It would be better if we passed in the length of nameBuff to this
// function, so we would have absolute certainty that no buffer
// overflows would occur. Buffer overflows *shouldn't* occur because
// nameBuff is of size MAX_ADAPTER_NAME_LENGTH.
break;
}
}
exit:
if (pAdapterInfo != NULL)
{
free( pAdapterInfo );
pAdapterInfo = NULL;
}
return ifName;
}
static DWORD
{
{
goto exit;
}
if (pAdapterInfo == NULL)
{
goto exit;
}
{
goto exit;
}
while (pAdapter)
{
{
break;
}
}
exit:
if (pAdapterInfo != NULL)
{
free( pAdapterInfo );
pAdapterInfo = NULL;
}
return ifIndex;
}
#endif