mdnsds: implement bonjour fallback on windows

* background task requiring no special privilegies (apart firewall)
* started by zeroconf only if bonjour is not installed/not working
* avoids console
* remove some compilation warnings

Change-Id: I50a6aee477ccf681a8e8ab084059190091954006
Reviewed-by: Jarek Kobus <jaroslaw.kobus@nokia.com>
This commit is contained in:
Fawzi Mohamed
2012-03-08 20:10:43 +01:00
parent a9e7e07b45
commit 71949ad4a2
24 changed files with 19161 additions and 3838 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
MessageIdTypedef=WORD
LanguageNames=(English=0x409:MSG00409)
MessageId=100
SymbolicName=MDNSRESPONDER_LOG
Severity=Success
Facility=Application
Language=English
%1
.

View File

@@ -0,0 +1,484 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2003-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
// <rdar://problem/4278931> Doesn't compile correctly with latest Platform SDK
#if !defined(_WIN32_DCOM)
# define _WIN32_DCOM
#endif
#include "Firewall.h"
#include <windows.h>
#include <crtdbg.h>
#include <netfw.h>
#include <objbase.h>
#include <oleauto.h>
static const int kMaxTries = 30;
static const int kRetrySleepPeriod = 1 * 1000; // 1 second
static OSStatus
mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile)
{
INetFwMgr * fwMgr = NULL;
INetFwPolicy * fwPolicy = NULL;
int numRetries = 0;
HRESULT err = kNoErr;
_ASSERT(fwProfile != NULL);
*fwProfile = NULL;
// Use COM to get a reference to the firewall settings manager. This
// call will fail on anything other than XP SP2
err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
require(SUCCEEDED(err) && ( fwMgr != NULL ), exit);
// Use the reference to get the local firewall policy
err = fwMgr->get_LocalPolicy(&fwPolicy);
require(SUCCEEDED(err) && ( fwPolicy != NULL ), exit);
// Use the reference to get the extant profile. Empirical evidence
// suggests that there is the potential for a race condition when a system
// service whose startup type is automatic calls this method.
// This is true even when the service declares itself to be dependent
// on the firewall service. Re-trying the method will succeed within
// a few seconds.
do
{
err = fwPolicy->get_CurrentProfile(fwProfile);
if (err)
{
Sleep(kRetrySleepPeriod);
}
}
while (err && (numRetries++ < kMaxTries));
require(SUCCEEDED(err), exit);
err = kNoErr;
exit:
// Release temporary COM objects
if (fwPolicy != NULL)
{
fwPolicy->Release();
}
if (fwMgr != NULL)
{
fwMgr->Release();
}
return err;
}
static void
mDNSFirewallCleanup
(
IN INetFwProfile * fwProfile
)
{
// Call Release on the COM reference.
if (fwProfile != NULL)
{
fwProfile->Release();
}
}
static OSStatus
mDNSFirewallAppIsEnabled
(
IN INetFwProfile * fwProfile,
IN const wchar_t * fwProcessImageFileName,
OUT BOOL * fwAppEnabled
)
{
BSTR fwBstrProcessImageFileName = NULL;
VARIANT_BOOL fwEnabled;
INetFwAuthorizedApplication * fwApp = NULL;
INetFwAuthorizedApplications* fwApps = NULL;
OSStatus err = kNoErr;
_ASSERT(fwProfile != NULL);
_ASSERT(fwProcessImageFileName != NULL);
_ASSERT(fwAppEnabled != NULL);
*fwAppEnabled = FALSE;
// Get the list of authorized applications
err = fwProfile->get_AuthorizedApplications(&fwApps);
require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
require_action( ( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
// Look for us
err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
if (SUCCEEDED(err) && ( fwApp != NULL ) )
{
// It's listed, but is it enabled?
err = fwApp->get_Enabled(&fwEnabled);
require(SUCCEEDED(err), exit);
if (fwEnabled != VARIANT_FALSE)
{
// Yes, it's enabled
*fwAppEnabled = TRUE;
}
}
err = kNoErr;
exit:
// Deallocate the BSTR
if ( fwBstrProcessImageFileName != NULL )
{
SysFreeString(fwBstrProcessImageFileName);
}
// Release the COM objects
if (fwApp != NULL)
{
fwApp->Release();
}
if (fwApps != NULL)
{
fwApps->Release();
}
return err;
}
static OSStatus
mDNSFirewallAddApp
(
IN INetFwProfile * fwProfile,
IN const wchar_t * fwProcessImageFileName,
IN const wchar_t * fwName
)
{
BOOL fwAppEnabled;
BSTR fwBstrName = NULL;
BSTR fwBstrProcessImageFileName = NULL;
INetFwAuthorizedApplication * fwApp = NULL;
INetFwAuthorizedApplications* fwApps = NULL;
OSStatus err = S_OK;
_ASSERT(fwProfile != NULL);
_ASSERT(fwProcessImageFileName != NULL);
_ASSERT(fwName != NULL);
// First check to see if the application is already authorized.
err = mDNSFirewallAppIsEnabled( fwProfile, fwProcessImageFileName, &fwAppEnabled );
require_noerr(err, exit);
// Only add the application if it isn't enabled
if (!fwAppEnabled)
{
// Get the list of authorized applications
err = fwProfile->get_AuthorizedApplications(&fwApps);
require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
// Create an instance of an authorized application.
err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp );
require(SUCCEEDED(err) && ( fwApp != NULL ), exit);
fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
require_action(( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
// Set the executable file name
err = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
require(SUCCEEDED(err), exit);
fwBstrName = SysAllocString(fwName);
require_action( ( fwBstrName != NULL ) && ( SysStringLen(fwBstrName) > 0 ), exit, err = kNoMemoryErr);
// Set the friendly name
err = fwApp->put_Name(fwBstrName);
require(SUCCEEDED(err), exit);
// Now add the application
err = fwApps->Add(fwApp);
require(SUCCEEDED(err), exit);
}
err = kNoErr;
exit:
// Deallocate the BSTR objects
if ( fwBstrName != NULL )
{
SysFreeString(fwBstrName);
}
if ( fwBstrProcessImageFileName != NULL )
{
SysFreeString(fwBstrProcessImageFileName);
}
// Release the COM objects
if (fwApp != NULL)
{
fwApp->Release();
}
if (fwApps != NULL)
{
fwApps->Release();
}
return err;
}
static OSStatus
mDNSFirewallIsFileAndPrintSharingEnabled
(
IN INetFwProfile * fwProfile,
OUT BOOL * fwServiceEnabled
)
{
VARIANT_BOOL fwEnabled;
INetFwService* fwService = NULL;
INetFwServices* fwServices = NULL;
OSStatus err = S_OK;
_ASSERT(fwProfile != NULL);
_ASSERT(fwServiceEnabled != NULL);
*fwServiceEnabled = FALSE;
// Retrieve the globally open ports collection.
err = fwProfile->get_Services(&fwServices);
require( SUCCEEDED( err ), exit );
// Attempt to retrieve the globally open port.
err = fwServices->Item(NET_FW_SERVICE_FILE_AND_PRINT, &fwService);
require( SUCCEEDED( err ), exit );
// Find out if the globally open port is enabled.
err = fwService->get_Enabled(&fwEnabled);
require( SUCCEEDED( err ), exit );
if (fwEnabled != VARIANT_FALSE)
{
*fwServiceEnabled = TRUE;
}
exit:
// Release the globally open port.
if (fwService != NULL)
{
fwService->Release();
}
// Release the globally open ports collection.
if (fwServices != NULL)
{
fwServices->Release();
}
return err;
}
OSStatus
mDNSAddToFirewall
(
LPWSTR executable,
LPWSTR name
)
{
INetFwProfile * fwProfile = NULL;
HRESULT comInit = E_FAIL;
OSStatus err = kNoErr;
// Initialize COM.
comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
// Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
// initialized with a different mode.
if (comInit != RPC_E_CHANGED_MODE)
{
err = comInit;
require(SUCCEEDED(err), exit);
}
// Connect to the firewall
err = mDNSFirewallInitialize(&fwProfile);
require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit);
// Add us to the list of exempt programs
err = mDNSFirewallAddApp( fwProfile, executable, name );
require_noerr(err, exit);
exit:
// Disconnect from the firewall
if ( fwProfile != NULL )
{
mDNSFirewallCleanup(fwProfile);
}
// De-initialize COM
if (SUCCEEDED(comInit))
{
CoUninitialize();
}
return err;
}
BOOL
mDNSIsFileAndPrintSharingEnabled( BOOL * retry )
{
INetFwProfile * fwProfile = NULL;
HRESULT comInit = E_FAIL;
BOOL enabled = FALSE;
OSStatus err = kNoErr;
// Initialize COM.
*retry = FALSE;
comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
// Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
// initialized with a different mode.
if (comInit != RPC_E_CHANGED_MODE)
{
*retry = TRUE;
err = comInit;
require(SUCCEEDED(err), exit);
}
// Connect to the firewall
err = mDNSFirewallInitialize(&fwProfile);
require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit);
err = mDNSFirewallIsFileAndPrintSharingEnabled( fwProfile, &enabled );
require_noerr( err, exit );
exit:
// Disconnect from the firewall
if ( fwProfile != NULL )
{
mDNSFirewallCleanup(fwProfile);
}
// De-initialize COM
if (SUCCEEDED(comInit))
{
CoUninitialize();
}
return enabled;
}

View File

@@ -0,0 +1,79 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2003-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifndef _Firewall_h
#define _Firewall_h
#include "CommonServices.h"
#include "DebugServices.h"
#if defined(__cplusplus)
extern "C"
{
#endif
OSStatus
mDNSAddToFirewall
(
LPWSTR executable,
LPWSTR name
);
BOOL
mDNSIsFileAndPrintSharingEnabled( BOOL * retry );
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,906 @@
/* -*- 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifdef _LEGACY_NAT_TRAVERSAL_
#include "stdlib.h" // For strtol()
#include "string.h" // For strlcpy(), For strncpy(), strncasecmp()
#if defined( WIN32 )
# include <winsock2.h>
# include <ws2tcpip.h>
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define mDNSASLLog( UUID, SUBDOMAIN, RESULT, SIGNATURE, FORMAT, ... ) ;
static int
inet_pton( int family, const char * addr, void * dst )
{
struct sockaddr_storage ss;
int sslen = sizeof( ss );
ZeroMemory( &ss, sizeof( ss ) );
ss.ss_family = (ADDRESS_FAMILY)family;
if ( WSAStringToAddressA( (LPSTR)addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
{
if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
else return 0;
}
else return 0;
}
#else
# include <arpa/inet.h> // For inet_pton()
#endif
#include "mDNSEmbeddedAPI.h"
#include "uDNS.h" // For natTraversalHandleAddressReply() etc.
// used to format SOAP port mapping arguments
typedef struct Property_struct
{
char *name;
char *type;
char *value;
} Property;
// All of the text parsing in this file is intentionally transparent so that we know exactly
// what's being done to the text, with an eye towards preventing security problems.
// This is an evolving list of useful acronyms to know. Please add to it at will.
// ST Service Type
// NT Notification Type
// USN Unique Service Name
// UDN Unique Device Name
// UUID Universally Unique Identifier
// URN/urn Universal Resource Name
// Forward declaration because of circular reference:
// SendPortMapRequest -> SendSOAPMsgControlAction -> MakeTCPConnection -> tcpConnectionCallback -> handleLNTPortMappingResponse
// In the event of a port conflict, handleLNTPortMappingResponse then increments tcpInfo->retries and calls back to SendPortMapRequest to try again
mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (mDNSu16)(n)->tcpInfo.retries)
// Note that this function assumes src is already NULL terminated
mDNSlocal void AllocAndCopy(mDNSu8 **const dst, const mDNSu8 *const src)
{
if (src == mDNSNULL) return;
if ((*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
{ LogMsg("AllocAndCopy: can't allocate string"); return; }
strcpy((char*)*dst, (char*)src);
}
// This function does a simple parse of an HTTP URL that may include a hostname, port, and path
// If found in the URL, addressAndPort and path out params will point to newly allocated space (and will leak if they were previously pointing at allocated space)
mDNSlocal mStatus ParseHttpUrl(const mDNSu8 *ptr, const mDNSu8 *const end, mDNSu8 **const addressAndPort, mDNSIPPort *const port, mDNSu8 **const path)
{
// if the data begins with "http://", we assume there is a hostname and possibly a port number
if (end - ptr >= 7 && strncasecmp((char*)ptr, "http://", 7) == 0)
{
int i;
const mDNSu8 *stop = end;
const mDNSu8 *addrPtr = mDNSNULL;
ptr += 7; //skip over "http://"
if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; }
// find the end of the host:port
addrPtr = ptr;
for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break;
// allocate the buffer (len i+1 so we have space to terminate the string)
if ((*addressAndPort = mDNSPlatformMemAllocate(i+1)) == mDNSNULL)
{ LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; }
strncpy((char*)*addressAndPort, (char*)ptr, i);
(*addressAndPort)[i] = '\0';
// find the port number in the string, by looking backwards for the ':'
stop = ptr; // can't go back farther than the original start
ptr = addrPtr; // move ptr to the path part
for (addrPtr--; addrPtr>stop; addrPtr--)
{
if (*addrPtr == ':')
{
addrPtr++; // skip over ':'
*port = mDNSOpaque16fromIntVal((mDNSu16)strtol((char*)addrPtr, mDNSNULL, 10)); // store it properly converted
break;
}
}
}
// ptr should now point to the first character we haven't yet processed
// everything that remains is the path
if (path && ptr < end)
{
if ((*path = mDNSPlatformMemAllocate((mDNSu32)(end - ptr) + 1)) == mDNSNULL)
{ LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; }
strncpy((char*)*path, (char*)ptr, end - ptr);
(*path)[end - ptr] = '\0';
}
return mStatus_NoError;
}
enum
{
HTTPCode_NeedMoreData = -1, // No code found in stream
HTTPCode_Other = -2, // Valid code other than those below found in stream
HTTPCode_Bad = -3,
HTTPCode_200 = 200,
HTTPCode_404 = 404,
HTTPCode_500 = 500,
};
mDNSlocal mDNSs16 ParseHTTPResponseCode(const mDNSu8 **const data, const mDNSu8 *const end)
{
const mDNSu8 *ptr = *data;
const mDNSu8 *code;
if (end - ptr < 5) return HTTPCode_NeedMoreData;
if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad;
ptr += 5;
// should we care about the HTTP protocol version?
// look for first space, which must come before first LF
while (ptr && ptr != end)
{
if (*ptr == '\n') return HTTPCode_Bad;
if (*ptr == ' ') break;
ptr++;
}
if (ptr == end) return HTTPCode_NeedMoreData;
ptr++;
if (end - ptr < 3) return HTTPCode_NeedMoreData;
code = ptr;
ptr += 3;
while (ptr && ptr != end)
{
if (*ptr == '\n') break;
ptr++;
}
if (ptr == end) return HTTPCode_NeedMoreData;
*data = ++ptr;
if (memcmp((char*)code, "200", 3) == 0) return HTTPCode_200;
if (memcmp((char*)code, "404", 3) == 0) return HTTPCode_404;
if (memcmp((char*)code, "500", 3) == 0) return HTTPCode_500;
LogInfo("ParseHTTPResponseCode found unexpected result code: %c%c%c", code[0], code[1], code[2]);
return HTTPCode_Other;
}
// This function parses the xml body of the device description response from the router. Basically, we look to
// make sure this is a response referencing a service we care about (WANIPConnection or WANPPPConnection),
// look for the "controlURL" header immediately following, and copy the addressing and URL info we need
mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
{
mDNS *m = tcpInfo->m;
const mDNSu8 *ptr = tcpInfo->Reply;
const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
const mDNSu8 *stop;
mDNSs16 http_result;
if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need
http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
if (http_result == HTTPCode_404) LNT_ClearState(m);
if (http_result != HTTPCode_200)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result);
return;
}
// Always reset our flag to use WANIPConnection. We'll use WANPPPConnection if we find it and don't find WANIPConnection.
m->UPnPWANPPPConnection = mDNSfalse;
// find either service we care about
while (ptr && ptr < end)
{
if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
ptr++;
}
if (ptr == end)
{
ptr = tcpInfo->Reply;
while (ptr && ptr < end)
{
if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0))
{
m->UPnPWANPPPConnection = mDNStrue;
break;
}
ptr++;
}
}
if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }
// find "controlURL", starting from where we left off
while (ptr && ptr < end)
{
if ((*ptr & 0xDF) == 'C' && (strncasecmp((char*)ptr, "controlURL", 10) == 0)) break; // find the first 'c'; is this controlURL? if not, keep looking
ptr++;
}
if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
ptr += 11; // skip over "controlURL>"
if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
// find the end of the controlURL element
for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
// fill in default port
m->UPnPSOAPPort = m->UPnPRouterPort;
// free string pointers and set to NULL
if (m->UPnPSOAPAddressString != mDNSNULL)
{
mDNSPlatformMemFree(m->UPnPSOAPAddressString);
m->UPnPSOAPAddressString = mDNSNULL;
}
if (m->UPnPSOAPURL != mDNSNULL)
{
mDNSPlatformMemFree(m->UPnPSOAPURL);
m->UPnPSOAPURL = mDNSNULL;
}
if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return;
// the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc"
if (m->UPnPSOAPAddressString == mDNSNULL)
{
ptr = tcpInfo->Reply;
while (ptr && ptr < end)
{
if ((*ptr & 0xDF) == 'U' && (strncasecmp((char*)ptr, "URLBase", 7) == 0)) break;
ptr++;
}
if (ptr < end) // found URLBase
{
LogInfo("handleLNTDeviceDescriptionResponse: found URLBase");
ptr += 8; // skip over "URLBase>"
// find the end of the URLBase element
for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError)
{
LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase");
}
}
// if all else fails, use the router address string
if (m->UPnPSOAPAddressString == mDNSNULL) AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
}
if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL");
else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL);
if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL");
else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL);
}
mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
{
mDNS *m = tcpInfo->m;
mDNSu16 err = NATErr_None;
mDNSv4Addr ExtAddr;
const mDNSu8 *ptr = tcpInfo->Reply;
const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
mDNSu8 *addrend;
static char tagname[20] = { 'N','e','w','E','x','t','e','r','n','a','l','I','P','A','d','d','r','e','s','s' };
// Array NOT including a terminating nul
// LogInfo("handleLNTGetExternalAddressResponse: %s", ptr);
mDNSs16 http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
if (http_result == HTTPCode_404) LNT_ClearState(m);
if (http_result != HTTPCode_200)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
return;
}
while (ptr < end && strncasecmp((char*)ptr, tagname, sizeof(tagname))) ptr++;
ptr += sizeof(tagname); // Skip over "NewExternalIPAddress"
while (ptr < end && *ptr != '>') ptr++;
ptr += 1; // Skip over ">"
// Find the end of the address and terminate the string so inet_pton() can convert it
// (Might be better to copy this to a local string here -- this is overwriting tcpInfo->Reply in-place
addrend = (mDNSu8*)ptr;
while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++;
if (addrend >= end) return;
*addrend = 0;
if (inet_pton(AF_INET, (char*)ptr, &ExtAddr) <= 0)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "inet_pton", "");
LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr);
err = NATErr_NetFail;
ExtAddr = zerov4Addr;
}
if (!err) LogInfo("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
natTraversalHandleAddressReply(m, err, ExtAddr);
}
mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
{
mDNS *m = tcpInfo->m;
mDNSIPPort extport = zeroIPPort;
const mDNSu8 *ptr = tcpInfo->Reply;
const mDNSu8 *const end = tcpInfo->Reply + tcpInfo->nread;
NATTraversalInfo *natInfo;
mDNSs16 http_result;
for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break; }
if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
if (http_result == HTTPCode_200)
{
LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
// Make sure to compute extport *before* we zero tcpInfo->retries
extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
tcpInfo->retries = 0;
natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
}
else if (http_result == HTTPCode_500)
{
while (ptr && ptr != end)
{
if (((*ptr & 0xDF) == 'C' && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) ||
(*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
{
if (tcpInfo->retries < 100)
{
tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo);
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries);
}
else
{
LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries);
natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
}
return;
}
ptr++;
}
}
else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response");
else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code");
else if (http_result == HTTPCode_404) LNT_ClearState(m);
if (http_result != HTTPCode_200 && http_result != HTTPCode_500)
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
}
mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
{
tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); } // If we found it, cut it from our list and free the memory
}
mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
{
mStatus status = mStatus_NoError;
tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
mDNSBool closed = mDNSfalse;
long n = 0;
long nsent = 0;
if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
// The handlers below expect to be called with the lock held
mDNS_Lock(tcpInfo->m);
if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; }
if (ConnectionEstablished) // connection is established - send the message
{
LogInfo("tcpConnectionCallback: connection established, sending message");
nsent = mDNSPlatformWriteTCP(sock, (char*)tcpInfo->Request, tcpInfo->requestLen);
if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
}
else
{
n = mDNSPlatformReadTCP(sock, (char*)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
if (n < 0) { LogInfo("tcpConnectionCallback - read returned %d", n); status = mStatus_ConnFailed; goto exit; }
else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
tcpInfo->nread += n;
LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
if (tcpInfo->nread > LNT_MAXBUFSIZE)
{
LogInfo("result truncated...");
tcpInfo->nread = LNT_MAXBUFSIZE;
}
switch (tcpInfo->op)
{
case LNTDiscoveryOp: handleLNTDeviceDescriptionResponse (tcpInfo); break;
case LNTExternalAddrOp: handleLNTGetExternalAddressResponse(tcpInfo); break;
case LNTPortMapOp: handleLNTPortMappingResponse (tcpInfo); break;
case LNTPortMapDeleteOp: status = mStatus_ConfigChanged; break;
default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
}
}
exit:
if (err || status)
{
mDNS *m = tcpInfo->m;
switch (tcpInfo->op)
{
case LNTDiscoveryOp: if (m->UPnPSOAPAddressString == mDNSNULL)
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", "");
if (m->UPnPSOAPURL == mDNSNULL)
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", "");
if (m->UPnPSOAPAddressString && m->UPnPSOAPURL)
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", "");
break;
case LNTExternalAddrOp: mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest",
mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success",
mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", "");
break;
case LNTPortMapOp: if (tcpInfo->parentNATInfo)
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success",
(tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result);
break;
case LNTPortMapDeleteOp: break;
default: break;
}
mDNSPlatformTCPCloseConnection(tcpInfo->sock);
tcpInfo->sock = mDNSNULL;
if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
if (tcpInfo->Reply ) { mDNSPlatformMemFree(tcpInfo->Reply); tcpInfo->Reply = mDNSNULL; }
}
if (tcpInfo) mDNS_Unlock(tcpInfo->m);
if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
}
mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op)
{
mStatus err = mStatus_NoError;
mDNSIPPort srcport = zeroIPPort;
if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port))
{ LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); }
info->m = m;
info->Address = *Addr;
info->Port = Port;
info->op = op;
info->nread = 0;
info->replyLen = LNT_MAXBUFSIZE;
if (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE); // reuse previously allocated buffer
else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport);
if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
if (err == mStatus_ConnPending) err = mStatus_NoError;
else if (err == mStatus_ConnEstablished)
{
mDNS_DropLockBeforeCallback();
tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError);
mDNS_ReclaimLockAfterCallback();
err = mStatus_NoError;
}
else
{
// Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
LogInfo("LNT MakeTCPConnection: connection failed");
mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above
info->sock = mDNSNULL;
mDNSPlatformMemFree(info->Reply);
info->Reply = mDNSNULL;
}
return(err);
}
mDNSlocal unsigned int AddSOAPArguments(char *const buf, const unsigned int maxlen, const int numArgs, const Property *const a)
{
static const char f1[] = "<%s>%s</%s>";
static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
int i, len = 0;
*buf = 0;
for (i = 0; i < numArgs; i++)
{
if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
else len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name, a[i].value, a[i].name);
}
return(len);
}
mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, const char *const Action, const int numArgs, const Property *const Arguments, const LNTOp_t op)
{
// SOAP message header format -
// - control URL
// - action (string)
// - router's host/port ("host:port")
// - content-length
static const char header[] =
"POST %s HTTP/1.1\r\n"
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"SOAPAction: \"urn:schemas-upnp-org:service:WAN%sConnection:1#%s\"\r\n"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
"Host: %s\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"%s\r\n";
static const char body1[] =
"<?xml version=\"1.0\"?>\r\n"
"<SOAP-ENV:Envelope"
" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""
" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<SOAP-ENV:Body>"
"<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WAN%sConnection:1\">";
static const char body2[] =
"</m:%s>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>\r\n";
mStatus err;
char *body = (char*)&m->omsg; // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
int bodyLen;
if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL) // if no SOAP URL or address exists get out here
{ LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; }
// Create body
bodyLen = mDNS_snprintf (body, sizeof(m->omsg), body1, Action, m->UPnPWANPPPConnection ? "PPP" : "IP");
bodyLen += AddSOAPArguments(body + bodyLen, sizeof(m->omsg) - bodyLen, numArgs, Arguments);
bodyLen += mDNS_snprintf (body + bodyLen, sizeof(m->omsg) - bodyLen, body2, Action);
// Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body);
err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
return err;
}
// Build port mapping request with new port (up to max) and send it
mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
{
char externalPort[6];
char internalPort[6];
char localIPAddrString[30];
char publicPortString[40];
Property propArgs[8];
mDNSu16 ReqPortNum = RequestedPortNum(n);
NATTraversalInfo *n2 = m->NATTraversals;
// Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
// UPnP gateways will report conflicts if different devices request the same external port, but if two
// clients on the same device request the same external port the second one just stomps over the first.
// One way this can happen is like this:
// 1. Client A binds local port 80
// 2. Client A requests external port 80 -> internal port 80
// 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
// 4. Client A tries again, and successfully gets external port 80 -> internal port 81
// 5. Client B on same machine tries to bind local port 80, and fails
// 6. Client B tries again, and successfully binds local port 81
// 7. Client B now requests external port 81 -> internal port 81
// 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping
while (n2)
{
if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
else
{
if (n->tcpInfo.retries < 100)
{
n->tcpInfo.retries++;
ReqPortNum = RequestedPortNum(n); // Pick a new port number
n2 = m->NATTraversals; // And re-scan the list looking for conflicts
}
else
{
natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
return mStatus_NoError;
}
}
}
// create strings to use in the message
mDNS_snprintf(externalPort, sizeof(externalPort), "%u", ReqPortNum);
mDNS_snprintf(internalPort, sizeof(internalPort), "%u", mDNSVal16(n->IntPort));
mDNS_snprintf(publicPortString, sizeof(publicPortString), "iC%u", ReqPortNum);
mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);
// build the message
mDNSPlatformMemZero(propArgs, sizeof(propArgs));
propArgs[0].name = "NewRemoteHost";
propArgs[0].type = "string";
propArgs[0].value = "";
propArgs[1].name = "NewExternalPort";
propArgs[1].type = "ui2";
propArgs[1].value = externalPort;
propArgs[2].name = "NewProtocol";
propArgs[2].type = "string";
propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
propArgs[3].name = "NewInternalPort";
propArgs[3].type = "ui2";
propArgs[3].value = internalPort;
propArgs[4].name = "NewInternalClient";
propArgs[4].type = "string";
propArgs[4].value = localIPAddrString;
propArgs[5].name = "NewEnabled";
propArgs[5].type = "boolean";
propArgs[5].value = "1";
propArgs[6].name = "NewPortMappingDescription";
propArgs[6].type = "string";
propArgs[6].value = publicPortString;
propArgs[7].name = "NewLeaseDuration";
propArgs[7].type = "ui4";
propArgs[7].value = "0";
LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
}
mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n)
{
LogInfo("LNT_MapPort");
if (n->tcpInfo.sock) return(mStatus_NoError); // If we already have a connection up don't make another request for the same thing
n->tcpInfo.parentNATInfo = n;
n->tcpInfo.retries = 0;
return SendPortMapRequest(m, n);
}
mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n)
{
char externalPort[10];
Property propArgs[3];
tcpLNTInfo *info;
tcpLNTInfo **infoPtr = &m->tcpInfoUnmapList;
mStatus err;
// If no NAT gateway to talk to, no need to do all this work for nothing
if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
mDNSPlatformMemZero(propArgs, sizeof(propArgs));
propArgs[0].name = "NewRemoteHost";
propArgs[0].type = "string";
propArgs[0].value = "";
propArgs[1].name = "NewExternalPort";
propArgs[1].type = "ui2";
propArgs[1].value = externalPort;
propArgs[2].name = "NewProtocol";
propArgs[2].type = "string";
propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
n->tcpInfo.parentNATInfo = n;
// clean up previous port mapping requests and allocations
if (n->tcpInfo.sock) LogInfo("LNT_UnmapPort: closing previous open connection");
if (n->tcpInfo.sock ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request); n->tcpInfo.Request = mDNSNULL; }
if (n->tcpInfo.Reply ) { mDNSPlatformMemFree(n->tcpInfo.Reply); n->tcpInfo.Reply = mDNSNULL; }
// make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns)
if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL)
{ LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
*info = n->tcpInfo;
while (*infoPtr) infoPtr = &(*infoPtr)->next; // find the end of the list
*infoPtr = info; // append
err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp);
if (err) DisposeInfoFromUnmapList(m, info);
return err;
}
mDNSexport mStatus LNT_GetExternalAddress(mDNS *m)
{
return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp);
}
mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
{
// Device description format -
// - device description URL
// - host/port
static const char szSSDPMsgDescribeDeviceFMT[] =
"GET %s HTTP/1.1\r\n"
"Accept: text/xml, application/xml\r\n"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n";
if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need
if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
// build message
if (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
else if ((info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
LogInfo("Describe Device: [%s]", info->Request);
return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
}
// This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
// referencing a service we care about (WANIPConnection or WANPPPConnection), then look for the "Location:" header and copy the addressing and
// URL info we need.
mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len)
{
const mDNSu8 *ptr = data;
const mDNSu8 *end = data + len;
const mDNSu8 *stop = ptr;
if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need
// The formatting of the HTTP header is not always the same when it comes to the placement of
// the service and location strings, so we just look for each of them from the beginning for every response
// figure out if this is a message from a service we care about
while (ptr && ptr != end)
{
if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
ptr++;
}
if (ptr == end)
{
ptr = data;
while (ptr && ptr != end)
{
if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0)) break;
ptr++;
}
}
if (ptr == mDNSNULL || ptr == end) return; // not a message we care about
// find "Location:", starting from the beginning
ptr = data;
while (ptr && ptr != end)
{
if ((*ptr & 0xDF) == 'L' && (strncasecmp((char*)ptr, "Location:", 9) == 0)) break; // find the first 'L'; is this Location? if not, keep looking
ptr++;
}
if (ptr == mDNSNULL || ptr == end)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
return; // not a message we care about
}
ptr += 9; //Skip over 'Location:'
while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces
if (ptr >= end) return;
// find the end of the line
for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } }
// fill in default port
m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);
// free string pointers and set to NULL
if (m->UPnPRouterAddressString != mDNSNULL)
{
mDNSPlatformMemFree(m->UPnPRouterAddressString);
m->UPnPRouterAddressString = mDNSNULL;
}
if (m->UPnPRouterURL != mDNSNULL)
{
mDNSPlatformMemFree(m->UPnPRouterURL);
m->UPnPRouterURL = mDNSNULL;
}
// the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", "");
return;
}
m->UPnPInterfaceID = InterfaceID;
if (m->UPnPRouterAddressString == mDNSNULL)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", "");
LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL");
}
else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString);
if (m->UPnPRouterURL == mDNSNULL)
{
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", "");
LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL");
}
else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL);
LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort));
LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID);
// Don't need the SSDP socket anymore
if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", "");
// now send message to get the device description
GetDeviceDescription(m, &m->tcpDeviceInfo);
}
mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
{
static const char msg[] =
"M-SEARCH * HTTP/1.1\r\n"
"Host:239.255.255.250:1900\r\n"
"ST:urn:schemas-upnp-org:service:WAN%sConnection:1\r\n"
"Man:\"ssdp:discover\"\r\n"
"MX:3\r\n\r\n";
static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
mDNSu8 *buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
unsigned int bufLen;
if (!mDNSIPPortIsZero(m->UPnPRouterPort))
{
if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo);
return;
}
// Always query for WANIPConnection in the first SSDP packet
if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse;
// Create message
bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP");
debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);
if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
{
if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router, SSDPPort);
mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort);
}
m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection;
}
mDNSexport void LNT_ClearState(mDNS *const m)
{
if (m->tcpAddrInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock); m->tcpAddrInfo.sock = mDNSNULL; }
if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort; // Reset UPnP ports
}
#endif /* _LEGACY_NAT_TRAVERSAL_ */

728
src/tools/mdnssd/Poll.c Normal file
View File

@@ -0,0 +1,728 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include "Poll.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <process.h>
#include "GenLinkedList.h"
#include "DebugServices.h"
typedef struct PollSource_struct
{
SOCKET socket;
HANDLE handle;
void *context;
union
{
mDNSPollSocketCallback socket;
mDNSPollEventCallback event;
} callback;
struct Worker_struct *worker;
struct PollSource_struct *next;
} PollSource;
typedef struct Worker_struct
{
HANDLE thread; // NULL for main worker
unsigned id; // 0 for main worker
HANDLE start; // NULL for main worker
HANDLE stop; // NULL for main worker
BOOL done; // Not used for main worker
DWORD numSources;
PollSource *sources[ MAXIMUM_WAIT_OBJECTS ];
HANDLE handles[ MAXIMUM_WAIT_OBJECTS ];
DWORD result;
struct Worker_struct *next;
} Worker;
typedef struct Poll_struct
{
mDNSBool setup;
HANDLE wakeup;
GenLinkedList sources;
DWORD numSources;
Worker main;
GenLinkedList workers;
HANDLE workerHandles[ MAXIMUM_WAIT_OBJECTS ];
DWORD numWorkers;
} Poll;
/*
* Poll Methods
*/
mDNSlocal mStatus PollSetup();
mDNSlocal mStatus PollRegisterSource( PollSource *source );
mDNSlocal void PollUnregisterSource( PollSource *source );
mDNSlocal mStatus PollStartWorkers();
mDNSlocal mStatus PollStopWorkers();
mDNSlocal void PollRemoveWorker( Worker *worker );
/*
* Worker Methods
*/
mDNSlocal mStatus WorkerInit( Worker *worker );
mDNSlocal void WorkerFree( Worker *worker );
mDNSlocal void WorkerRegisterSource( Worker *worker, PollSource *source );
mDNSlocal int WorkerSourceToIndex( Worker *worker, PollSource *source );
mDNSlocal void WorkerUnregisterSource( Worker *worker, PollSource *source );
mDNSlocal void WorkerDispatch( Worker *worker);
mDNSlocal void CALLBACK WorkerWakeupNotification( HANDLE event, void *context );
mDNSlocal unsigned WINAPI WorkerMain( LPVOID inParam );
static void
ShiftDown( void * arr, size_t arraySize, size_t itemSize, int index )
{
memmove( ( ( unsigned char* ) arr ) + ( ( index - 1 ) * itemSize ), ( ( unsigned char* ) arr ) + ( index * itemSize ), ( arraySize - index ) * itemSize );
}
#define DEBUG_NAME "[mDNSWin32] "
#define gMDNSRecord mDNSStorage
mDNSlocal Poll gPoll = { mDNSfalse, NULL };
#define LogErr( err, FUNC ) LogMsg( "%s:%d - %s failed: %d\n", __FUNCTION__, __LINE__, FUNC, err );
mStatus
mDNSPollRegisterSocket( SOCKET socket, int networkEvents, mDNSPollSocketCallback callback, void *context )
{
PollSource *source = NULL;
HANDLE event = INVALID_HANDLE_VALUE;
mStatus err = mStatus_NoError;
if ( !gPoll.setup )
{
err = PollSetup();
require_noerr( err, exit );
}
source = malloc( sizeof( PollSource ) );
require_action( source, exit, err = mStatus_NoMemoryErr );
event = WSACreateEvent();
require_action( event, exit, err = mStatus_NoMemoryErr );
err = WSAEventSelect( socket, event, networkEvents );
require_noerr( err, exit );
source->socket = socket;
source->handle = event;
source->callback.socket = callback;
source->context = context;
err = PollRegisterSource( source );
require_noerr( err, exit );
exit:
if ( err != mStatus_NoError )
{
if ( event != INVALID_HANDLE_VALUE )
{
WSACloseEvent( event );
}
if ( source != NULL )
{
free( source );
}
}
return err;
}
void
mDNSPollUnregisterSocket( SOCKET socket )
{
PollSource *source;
for ( source = gPoll.sources.Head; source; source = source->next )
{
if ( source->socket == socket )
{
break;
}
}
if ( source )
{
WSACloseEvent( source->handle );
PollUnregisterSource( source );
free( source );
}
}
mStatus
mDNSPollRegisterEvent( HANDLE event, mDNSPollEventCallback callback, void *context )
{
PollSource *source = NULL;
mStatus err = mStatus_NoError;
if ( !gPoll.setup )
{
err = PollSetup();
require_noerr( err, exit );
}
source = malloc( sizeof( PollSource ) );
require_action( source, exit, err = mStatus_NoMemoryErr );
source->socket = INVALID_SOCKET;
source->handle = event;
source->callback.event = callback;
source->context = context;
err = PollRegisterSource( source );
require_noerr( err, exit );
exit:
if ( err != mStatus_NoError )
{
if ( source != NULL )
{
free( source );
}
}
return err;
}
void
mDNSPollUnregisterEvent( HANDLE event )
{
PollSource *source;
for ( source = gPoll.sources.Head; source; source = source->next )
{
if ( source->handle == event )
{
break;
}
}
if ( source )
{
PollUnregisterSource( source );
free( source );
}
}
mStatus
mDNSPoll( DWORD msec )
{
mStatus err = mStatus_NoError;
if ( gPoll.numWorkers > 0 )
{
err = PollStartWorkers();
require_noerr( err, exit );
}
gPoll.main.result = WaitForMultipleObjects( gPoll.main.numSources, gPoll.main.handles, FALSE, msec );
err = translate_errno( ( gPoll.main.result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "WaitForMultipleObjects()" );
require_action( gPoll.main.result != WAIT_FAILED, exit, err = ( mStatus ) GetLastError() );
if ( gPoll.numWorkers > 0 )
{
err = PollStopWorkers();
require_noerr( err, exit );
}
WorkerDispatch( &gPoll.main );
exit:
return ( err );
}
mDNSlocal mStatus
PollSetup()
{
mStatus err = mStatus_NoError;
if ( !gPoll.setup )
{
memset( &gPoll, 0, sizeof( gPoll ) );
InitLinkedList( &gPoll.sources, offsetof( PollSource, next ) );
InitLinkedList( &gPoll.workers, offsetof( Worker, next ) );
gPoll.wakeup = CreateEvent( NULL, TRUE, FALSE, NULL );
require_action( gPoll.wakeup, exit, err = mStatus_NoMemoryErr );
err = WorkerInit( &gPoll.main );
require_noerr( err, exit );
gPoll.setup = mDNStrue;
}
exit:
return err;
}
mDNSlocal mStatus
PollRegisterSource( PollSource *source )
{
Worker *worker = NULL;
mStatus err = mStatus_NoError;
AddToTail( &gPoll.sources, source );
gPoll.numSources++;
// First check our main worker. In most cases, we won't have to worry about threads
if ( gPoll.main.numSources < MAXIMUM_WAIT_OBJECTS )
{
WorkerRegisterSource( &gPoll.main, source );
}
else
{
// Try to find a thread to use that we've already created
for ( worker = gPoll.workers.Head; worker; worker = worker->next )
{
if ( worker->numSources < MAXIMUM_WAIT_OBJECTS )
{
WorkerRegisterSource( worker, source );
break;
}
}
// If not, then create a worker and make a thread to run it in
if ( !worker )
{
worker = ( Worker* ) malloc( sizeof( Worker ) );
require_action( worker, exit, err = mStatus_NoMemoryErr );
memset( worker, 0, sizeof( Worker ) );
worker->start = CreateEvent( NULL, FALSE, FALSE, NULL );
require_action( worker->start, exit, err = mStatus_NoMemoryErr );
worker->stop = CreateEvent( NULL, FALSE, FALSE, NULL );
require_action( worker->stop, exit, err = mStatus_NoMemoryErr );
err = WorkerInit( worker );
require_noerr( err, exit );
// Create thread with _beginthreadex() instead of CreateThread() to avoid
// memory leaks when using static run-time libraries.
// See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
worker->thread = ( HANDLE ) _beginthreadex_compat( NULL, 0, WorkerMain, worker, 0, &worker->id );
err = translate_errno( worker->thread, ( mStatus ) GetLastError(), kUnknownErr );
require_noerr( err, exit );
AddToTail( &gPoll.workers, worker );
gPoll.workerHandles[ gPoll.numWorkers++ ] = worker->stop;
WorkerRegisterSource( worker, source );
}
}
exit:
if ( err && worker )
{
WorkerFree( worker );
}
return err;
}
mDNSlocal void
PollUnregisterSource( PollSource *source )
{
RemoveFromList( &gPoll.sources, source );
gPoll.numSources--;
WorkerUnregisterSource( source->worker, source );
}
mDNSlocal mStatus
PollStartWorkers()
{
Worker *worker;
mStatus err = mStatus_NoError;
BOOL ok;
dlog( kDebugLevelChatty, DEBUG_NAME "starting workers\n" );
worker = gPoll.workers.Head;
while ( worker )
{
Worker *next = worker->next;
if ( worker->numSources == 1 )
{
PollRemoveWorker( worker );
}
else
{
dlog( kDebugLevelChatty, DEBUG_NAME "waking up worker\n" );
ok = SetEvent( worker->start );
err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "SetEvent()" );
if ( err )
{
PollRemoveWorker( worker );
}
}
worker = next;
}
err = mStatus_NoError;
return err;
}
mDNSlocal mStatus
PollStopWorkers()
{
DWORD result;
Worker *worker;
BOOL ok;
mStatus err = mStatus_NoError;
dlog( kDebugLevelChatty, DEBUG_NAME "stopping workers\n" );
ok = SetEvent( gPoll.wakeup );
err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "SetEvent()" );
// Wait For 5 seconds for all the workers to wake up
result = WaitForMultipleObjects( gPoll.numWorkers, gPoll.workerHandles, TRUE, 5000 );
err = translate_errno( ( result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "WaitForMultipleObjects()" );
ok = ResetEvent( gPoll.wakeup );
err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "ResetEvent()" );
for ( worker = gPoll.workers.Head; worker; worker = worker->next )
{
WorkerDispatch( worker );
}
err = mStatus_NoError;
return err;
}
mDNSlocal void
PollRemoveWorker( Worker *worker )
{
DWORD result;
mStatus err;
BOOL ok;
DWORD i;
dlog( kDebugLevelChatty, DEBUG_NAME "removing worker %d\n", worker->id );
RemoveFromList( &gPoll.workers, worker );
// Remove handle from gPoll.workerHandles
for ( i = 0; i < gPoll.numWorkers; i++ )
{
if ( gPoll.workerHandles[ i ] == worker->stop )
{
ShiftDown( gPoll.workerHandles, gPoll.numWorkers, sizeof( gPoll.workerHandles[ 0 ] ), i + 1 );
break;
}
}
worker->done = TRUE;
gPoll.numWorkers--;
// Cause the thread to exit.
ok = SetEvent( worker->start );
err = translate_errno( ok, ( OSStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "SetEvent()" );
result = WaitForSingleObject( worker->thread, 5000 );
err = translate_errno( result != WAIT_FAILED, ( OSStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "WaitForSingleObject()" );
if ( ( result == WAIT_FAILED ) || ( result == WAIT_TIMEOUT ) )
{
ok = TerminateThread( worker->thread, 0 );
err = translate_errno( ok, ( OSStatus ) GetLastError(), kUnknownErr );
if ( err ) LogErr( err, "TerminateThread()" );
}
CloseHandle( worker->thread );
worker->thread = NULL;
WorkerFree( worker );
}
mDNSlocal void
WorkerRegisterSource( Worker *worker, PollSource *source )
{
source->worker = worker;
worker->sources[ worker->numSources ] = source;
worker->handles[ worker->numSources ] = source->handle;
worker->numSources++;
}
mDNSlocal int
WorkerSourceToIndex( Worker *worker, PollSource *source )
{
int index;
for ( index = 0; index < ( int ) worker->numSources; index++ )
{
if ( worker->sources[ index ] == source )
{
break;
}
}
if ( index == ( int ) worker->numSources )
{
index = -1;
}
return index;
}
mDNSlocal void
WorkerUnregisterSource( Worker *worker, PollSource *source )
{
int sourceIndex = WorkerSourceToIndex( worker, source );
DWORD delta;
if ( sourceIndex == -1 )
{
LogMsg( "WorkerUnregisterSource: source not found in list" );
goto exit;
}
delta = ( worker->numSources - sourceIndex - 1 );
// If this source is not at the end of the list, then move memory
if ( delta > 0 )
{
ShiftDown( worker->sources, worker->numSources, sizeof( worker->sources[ 0 ] ), sourceIndex + 1 );
ShiftDown( worker->handles, worker->numSources, sizeof( worker->handles[ 0 ] ), sourceIndex + 1 );
}
worker->numSources--;
exit:
return;
}
mDNSlocal void CALLBACK
WorkerWakeupNotification( HANDLE event, void *context )
{
DEBUG_UNUSED( event );
DEBUG_UNUSED( context );
dlog( kDebugLevelChatty, DEBUG_NAME "Worker thread wakeup\n" );
}
mDNSlocal void
WorkerDispatch( Worker *worker )
{
if ( worker->result == WAIT_FAILED )
{
/* What should we do here? */
}
else if ( worker->result == WAIT_TIMEOUT )
{
dlog( kDebugLevelChatty, DEBUG_NAME "timeout\n" );
}
else
{
DWORD waitItemIndex = ( DWORD )( ( ( int ) worker->result ) - WAIT_OBJECT_0 );
PollSource *source = NULL;
// Sanity check
if ( waitItemIndex >= worker->numSources )
{
LogMsg( "WorkerDispatch: waitItemIndex (%d) is >= numSources (%d)", waitItemIndex, worker->numSources );
goto exit;
}
source = worker->sources[ waitItemIndex ];
if ( source->socket != INVALID_SOCKET )
{
WSANETWORKEVENTS event;
if ( WSAEnumNetworkEvents( source->socket, source->handle, &event ) == 0 )
{
source->callback.socket( source->socket, &event, source->context );
}
else
{
source->callback.socket( source->socket, NULL, source->context );
}
}
else
{
source->callback.event( source->handle, source->context );
}
}
exit:
return;
}
mDNSlocal mStatus
WorkerInit( Worker *worker )
{
PollSource *source = NULL;
mStatus err = mStatus_NoError;
require_action( worker, exit, err = mStatus_BadParamErr );
source = malloc( sizeof( PollSource ) );
require_action( source, exit, err = mStatus_NoMemoryErr );
source->socket = INVALID_SOCKET;
source->handle = gPoll.wakeup;
source->callback.event = WorkerWakeupNotification;
source->context = NULL;
WorkerRegisterSource( worker, source );
exit:
return err;
}
mDNSlocal void
WorkerFree( Worker *worker )
{
if ( worker->start )
{
CloseHandle( worker->start );
worker->start = NULL;
}
if ( worker->stop )
{
CloseHandle( worker->stop );
worker->stop = NULL;
}
free( worker );
}
mDNSlocal unsigned WINAPI
WorkerMain( LPVOID inParam )
{
Worker *worker = ( Worker* ) inParam;
mStatus err = mStatus_NoError;
require_action( worker, exit, err = mStatus_BadParamErr );
dlog( kDebugLevelVerbose, DEBUG_NAME, "entering WorkerMain()\n" );
while ( TRUE )
{
DWORD result;
BOOL ok;
dlog( kDebugLevelChatty, DEBUG_NAME, "worker thread %d will wait on main loop\n", worker->id );
result = WaitForSingleObject( worker->start, INFINITE );
err = translate_errno( ( result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) { LogErr( err, "WaitForSingleObject()" ); break; }
if ( worker->done ) break;
dlog( kDebugLevelChatty, DEBUG_NAME "worker thread %d will wait on sockets\n", worker->id );
worker->result = WaitForMultipleObjects( worker->numSources, worker->handles, FALSE, INFINITE );
err = translate_errno( ( worker->result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) { LogErr( err, "WaitForMultipleObjects()" ); break; }
dlog( kDebugLevelChatty, DEBUG_NAME "worker thread %d did wait on sockets: %d\n", worker->id, worker->result );
ok = SetEvent( gPoll.wakeup );
err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) { LogErr( err, "SetEvent()" ); break; }
dlog( kDebugLevelChatty, DEBUG_NAME, "worker thread %d preparing to sleep\n", worker->id );
ok = SetEvent( worker->stop );
err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
if ( err ) { LogErr( err, "SetEvent()" ); break; }
}
dlog( kDebugLevelVerbose, DEBUG_NAME "exiting WorkerMain()\n" );
exit:
return 0;
}

61
src/tools/mdnssd/Poll.h Normal file
View File

@@ -0,0 +1,61 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifndef _Poll_h
#define _Poll_h
#include "CommonServices.h"
#include <mswsock.h>
#include "mDNSEmbeddedAPI.h"
#include "uDNS.h"
#if defined(__cplusplus )
extern "C" {
#endif
typedef void ( CALLBACK *mDNSPollSocketCallback )( SOCKET socket, LPWSANETWORKEVENTS event, void *context );
typedef void ( CALLBACK *mDNSPollEventCallback )( HANDLE event, void *context );
extern mStatus
mDNSPollRegisterSocket( SOCKET socket, int networkEvents, mDNSPollSocketCallback callback, void *context );
extern void
mDNSPollUnregisterSocket( SOCKET socket );
extern mStatus
mDNSPollRegisterEvent( HANDLE event, mDNSPollEventCallback callback, void *context );
extern void
mDNSPollUnregisterEvent( HANDLE event );
extern mStatus
mDNSPoll( DWORD msec );
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,57 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
//----------------------------------------------------------------------------------------
// Registry Constants
//----------------------------------------------------------------------------------------
#if defined(UNICODE)
# define kServiceParametersSoftware L"SOFTWARE"
# define kServiceParametersAppleComputer L"Apple Computer, Inc."
# define kServiceParametersBonjour L"Bonjour"
# define kServiceParametersNode L"SOFTWARE\\Apple Inc.\\Bonjour"
# define kServiceName L"Bonjour Service"
# define kServiceDynDNSBrowseDomains L"BrowseDomains"
# define kServiceDynDNSHostNames L"HostNames"
# define kServiceDynDNSRegistrationDomains L"RegistrationDomains"
# define kServiceDynDNSDomains L"Domains" // value is comma separated list of domains
# define kServiceDynDNSEnabled L"Enabled"
# define kServiceDynDNSStatus L"Status"
# define kServiceManageLLRouting L"ManageLLRouting"
# define kServiceCacheEntryCount L"CacheEntryCount"
# define kServiceManageFirewall L"ManageFirewall"
# define kServiceAdvertisedServices L"Services"
# else
# define kServiceParametersSoftware "SOFTWARE"
# define kServiceParametersAppleComputer "Apple Computer, Inc."
# define kServiceParametersBonjour "Bonjour"
# define kServiceParametersNode "SOFTWARE\\Apple Inc.\\Bonjour"
# define kServiceName "Bonjour Service"
# define kServiceDynDNSBrowseDomains "BrowseDomains"
# define kServiceDynDNSHostNames "HostNames"
# define kServiceDynDNSRegistrationDomains "RegistrationDomains"
# define kServiceDynDNSDomains "Domains" // value is comma separated list of domains
# define kServiceDynDNSEnabled "Enabled"
# define kServiceDynDNSStatus "Status"
# define kServiceManageLLRouting "ManageLLRouting"
# define kServiceCacheEntryCount "CacheEntryCount"
# define kServiceManageFirewall "ManageFirewall"
#endif

338
src/tools/mdnssd/Secret.c Normal file
View File

@@ -0,0 +1,338 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include "Secret.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <process.h>
#include <ntsecapi.h>
#include <lm.h>
#include "DebugServices.h"
mDNSlocal OSStatus MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input );
mDNSlocal OSStatus MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input );
BOOL
LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainSize, char * outKey, unsigned outKeySize, char * outSecret, unsigned outSecretSize )
{
PLSA_UNICODE_STRING domainLSA;
PLSA_UNICODE_STRING keyLSA;
PLSA_UNICODE_STRING secretLSA;
size_t i;
size_t dlen;
LSA_OBJECT_ATTRIBUTES attrs;
LSA_HANDLE handle = NULL;
NTSTATUS res;
OSStatus err;
check( inDomain );
check( outDomain );
check( outKey );
check( outSecret );
// Initialize
domainLSA = NULL;
keyLSA = NULL;
secretLSA = NULL;
// Make sure we have enough space to add trailing dot
dlen = strlen( inDomain );
err = strcpy_s( outDomain, outDomainSize - 2, inDomain );
require_noerr( err, exit );
// If there isn't a trailing dot, add one because the mDNSResponder
// presents names with the trailing dot.
if ( outDomain[ dlen - 1 ] != '.' )
{
outDomain[ dlen++ ] = '.';
outDomain[ dlen ] = '\0';
}
// Canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
for ( i = 0; i < dlen; i++ )
{
outDomain[i] = (char) tolower( outDomain[i] ); // canonicalize -> lower case
}
// attrs are reserved, so initialize to zeroes.
ZeroMemory( &attrs, sizeof( attrs ) );
// Get a handle to the Policy object on the local system
res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle );
err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
require_noerr( err, exit );
// Get the encrypted data
domainLSA = ( PLSA_UNICODE_STRING ) malloc( sizeof( LSA_UNICODE_STRING ) );
require_action( domainLSA != NULL, exit, err = mStatus_NoMemoryErr );
err = MakeLsaStringFromUTF8String( domainLSA, outDomain );
require_noerr( err, exit );
// Retrieve the key
res = LsaRetrievePrivateData( handle, domainLSA, &keyLSA );
err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
require_noerr_quiet( err, exit );
// <rdar://problem/4192119> Lsa secrets use a flat naming space. Therefore, we will prepend "$" to the keyname to
// make sure it doesn't conflict with a zone name.
// Strip off the "$" prefix.
err = MakeUTF8StringFromLsaString( outKey, outKeySize, keyLSA );
require_noerr( err, exit );
require_action( outKey[0] == '$', exit, err = kUnknownErr );
memcpy( outKey, outKey + 1, strlen( outKey ) );
// Retrieve the secret
res = LsaRetrievePrivateData( handle, keyLSA, &secretLSA );
err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
require_noerr_quiet( err, exit );
// Convert the secret to UTF8 string
err = MakeUTF8StringFromLsaString( outSecret, outSecretSize, secretLSA );
require_noerr( err, exit );
exit:
if ( domainLSA != NULL )
{
if ( domainLSA->Buffer != NULL )
{
free( domainLSA->Buffer );
}
free( domainLSA );
}
if ( keyLSA != NULL )
{
LsaFreeMemory( keyLSA );
}
if ( secretLSA != NULL )
{
LsaFreeMemory( secretLSA );
}
if ( handle )
{
LsaClose( handle );
handle = NULL;
}
return ( !err ) ? TRUE : FALSE;
}
mDNSBool
LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret )
{
size_t inDomainLength;
size_t inKeyLength;
char domain[ 1024 ];
char key[ 1024 ];
LSA_OBJECT_ATTRIBUTES attrs;
LSA_HANDLE handle = NULL;
NTSTATUS res;
LSA_UNICODE_STRING lucZoneName;
LSA_UNICODE_STRING lucKeyName;
LSA_UNICODE_STRING lucSecretName;
BOOL ok = TRUE;
OSStatus err;
require_action( inDomain != NULL, exit, ok = FALSE );
require_action( inKey != NULL, exit, ok = FALSE );
require_action( inSecret != NULL, exit, ok = FALSE );
// If there isn't a trailing dot, add one because the mDNSResponder
// presents names with the trailing dot.
ZeroMemory( domain, sizeof( domain ) );
inDomainLength = strlen( inDomain );
require_action( inDomainLength > 0, exit, ok = FALSE );
err = strcpy_s( domain, sizeof( domain ) - 2, inDomain );
require_action( !err, exit, ok = FALSE );
if ( domain[ inDomainLength - 1 ] != '.' )
{
domain[ inDomainLength++ ] = '.';
domain[ inDomainLength ] = '\0';
}
// <rdar://problem/4192119>
//
// Prepend "$" to the key name, so that there will
// be no conflict between the zone name and the key
// name
ZeroMemory( key, sizeof( key ) );
inKeyLength = strlen( inKey );
require_action( inKeyLength > 0 , exit, ok = FALSE );
key[ 0 ] = '$';
err = strcpy_s( key + 1, sizeof( key ) - 3, inKey );
require_action( !err, exit, ok = FALSE );
inKeyLength++;
if ( key[ inKeyLength - 1 ] != '.' )
{
key[ inKeyLength++ ] = '.';
key[ inKeyLength ] = '\0';
}
// attrs are reserved, so initialize to zeroes.
ZeroMemory( &attrs, sizeof( attrs ) );
// Get a handle to the Policy object on the local system
res = LsaOpenPolicy( NULL, &attrs, POLICY_ALL_ACCESS, &handle );
err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
require_noerr( err, exit );
// Intializing PLSA_UNICODE_STRING structures
err = MakeLsaStringFromUTF8String( &lucZoneName, domain );
require_noerr( err, exit );
err = MakeLsaStringFromUTF8String( &lucKeyName, key );
require_noerr( err, exit );
err = MakeLsaStringFromUTF8String( &lucSecretName, inSecret );
require_noerr( err, exit );
// Store the private data.
res = LsaStorePrivateData( handle, &lucZoneName, &lucKeyName );
err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
require_noerr( err, exit );
res = LsaStorePrivateData( handle, &lucKeyName, &lucSecretName );
err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
require_noerr( err, exit );
exit:
if ( handle )
{
LsaClose( handle );
handle = NULL;
}
return ok;
}
//===========================================================================================================================
// MakeLsaStringFromUTF8String
//===========================================================================================================================
mDNSlocal OSStatus
MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input )
{
int size;
OSStatus err;
check( input );
check( output );
output->Buffer = NULL;
size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 );
err = translate_errno( size > 0, GetLastError(), kUnknownErr );
require_noerr( err, exit );
output->Length = (USHORT)( size * sizeof( wchar_t ) );
output->Buffer = (PWCHAR) malloc( output->Length );
require_action( output->Buffer, exit, err = mStatus_NoMemoryErr );
size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size );
err = translate_errno( size > 0, GetLastError(), kUnknownErr );
require_noerr( err, exit );
// We're going to subtrace one wchar_t from the size, because we didn't
// include it when we encoded the string
output->MaximumLength = output->Length;
output->Length -= sizeof( wchar_t );
exit:
if ( err && output->Buffer )
{
free( output->Buffer );
output->Buffer = NULL;
}
return( err );
}
//===========================================================================================================================
// MakeUTF8StringFromLsaString
//===========================================================================================================================
mDNSlocal OSStatus
MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input )
{
size_t size;
OSStatus err = kNoErr;
// The Length field of this structure holds the number of bytes,
// but WideCharToMultiByte expects the number of wchar_t's. So
// we divide by sizeof(wchar_t) to get the correct number.
size = (size_t) WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL);
err = translate_errno( size != 0, GetLastError(), kUnknownErr );
require_noerr( err, exit );
// Ensure that we have enough space (Add one for trailing '\0')
require_action( ( size + 1 ) <= len, exit, err = mStatus_NoMemoryErr );
// Convert the string
size = (size_t) WideCharToMultiByte( CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), output, (int) size, NULL, NULL);
err = translate_errno( size != 0, GetLastError(), kUnknownErr );
require_noerr( err, exit );
// have to add the trailing 0 because WideCharToMultiByte doesn't do it,
// although it does return the correct size
output[size] = '\0';
exit:
return err;
}

