📄 upnpcapi.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <windows.h>
#include <ssdppch.h>
#include <upnpdevapi.h>
#include <ssdpapi.h>
#include <ssdpioctl.h>
#include <service.h>
#include <upnpmem.h>
#include "ssdpfuncc.h"
#include "string.hxx"
#define celems(_x) (sizeof(_x) / sizeof(_x[0]))
BOOL InitCallbackTarget(PCWSTR pszName, PUPNPCALLBACK pfCallback, PVOID pvContext, DWORD *phCallback);
BOOL StopCallbackTarget(PCWSTR pszName);
ce::psl_proxy<> proxy(L"UPP1:", UPNP_IOCTL_INVOKE, NULL);
CRITICAL_SECTION g_csUPNPAPI;
BOOL WINAPI ClientStart()
{
return TRUE;
}
void WINAPI ClientStop()
{
}
/*
Device creation
*/
BOOL
WINAPI
UpnpAddDevice(IN UPNPDEVICEINFO *pDev)
{
BOOL fRet = FALSE;
DWORD dwCallbackHandle;
TraceTag(ttidDevice, "%s: Adding Upnp Device %S\n", __FUNCTION__, pDev->pszDeviceName);
fRet = InitCallbackTarget(pDev->pszDeviceName, pDev->pfCallback, pDev->pvUserDevContext, &dwCallbackHandle);
if(fRet)
{
PVOID pvTemp = pDev->pvUserDevContext;
pDev->pvUserDevContext = (PVOID)dwCallbackHandle;
fRet = (ERROR_SUCCESS == proxy.call(UPNP_IOCTL_ADD_DEVICE, pDev));
// restore the changed parameters
pDev->pvUserDevContext = pvTemp;
if(!fRet)
StopCallbackTarget(pDev->pszDeviceName);
}
return fRet;
}
BOOL
WINAPI
UpnpRemoveDevice(
PCWSTR pszDeviceName)
{
BOOL fRet;
TraceTag(ttidDevice, "%s: Removing Upnp Device %S\n", __FUNCTION__, pszDeviceName);
fRet = (ERROR_SUCCESS == proxy.call(UPNP_IOCTL_REMOVE_DEVICE, pszDeviceName));
StopCallbackTarget(pszDeviceName); // this may fail if the target has already been removed
return fRet;
}
/*
Publication control
*/
BOOL
WINAPI
UpnpPublishDevice(
PCWSTR pszDeviceName)
{
return ERROR_SUCCESS == proxy.call(UPNP_IOCTL_PUBLISH_DEVICE, pszDeviceName);
}
BOOL
WINAPI
UpnpUnpublishDevice(
PCWSTR pszDeviceName)
{
return ERROR_SUCCESS == proxy.call(UPNP_IOCTL_UNPUBLISH_DEVICE, pszDeviceName);
}
/*
Description info
*/
BOOL
WINAPI
UpnpGetUDN(
IN PCWSTR pszDeviceName, // [in] local device name
IN PCWSTR pszTemplateUDN, // [in, optional] the UDN element in the original device description
OUT PWSTR pszUDNBuf, // [in] buffer to hold the assigned UDN
IN OUT PDWORD pcchBuf) // [in,out] size of buffer/ length filled (in WCHARs)
{
return ERROR_SUCCESS == proxy.call(UPNP_IOCTL_GET_UDN, pszDeviceName, pszTemplateUDN, ce::psl_buffer(pszUDNBuf, *pcchBuf), pcchBuf);
}
BOOL
WINAPI
UpnpGetSCPDPath(
IN PCWSTR pszDeviceName, // [in] local device name
IN PCWSTR pszUDN,
IN PCWSTR pszServiceId, // [in] serviceId (from device description)
OUT PWSTR pszSCPDPath, // [out] file path to SCPD
IN DWORD cchFilePath) // [in] size of pszSCPDFilePath in WCHARs
{
return ERROR_SUCCESS == proxy.call(UPNP_IOCTL_GET_SCPD_PATH, pszDeviceName, pszUDN, pszServiceId, ce::psl_buffer(pszSCPDPath, cchFilePath));
}
/*
Eventing
*/
BOOL
WINAPI
UpnpSubmitPropertyEvent(
PCWSTR pszDeviceName,
PCWSTR pszUDN,
PCWSTR pszServiceName,
DWORD nArgs,
UPNPPARAM *rgArgs)
{
return ERROR_SUCCESS == proxy.call(UPNP_IOCTL_SUBMIT_PROPERTY_EVENT, pszDeviceName, pszUDN, pszServiceName, ce::psl_buffer(rgArgs, nArgs));
}
BOOL
WINAPI
UpnpUpdateEventedVariables(
PCWSTR pszDeviceName,
PCWSTR pszUDN,
PCWSTR pszServiceName,
DWORD nArgs,
UPNPPARAM *rgArgs)
{
return ERROR_SUCCESS == proxy.call(UPNP_IOCTL_UPDATE_EVENTED_VARIABLES, pszDeviceName, pszUDN, pszServiceName, ce::psl_buffer(rgArgs, nArgs));
}
bool EncodeForXML(LPCWSTR pwsz, ce::wstring* pstr)
{
wchar_t aCharacters[] = {L'<', L'>', L'\'', L'"', L'&'};
wchar_t* aEntityReferences[] = {L"<", L">", L"'", L""", L"&"};
bool bReplaced;
pstr->reserve(static_cast<ce::wstring::size_type>(1.1 * wcslen(pwsz)));
pstr->resize(0);
for(const wchar_t* pwch = pwsz; *pwch; ++pwch)
{
bReplaced = false;
for(int i = 0; i < sizeof(aCharacters)/sizeof(*aCharacters); ++i)
if(*pwch == aCharacters[i])
{
pstr->append(aEntityReferences[i]);
bReplaced = true;
break;
}
if(!bReplaced)
pstr->append(pwch, 1);
}
return true;
}
/*
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:actionNameResponse xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
<argumentName>out arg value</argumentName>
other out args and their values go here, if any
</u:actionNameResponse>
</s:Body>
</s:Envelope>
*/
const WCHAR c_szSOAPResp1[] = L"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n"
L"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
L" <s:Body>\r\n"
L" <u:%sResponse xmlns:u=\"%s\">\r\n";
const WCHAR c_szSOAPResp2[] = L" </u:%sResponse>\r\n"
L" </s:Body>\r\n"
L"</s:Envelope>\r\n";
const WCHAR c_szSOAPArg[] = L"<%s>%s</%s>\r\n";
static bool _UpnpSetControlResponse(
UPNPSERVICECONTROL *pUPNPAction,
DWORD cOutArgs,
UPNPPARAM *aOutArg,
PWSTR* ppszRawResp)
{
int cch = celems(c_szSOAPResp1) + celems(c_szSOAPResp2), cch2;
ce::wstring str;
DWORD i;
// force out argument for QueryStateVariable to be "return"
if (wcscmp(pUPNPAction->pszAction, L"QueryStateVariable") == 0 && cOutArgs == 1)
aOutArg[0].pszName = L"return";
cch += 2*wcslen(pUPNPAction->pszAction) + wcslen(pUPNPAction->pszServiceType);
for (i=0; i < cOutArgs; i++)
{
EncodeForXML(aOutArg[i].pszValue, &str);
cch += wcslen(c_szSOAPArg) + 2*wcslen(aOutArg[i].pszName) + str.length();
}
*ppszRawResp = new WCHAR [cch];
if (!*ppszRawResp)
return false;
cch2 = wsprintfW(*ppszRawResp,c_szSOAPResp1,pUPNPAction->pszAction, pUPNPAction->pszServiceType);
for (i=0; i < cOutArgs; i++)
{
EncodeForXML(aOutArg[i].pszValue, &str);
cch2+=wsprintfW(*ppszRawResp + cch2, c_szSOAPArg, aOutArg[i].pszName, static_cast<LPCWSTR>(str), aOutArg[i].pszName);
}
cch2 += wsprintfW(*ppszRawResp + cch2, c_szSOAPResp2, pUPNPAction->pszAction);
DBGCHK(L"UPNPAPI", cch2 < cch);
return true;
}
BOOL
WINAPI
UpnpSetControlResponse(
UPNPSERVICECONTROL *pUPNPAction,
DWORD cOutArgs,
UPNPPARAM *aOutArg)
{
BOOL fRet = FALSE;
PWSTR pszRawResp = NULL;
__try
{
fRet = _UpnpSetControlResponse(pUPNPAction, cOutArgs, aOutArg, &pszRawResp);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
fRet = FALSE;
}
if (fRet)
fRet = UpnpSetRawControlResponse(pUPNPAction,HTTP_STATUS_OK, pszRawResp);
if (pszRawResp)
delete[] pszRawResp;
return fRet;
}
const WCHAR c_szSOAPFault[]= L"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n"
L" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
L" <s:Body>\r\n"
L" <s:Fault>\r\n"
L" <faultcode>s:Client</faultcode>\r\n"
L" <faultstring>UPnPError</faultstring>\r\n"
L" <detail>\r\n"
L" <UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\r\n"
L" <errorCode>%d</errorCode>\r\n"
L" <errorDescription>%s</errorDescription>\r\n"
L" </UPnPError>\r\n"
L" </detail>\r\n"
L" </s:Fault>\r\n"
L" </s:Body>\r\n"
L" </s:Envelope>\r\n";
static bool _UpnpSetErrorResponse(
UPNPSERVICECONTROL *pUPNPAction,
DWORD dwErrorCode,
PCWSTR pszErrorDescription, // error code and description
PWSTR* ppszRawResp)
{
int cch;
ce::wstring strErrorDescription;
EncodeForXML(pszErrorDescription, &strErrorDescription);
cch = strErrorDescription.length() + 10 + celems(c_szSOAPFault);
*ppszRawResp = new WCHAR [cch];
if (!*ppszRawResp)
return false;
cch -= wsprintfW(*ppszRawResp, c_szSOAPFault, dwErrorCode, static_cast<LPCWSTR>(strErrorDescription));
DBGCHK(L"UPNPAPI",cch > 0);
return true;
}
BOOL
WINAPI
UpnpSetErrorResponse(
UPNPSERVICECONTROL *pUPNPAction,
DWORD dwErrorCode,
PCWSTR pszErrorDescription // error code and description
)
{
BOOL fRet = FALSE;
PWSTR pszRawResp = NULL;
__try
{
fRet = _UpnpSetErrorResponse(pUPNPAction, dwErrorCode, pszErrorDescription, &pszRawResp);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
fRet = FALSE;
}
if (fRet)
fRet = UpnpSetRawControlResponse(pUPNPAction, HTTP_STATUS_SERVER_ERROR, pszRawResp);
if (pszRawResp)
delete[] pszRawResp;
return fRet;
}
#ifdef DEBUG
DBGPARAM dpCurSettings = {
TEXT("UPNPCAPI"), {
TEXT("Misc"), TEXT("Init"), TEXT("Announce"), TEXT("Events"),
TEXT("Socket"),TEXT("Search"), TEXT("Parser"),TEXT("Timer"),
TEXT("Cache"),TEXT("Control"),TEXT("Cache"),TEXT("Device"),
TEXT(""),TEXT(""),TEXT("Trace"),TEXT("Error") },
0x00008000
};
#endif
extern "C"
BOOL
WINAPI
DllMain(IN PVOID DllHandle,
IN ULONG Reason,
IN PVOID Context OPTIONAL)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
DEBUGREGISTER((HMODULE)DllHandle);
if(!UpnpHeapCreate())
return FALSE;
InitializeCriticalSection(&g_csUPNPAPI);
SocketInit();
// We don't need to receive thread attach and detach
// notifications, so disable them to help application
// performance.
DisableThreadLibraryCalls((HMODULE)DllHandle);
svsutil_Initialize();
break;
case DLL_PROCESS_DETACH:
SocketFinish();
DeleteCriticalSection(&g_csUPNPAPI);
UpnpHeapDestroy();
break;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -