/* -*- 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.
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.
*/
// 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
// When compiling with "-Wshadow" set, including jni.h produces the following error:
// /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration
// To work around this, we use the preprocessor to map the identifier 'index', which appears harmlessly in function prototype declarations,
// to something 'jni_index', which doesn't conflict
#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 != kInterfaceVersionCurrent)
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,
{
p = P2P_NAME;
}
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
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
// To expand "version" to its value before making the string, use STRINGIFY(version) instead
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
// NOT static -- otherwise the compiler may optimize it out
// The "@(#) " pattern is a special prefix the "what" command looks for
#ifndef MDNS_VERSIONSTR_NODTS
const char VersionString_SCCS[] = "@(#) libjdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
#else
#endif