42
src/tools/mdnssd/Secret.h Normal file
View File

@@ -0,0 +1,42 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifndef _Secret_h
#define _Secret_h
#include "mDNSEmbeddedAPI.h"
#if defined(__cplusplus )
extern "C" {
#endif
extern mDNSBool
LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainLength, char * outKey, unsigned outKeyLength, char * outSecret, unsigned outSecretLength );
extern mDNSBool
LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret );
#if defined(__cplusplus)
}
#endif
#endif

2597
src/tools/mdnssd/Service.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifndef __MDNS_SERVICE_H__
#define __MDNS_SERVICE_H__
#include <windows.h>
extern int RunDirect( int argc, LPTSTR argv[] );
extern int Main( int argc, LPTSTR argv[] );
#endif

115
src/tools/mdnssd/Service.rc Normal file
View File

@@ -0,0 +1,115 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
//#include "winres.h"
//#include "WinVersRes.h"
#include "windows.h"
#include "EventLog.rc"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)\0"
VALUE "FileDescription", "Bonjour Service Fallback\0"
VALUE "FileVersion", 1,0,0,0
VALUE "InternalName", "mdnssd.exe\0"
VALUE "LegalCopyright", "Copyright(c)2003-2012, Apple Computer, 2012 Nokia Corporation and/or its subsidiary(-ies).\0"
VALUE "OriginalFilename", "mdnssd.exe\0"
VALUE "ProductName", "Bonjour Fallback\0"
VALUE "ProductVersion", "1.0\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"#include ""WinVersRes.h""\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_SERVICE_DESCRIPTION "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence, so that users can discover and use those services without any unnecessary manual setup or administration."
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -1884,7 +1884,7 @@ mDNSlocal mDNSu16 CheckSum(const void *const data, mDNSs32 length, mDNSu32 sum)
while (length > 0) { length -= 2; sum += *ptr++; } while (length > 0) { length -= 2; sum += *ptr++; }
sum = (sum & 0xFFFF) + (sum >> 16); sum = (sum & 0xFFFF) + (sum >> 16);
sum = (sum & 0xFFFF) + (sum >> 16); sum = (sum & 0xFFFF) + (sum >> 16);
return(sum != 0xFFFF ? sum : 0); return (mDNSu16)(sum != 0xFFFF ? sum : 0);
} }
mDNSlocal mDNSu16 IPv6CheckSum(const mDNSv6Addr *const src, const mDNSv6Addr *const dst, const mDNSu8 protocol, const void *const data, const mDNSu32 length) mDNSlocal mDNSu16 IPv6CheckSum(const mDNSv6Addr *const src, const mDNSv6Addr *const dst, const mDNSu8 protocol, const void *const data, const mDNSu32 length)
@@ -1892,10 +1892,10 @@ mDNSlocal mDNSu16 IPv6CheckSum(const mDNSv6Addr *const src, const mDNSv6Addr *co
IPv6PseudoHeader ph; IPv6PseudoHeader ph;
ph.src = *src; ph.src = *src;
ph.dst = *dst; ph.dst = *dst;
ph.len.b[0] = length >> 24; ph.len.b[0] = (0xFF & (length >> 24));
ph.len.b[1] = length >> 16; ph.len.b[1] = (0xFF & (length >> 16));
ph.len.b[2] = length >> 8; ph.len.b[2] = (0xFF & (length >> 8));
ph.len.b[3] = length; ph.len.b[3] = (0xFF & length);
ph.pro.b[0] = 0; ph.pro.b[0] = 0;
ph.pro.b[1] = 0; ph.pro.b[1] = 0;
ph.pro.b[2] = 0; ph.pro.b[2] = 0;
@@ -7706,23 +7706,23 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
} }
} }
mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout) mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface1, mDNSu32 timeout)
{ {
McastResolver **p = &m->McastResolvers; McastResolver **p = &m->McastResolvers;
McastResolver *tmp = mDNSNULL; McastResolver *tmp = mDNSNULL;
if (!d) d = (const domainname *)""; if (!d) d = (const domainname *)"";
LogInfo("mDNS_AddMcastResolver: Adding %##s, InterfaceID %p, timeout %u", d->c, interface, timeout); LogInfo("mDNS_AddMcastResolver: Adding %##s, InterfaceID %p, timeout %u", d->c, interface1, timeout);
if (m->mDNS_busy != m->mDNS_reentrancy+1) if (m->mDNS_busy != m->mDNS_reentrancy+1)
LogMsg("mDNS_AddMcastResolver: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); LogMsg("mDNS_AddMcastResolver: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
while (*p) // Check if we already have this {interface, domain} tuple registered while (*p) // Check if we already have this {interface, domain} tuple registered
{ {
if ((*p)->interface == interface && SameDomainName(&(*p)->domain, d)) if ((*p)->interface1 == interface1 && SameDomainName(&(*p)->domain, d))
{ {
if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: Mcast Resolver domain %##s (%p) registered more than once", d->c, interface); if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: Mcast Resolver domain %##s (%p) registered more than once", d->c, interface1);
(*p)->flags &= ~DNSServer_FlagDelete; (*p)->flags &= ~DNSServer_FlagDelete;
tmp = *p; tmp = *p;
*p = tmp->next; *p = tmp->next;
@@ -7740,7 +7740,7 @@ mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname
if (!*p) LogMsg("mDNS_AddMcastResolver: ERROR!! - malloc"); if (!*p) LogMsg("mDNS_AddMcastResolver: ERROR!! - malloc");
else else
{ {
(*p)->interface = interface; (*p)->interface1 = interface1;
(*p)->flags = DNSServer_FlagNew; (*p)->flags = DNSServer_FlagNew;
(*p)->timeout = timeout; (*p)->timeout = timeout;
AssignDomainName(&(*p)->domain, d); AssignDomainName(&(*p)->domain, d);
@@ -7905,13 +7905,13 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
// //
// Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout // Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout
if (curr->scoped && curr->interface == mDNSInterface_Any) if (curr->scoped && curr->interface1 == mDNSInterface_Any)
{ debugf("SetValidDNSServers: Scoped DNS server %#a (Domain %##s) with Interface Any", &curr->addr, curr->domain.c); continue; } { debugf("SetValidDNSServers: Scoped DNS server %#a (Domain %##s) with Interface Any", &curr->addr, curr->domain.c); continue; }
currcount = CountLabels(&curr->domain); currcount = CountLabels(&curr->domain);
if ((!DEQuery || !curr->cellIntf) && if ((!DEQuery || !curr->cellIntf) &&
((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) ||
(curr->interface == question->InterfaceID))) (curr->interface1 == question->InterfaceID)))
{ {
bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen); bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
@@ -7926,7 +7926,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
if (bettermatch) { debugf("SetValidDNSServers: Resetting all the bits"); question->validDNSServers = zeroOpaque64; timeout = 0; } if (bettermatch) { debugf("SetValidDNSServers: Resetting all the bits"); question->validDNSServers = zeroOpaque64; timeout = 0; }
debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d," debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d,"
" Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout, " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout,
curr->interface); curr->interface1);
timeout += curr->timeout; timeout += curr->timeout;
if (DEQuery) debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf); if (DEQuery) debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf);
bit_set_opaque64(question->validDNSServers, index); bit_set_opaque64(question->validDNSServers, index);
@@ -7993,7 +7993,7 @@ mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfac
// is the new way of specifying an InterfaceID option for DNSServer. These will be considered // is the new way of specifying an InterfaceID option for DNSServer. These will be considered
// only when the question has non-zero interfaceID. // only when the question has non-zero interfaceID.
if ((!curr->scoped && !InterfaceID) || (curr->interface == InterfaceID)) if ((!curr->scoped && !InterfaceID) || (curr->interface1 == InterfaceID))
{ {
// If we know that all the names are already equally good matches, then skip calling BetterMatchForName. // If we know that all the names are already equally good matches, then skip calling BetterMatchForName.
@@ -9065,7 +9065,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
query->ServiceInfoQueryContext = Context; query->ServiceInfoQueryContext = Context;
// info->name = Must already be set up by client // info->name = Must already be set up by client
// info->interface = Must already be set up by client // info->interface1 = Must already be set up by client
info->ip = zeroAddr; info->ip = zeroAddr;
info->port = zeroIPPort; info->port = zeroIPPort;
info->TXTlen = 0; info->TXTlen = 0;
@@ -9713,9 +9713,9 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
// 3. Any DNS servers specific to this interface are now unusable // 3. Any DNS servers specific to this interface are now unusable
for (s = m->DNSServers; s; s = s->next) for (s = m->DNSServers; s; s = s->next)
if (s->interface == set->InterfaceID) if (s->interface1 == set->InterfaceID)
{ {
s->interface = mDNSInterface_Any; s->interface1 = mDNSInterface_Any;
s->teststate = DNSServer_Disabled; s->teststate = DNSServer_Disabled;
} }
} }

View File

@@ -1054,7 +1054,7 @@ enum
typedef struct McastResolver typedef struct McastResolver
{ {
struct McastResolver *next; struct McastResolver *next;
mDNSInterfaceID interface; mDNSInterfaceID interface1;
mDNSu32 flags; // Set when we're planning to delete this from the list mDNSu32 flags; // Set when we're planning to delete this from the list
domainname domain; domainname domain;
mDNSu32 timeout; // timeout value for questions mDNSu32 timeout; // timeout value for questions
@@ -1063,7 +1063,7 @@ typedef struct McastResolver
typedef struct DNSServer typedef struct DNSServer
{ {
struct DNSServer *next; struct DNSServer *next;
mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces mDNSInterfaceID interface1; // For specialized uses; we can have DNS servers reachable over specific interfaces
mDNSAddr addr; mDNSAddr addr;
mDNSIPPort port; mDNSIPPort port;
mDNSOpaque16 testid; mDNSOpaque16 testid;
@@ -2469,11 +2469,11 @@ extern void RecreateNATMappings(mDNS *const m);
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext); extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn); extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router); extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf); extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface1, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q); extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q);
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID); extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
extern McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout); extern McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface1, mDNSu32 timeout);
// We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2 // We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2
#define mDNS_AddSearchDomain_CString(X, I) \ #define mDNS_AddSearchDomain_CString(X, I) \

5018
src/tools/mdnssd/mDNSWin32.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#ifndef __MDNS_WIN32__
#define __MDNS_WIN32__
#include "CommonServices.h"
#if( !defined( _WIN32_WCE ) )
#include <mswsock.h>
#endif
#include "mDNSEmbeddedAPI.h"
#include "uDNS.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void ( *TCPUserCallback )();
struct TCPSocket_struct
{
TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
SOCKET fd;
BOOL connected;
TCPUserCallback userCallback;
void * userContext;
BOOL closed;
mDNS * m;
};
struct UDPSocket_struct
{
mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
mDNSAddr addr; // This is initialized by our code. If we don't get the
// dstAddr from WSARecvMsg we use this value instead.
SOCKET fd;
LPFN_WSARECVMSG recvMsgPtr;
DNSMessage packet;
struct mDNSInterfaceData *ifd;
UDPSocket *next;
mDNS *m;
};
//---------------------------------------------------------------------------------------------------------------------------
/*! @struct mDNSInterfaceData
@abstract Structure containing interface-specific data.
*/
typedef struct mDNSInterfaceData mDNSInterfaceData;
struct mDNSInterfaceData
{
char name[ 128 ];
uint32_t index;
uint32_t scopeID;
struct UDPSocket_struct sock;
NetworkInterfaceInfo interfaceInfo;
mDNSBool hostRegistered;
mDNSInterfaceData * next;
};
//---------------------------------------------------------------------------------------------------------------------------
/*! @typedef ReportStatusFunc
*/
typedef void (*ReportStatusFunc)(int inType, const char *inFormat, ...);
//---------------------------------------------------------------------------------------------------------------------------
/*! @struct mDNS_PlatformSupport_struct
@abstract Structure containing platform-specific data.
*/
struct mDNS_PlatformSupport_struct
{
HANDLE mainThread;
HANDLE checkFileSharesTimer;
mDNSs32 checkFileSharesTimeout;
ReportStatusFunc reportStatusFunc;
time_t nextDHCPLeaseExpires;
char nbname[ 32 ];
char nbdomain[ 32 ];
mDNSBool smbFileSharing;
mDNSBool smbPrintSharing;
ServiceRecordSet smbSRS;
AuthRecord smbSubTypes[ 2 ];
mDNSBool registeredLoopback4;
int interfaceCount;
mDNSInterfaceData * interfaceList;
mDNSInterfaceData * inactiveInterfaceList;
struct UDPSocket_struct unicastSock4;
struct UDPSocket_struct unicastSock6;
DWORD osMajorVersion;
DWORD osMinorVersion;
};
//---------------------------------------------------------------------------------------------------------------------------
/*! @struct ifaddrs
@abstract Interface information
*/
struct ifaddrs
{
struct ifaddrs * ifa_next;
char * ifa_name;
u_int ifa_flags;
struct sockaddr * ifa_addr;
struct sockaddr * ifa_netmask;
struct sockaddr * ifa_broadaddr;
struct sockaddr * ifa_dstaddr;
BYTE ifa_physaddr[6];
BOOL ifa_dhcpEnabled;
time_t ifa_dhcpLeaseExpires;
mDNSu8 ifa_womp;
void * ifa_data;
struct
{
uint32_t index;
} ifa_extra;
};
extern void InterfaceListDidChange( mDNS * const inMDNS );
extern void ComputerDescriptionDidChange( mDNS * const inMDNS );
extern void TCPIPConfigDidChange( mDNS * const inMDNS );
extern void DynDNSConfigDidChange( mDNS * const inMDNS );
extern void FileSharingDidChange( mDNS * const inMDNS );
extern void FirewallDidChange( mDNS * const inMDNS );
extern mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock );
extern mStatus SetupInterfaceList( mDNS * const inMDNS );
extern mStatus TearDownInterfaceList( mDNS * const inMDNS );
extern BOOL IsWOMPEnabled();
extern void DispatchSocketEvents( mDNS * const inMDNS );
#ifdef __cplusplus
}
#endif
#endif // __MDNS_WIN32__

38
src/tools/mdnssd/main.c Normal file
View File

@@ -0,0 +1,38 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 2002-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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
#include "Service.h"
#include "Shellapi.h"
//===========================================================================================================================
// main
//===========================================================================================================================
int APIENTRY wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
LPWSTR *argv;
int argc, res;
argv = CommandLineToArgvW(lpCmdLine, &argc);
if (argv == NULL)
argc = 0;
res = Main( argc, argv );
LocalFree(argv);
return res;
}

View File

@@ -1,19 +1,12 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-10-14T10:22:27
#
#-------------------------------------------------
QT -= gui QT -= gui
QT += core TEST = 0
include(../../../qtcreator.pri)
CONFIG -= console testlib TEST
TARGET = mdnssd TARGET = mdnssd
CONFIG += console
CONFIG -= app_bundle CONFIG -= app_bundle
TEMPLATE = app TEMPLATE = app
include(../../../qtcreator.pri)
DESTDIR = $$IDE_BIN_PATH DESTDIR = $$IDE_BIN_PATH
DEFINES += PID_FILE=\\\"/var/run/mdnsd.pid\\\" MDNS_UDS_SERVERPATH=\\\"/var/run/mdnsd\\\" MDNS_DEBUGMSGS=0 DEFINES += PID_FILE=\\\"/var/run/mdnsd.pid\\\" MDNS_UDS_SERVERPATH=\\\"/var/run/mdnsd\\\" MDNS_DEBUGMSGS=0
@@ -21,10 +14,6 @@ DEFINES += PID_FILE=\\\"/var/run/mdnsd.pid\\\" MDNS_UDS_SERVERPATH=\\\"/var/run/
SOURCES += \ SOURCES += \
uds_daemon.c \ uds_daemon.c \
uDNS.c \ uDNS.c \
PosixDaemon.c \
PlatformCommon.c \
mDNSUNP.c \
mDNSPosix.c \
mDNSDebug.c \ mDNSDebug.c \
mDNS.c \ mDNS.c \
GenLinkedList.c \ GenLinkedList.c \
@@ -35,9 +24,7 @@ SOURCES += \
HEADERS += \ HEADERS += \
uds_daemon.h \ uds_daemon.h \
uDNS.h \ uDNS.h \
PlatformCommon.h \
mDNSUNP.h \ mDNSUNP.h \
mDNSPosix.h \
mDNSEmbeddedAPI.h \ mDNSEmbeddedAPI.h \
mDNSDebug.h \ mDNSDebug.h \
GenLinkedList.h \ GenLinkedList.h \
@@ -46,14 +33,70 @@ HEADERS += \
DebugServices.h \ DebugServices.h \
dns_sd.h dns_sd.h
linux-* {
SOURCES += mDNSPosix.c \
PlatformCommon.c \
PosixDaemon.c \
mDNSUNP.c
HEADERS +=\
PlatformCommon.h \
mDNSPosix.h
}
*-g++ { *-g++ {
QMAKE_CFLAGS += -Wno-unused-but-set-variable QMAKE_CFLAGS += -Wno-unused-but-set-variable
QMAKE_CXXFLAGS += -Wno-unused-but-set-variable QMAKE_CXXFLAGS += -Wno-unused-but-set-variable
} }
linux-* { linux-* {
DEFINES += _GNU_SOURCE HAVE_IPV6 NOT_HAVE_SA_LEN USES_NETLINK HAVE_LINUX TARGET_OS_LINUX DEFINES += _GNU_SOURCE HAVE_IPV6 NOT_HAVE_SA_LEN USES_NETLINK HAVE_LINUX TARGET_OS_LINUX
} }
macx { macx {
DEFINES += HAVE_IPV6 __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 __APPLE_USE_RFC_2292 DEFINES += HAVE_IPV6 __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 __APPLE_USE_RFC_2292
} }
win32 {
HEADERS += \
CommonServices.h \
DebugServices.h \
Firewall.h \
mDNSWin32.h \
Poll.h \
resource.h \
Secret.h \
Service.h \
RegNames.h
SOURCES += \
DebugServices.c \
Firewall.cpp \
LegacyNATTraversal.c \
main.c \
mDNSWin32.c \
Poll.c \
Secret.c \
Service.c
RC_FILE = Service.rc
MC_FILES += \
EventLog.mc
OTHER_FILES += \
$$MC_FILES \
Service.rc
DEFINES += HAVE_IPV6 _WIN32_WINNT=0x0501 NDEBUG MDNS_DEBUGMSGS=0 TARGET_OS_WIN32 WIN32_LEAN_AND_MEAN USE_TCP_LOOPBACK PLATFORM_NO_STRSEP PLATFORM_NO_EPIPE PLATFORM_NO_RLIMIT UNICODE _UNICODE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 _LEGACY_NAT_TRAVERSAL_ _USE_32BIT_TIME_T
LIBS += ws2_32.lib advapi32.lib ole32.lib oleaut32.lib iphlpapi.lib netapi32.lib user32.lib powrprof.lib shell32.lib
mc.output = ${QMAKE_FILE_BASE}.h
mc.commands = mc ${QMAKE_FILE_NAME}
mc.input = MC_FILES
mc.CONFIG += no_link target_predeps explicit_dependencies
QMAKE_EXTRA_COMPILERS += mc
}
target.path=/bin
INSTALLS+=target

View File

@@ -0,0 +1,17 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Service.rc
//
#define IDS_SERVICE_DESCRIPTION 100
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -101,7 +101,7 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
#pragma mark - Name Server List Management #pragma mark - Name Server List Management
#endif #endif
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf) mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface1, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf)
{ {
DNSServer **p = &m->DNSServers; DNSServer **p = &m->DNSServers;
DNSServer *tmp = mDNSNULL; DNSServer *tmp = mDNSNULL;
@@ -114,16 +114,16 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
if (!d) d = (const domainname *)""; if (!d) d = (const domainname *)"";
LogInfo("mDNS_AddDNSServer: Adding %#a for %##s, InterfaceID %p, scoped %d", addr, d->c, interface, scoped); LogInfo("mDNS_AddDNSServer: Adding %#a for %##s, InterfaceID %p, scoped %d", addr, d->c, interface1, scoped);
if (m->mDNS_busy != m->mDNS_reentrancy+1) if (m->mDNS_busy != m->mDNS_reentrancy+1)
LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
while (*p) // Check if we already have this {interface,address,port,domain} tuple registered while (*p) // Check if we already have this {interface,address,port,domain} tuple registered
{ {
if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->teststate != DNSServer_Disabled && if ((*p)->scoped == scoped && (*p)->interface1 == interface1 && (*p)->teststate != DNSServer_Disabled &&
mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d)) mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
{ {
if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface); if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface1);
(*p)->flags &= ~DNSServer_FlagDelete; (*p)->flags &= ~DNSServer_FlagDelete;
tmp = *p; tmp = *p;
*p = tmp->next; *p = tmp->next;
@@ -143,7 +143,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
{ {
NumUnicastDNSServers++; NumUnicastDNSServers++;
(*p)->scoped = scoped; (*p)->scoped = scoped;
(*p)->interface = interface; (*p)->interface1 = interface1;
(*p)->addr = *addr; (*p)->addr = *addr;
(*p)->port = port; (*p)->port = port;
(*p)->flags = DNSServer_FlagNew; (*p)->flags = DNSServer_FlagNew;
@@ -4215,7 +4215,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries); q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
else err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL); else err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface1, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
} }
} }

View File

@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*- /* -*- Mode: C; tab-width: 4 -*-
* *
* Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved. * Copyright (c) 2003-2011 Apple Computer, Inc. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,7 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
#if defined(_WIN32) #if defined(WIN32)
#include <WinSock2.h>
#include <process.h> #include <process.h>
#define usleep(X) Sleep(((X)+999)/1000) #define usleep(X) Sleep(((X)+999)/1000)
#else #else
@@ -282,8 +283,9 @@ mDNSexport DNameListElem *AutoBrowseDomains; // List created from those local-o
mDNSlocal void FatalError(char *errmsg) mDNSlocal void FatalError(char *errmsg)
{ {
char* ptr = NULL;
LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno)); LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
*(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does *ptr = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
abort(); // On platforms where writing to zero doesn't generate an exception, abort instead abort(); // On platforms where writing to zero doesn't generate an exception, abort instead
} }
@@ -2334,7 +2336,7 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
#endif #endif
// ask the questions // ask the questions
LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c); LogOperation("%3d: DNSServiceResolve(%X %d %##s) START", request->sd, flags, interfaceIndex, request->u.resolve.qsrv.qname.c);
err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv); err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
if (!err) if (!err)
{ {
@@ -4299,7 +4301,7 @@ mDNSexport void udsserver_info(mDNS *const m)
const char *ifname; const char *ifname;
mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID; mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
if (!InterfaceID && cr->resrec.rDNSServer) if (!InterfaceID && cr->resrec.rDNSServer)
InterfaceID = cr->resrec.rDNSServer->interface; InterfaceID = cr->resrec.rDNSServer->interface1;
ifname = InterfaceNameForID(m, InterfaceID); ifname = InterfaceNameForID(m, InterfaceID);
CacheUsed++; CacheUsed++;
if (cr->CRActiveQuestion) CacheActive++; if (cr->CRActiveQuestion) CacheActive++;
@@ -4707,7 +4709,7 @@ struct CompileTimeAssertionChecks_uds_daemon
// Check our structures are reasonable sizes. Including overly-large buffers, or embedding // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
// other overly-large structures instead of having a pointer to them, can inadvertently // other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably. // cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_request_state [(sizeof(request_state) <= 1784) ? 1 : -1]; char sizecheck_request_state [(sizeof(request_state) <= 2000) ? 1 : -1];
char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1]; char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1];
char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1]; char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1];
char sizecheck_browser_t [(sizeof(browser_t) <= 1050) ? 1 : -1]; char sizecheck_browser_t [(sizeof(browser_t) <= 1050) ? 1 : -1];

View File

@@ -5,6 +5,7 @@ SUBDIRS = qtpromaker \
win32 { win32 {
SUBDIRS += qtcdebugger SUBDIRS += qtcdebugger
SUBDIRS += mdnssd
# win64interrupt only make sense for 64bit builds # win64interrupt only make sense for 64bit builds
ENV_CPU=$$(CPU) ENV_CPU=$$(CPU)
ENV_LIBPATH=$$(LIBPATH) ENV_LIBPATH=$$(LIBPATH)