📄 devsvc.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 "pch.h"
#pragma hdrstop
#include <devsvc.h>
#include <httpext.h>
CRITICAL_SECTION g_csUPNP;
LIST_ENTRY g_DevTreeList;
static HostedDeviceTree *FindDevTreeByName(PCWSTR pszDevTreeName)
{
LIST_ENTRY *pLink;
for (pLink = g_DevTreeList.Flink; pLink != &g_DevTreeList; pLink = pLink->Flink)
{
HostedDeviceTree *pDevTree;
pDevTree = CONTAINING_RECORD(pLink, HostedDeviceTree, m_link);
if (wcscmp(pszDevTreeName, pDevTree->Name()) == 0)
return pDevTree;
}
return NULL;
}
static HostedDeviceTree *FindDevTreeSafe(PCWSTR pszDevName)
{
HostedDeviceTree *pDevTree = NULL;
EnterCriticalSection(&g_csUPNP);
__try {
pDevTree = FindDevTreeByName(pszDevName);
if (!pDevTree)
{
SetLastError(ERROR_FILE_NOT_FOUND);
__leave;
}
pDevTree->IncRef();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
}
LeaveCriticalSection(&g_csUPNP);
return pDevTree;
}
// find HostedDevTree by UDN. If found, increment refcount and return pointer
static HostedDeviceTree *FindDevTreeByUDN(PCWSTR pszUDN)
{
HostedDeviceTree *pDevTree = NULL;
LIST_ENTRY *pLink;
EnterCriticalSection(&g_csUPNP);
for (pLink = g_DevTreeList.Flink; pLink != &g_DevTreeList; pLink = pLink->Flink)
{
pDevTree = CONTAINING_RECORD(pLink, HostedDeviceTree, m_link);
if(NULL != pDevTree->FindDevice(pszUDN))
{
pDevTree->IncRef();
break;
}
}
LeaveCriticalSection(&g_csUPNP);
if(pLink == &g_DevTreeList)
return NULL;
return pDevTree;
}
HostedDeviceTree *FindDevTreeAndServiceIdFromUri(PCSTR pszaUri, PWSTR *ppszUDN, PWSTR *ppszSid)
{
// szaUri is "UDN+ServiceID"
const CHAR *pszaSid;
HostedDeviceTree *pDevTree = NULL;
PWSTR pszUDN;
*ppszUDN = NULL;
*ppszSid = NULL;
pszaSid = strchr(pszaUri, '+');
if (!pszaSid)
return FALSE;
pszUDN = new WCHAR [pszaSid - pszaUri + 1];
if (pszUDN) {
mbstowcs(pszUDN, pszaUri, pszaSid - pszaUri);
pszUDN[pszaSid - pszaUri] = 0; // null terminate;
pDevTree = FindDevTreeByUDN(pszUDN);
if(pDevTree)
*ppszUDN = pszUDN;
else
delete [] pszUDN;
}
pszaSid++;
if (pDevTree)
{
if (ppszSid)
{
*ppszSid = StrDupAtoW(pszaSid);
if (!*ppszSid)
{
pDevTree->DecRef();
pDevTree = NULL;
delete *ppszUDN;
*ppszUDN = NULL;
}
}
}
return pDevTree;
}
/*
* UPnP Service Interface
*
* - upnpsvc interface routines
* - parameter checking delegates
*
*/
// FORWARD Declarations
BOOL UpnpAddDeviceImpl(__in HANDLE hOwner, __in UPNPDEVICEINFO* pDevInfo);
BOOL UpnpRemoveDeviceImpl(__in PCWSTR pszDeviceName);
BOOL UpnpPublishDeviceImpl(__in PCWSTR pszDeviceName);
BOOL UpnpUnpublishDeviceImpl(__in PCWSTR pszDeviceName);
BOOL UpnpGetUDNImpl(__in PCWSTR pszDeviceName, __in PCWSTR pszTemplateUDN, __out ce::psl_buffer_wrapper<PWSTR>& UDNBuf, __out PDWORD pcchBuf);
BOOL UpnpGetSCPDPathImpl(__in PCWSTR pszDeviceName, __in PCWSTR pszUDN, __in PCWSTR pszServiceId, __out ce::psl_buffer_wrapper<PWSTR>& SCPDFilePath);
BOOL SetRawControlResponseImpl(__in DWORD hRequest, __in DWORD dwHttpStatus, __in PCWSTR pszResp);
BOOL UpnpSubmitPropertyEventImpl(__in PCWSTR pszDeviceName, __in PCWSTR pszUDN, __in PCWSTR pszServiceId, __in ce::psl_buffer_wrapper<UPNPPARAM*> Args);
BOOL UpnpUpdateEventedVariablesImpl(PCWSTR pszDeviceName, PCWSTR pszUDN, PCWSTR pszServiceId, ce::psl_buffer_wrapper<UPNPPARAM*> Args);
BOOL ReceiveInvokeRequestImpl(__in DWORD retCode, __out ce::psl_buffer_wrapper<PBYTE>& pReqBuf, __out PDWORD pcbReqBuf);
/*
* UpnpAddDeviceImpl:
*
* - perform parameter checking then differ to delegate
*
*/
BOOL UpnpAddDeviceImpl(__in HANDLE hOwner, __in ce::marshal_arg<ce::copy_in, UPNPDEVICEINFO*> pDevInfo)
{
if (!pDevInfo ||
pDevInfo->cbStruct != sizeof(UPNPDEVICEINFO) ||
!pDevInfo->pszDeviceDescription ||
!pDevInfo->pszDeviceName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return UpnpAddDeviceImpl(hOwner, static_cast<UPNPDEVICEINFO*>(pDevInfo));
}
/*
* UpnpAddDeviceImpl:
*
* - create a new HostedDeviceTree object representing the upnp device
*
*/
BOOL UpnpAddDeviceImpl(__in HANDLE hOwner, __in UPNPDEVICEINFO* pDevInfo)
{
DWORD error = NO_ERROR;
BOOL fRet = FALSE;
HostedDeviceTree *pDevTree;
EnterCriticalSection(&g_csUPNP);
pDevTree = FindDevTreeByName(pDevInfo->pszDeviceName);
if (pDevTree)
{
error = ERROR_ALREADY_EXISTS;
goto Finish;
}
pDevTree = new HostedDeviceTree();
if (!pDevTree)
{
error = ERROR_OUTOFMEMORY;
goto Finish;
}
// because we can't load MSXML in a borrowed thread without sideeffects
// the following hack is to do the initialization in another thread
#pragma warning(push)
#pragma warning(disable:4068) // warning C4068: unknown pragma
#pragma prefast(disable:11) // prefast bug - doesn't understand variable declaration in a conditional
if(struct HDTInitInfo *pinitInfo = new struct HDTInitInfo)
{
pinitInfo->pHDT = pDevTree;
pinitInfo->devInfo.cbStruct = sizeof(pinitInfo->devInfo);
pinitInfo->devInfo.pszDeviceDescription = StrDupW(pDevInfo->pszDeviceDescription);
pinitInfo->devInfo.pszDeviceName = StrDupW(pDevInfo->pszDeviceName);
pinitInfo->devInfo.pszUDN = StrDupW(pDevInfo->pszUDN);
pinitInfo->devInfo.cachecontrol = pDevInfo->cachecontrol;
pinitInfo->devInfo.pfCallback = pDevInfo->pfCallback;
pinitInfo->devInfo.pvUserDevContext = pDevInfo->pvUserDevContext;
pinitInfo->hOwner = hOwner;
pinitInfo->hOwnerProc = GetCallerProcess();
pinitInfo->fRet = FALSE;
HANDLE h = CreateThread(NULL, 0, HostedDeviceTree::Initialize2, pinitInfo, 0, NULL);
if(h)
{
DWORD dwWait;
dwWait = WaitForSingleObject(h, INFINITE);
Assert(dwWait == WAIT_OBJECT_0);
CloseHandle(h);
}
fRet = pinitInfo->fRet;
delete pinitInfo->devInfo.pszDeviceDescription;
delete pinitInfo->devInfo.pszDeviceName;
delete pinitInfo->devInfo.pszUDN;
delete pinitInfo;
}
#pragma prefast(enable:11)
#pragma warning(pop)
if (!fRet)
{
delete pDevTree;
pDevTree = NULL;
}
else
{
pDevTree->IncRef(); // set the refcount to 1
pDevTree->AddToList(&g_DevTreeList);
}
Finish:
LeaveCriticalSection(&g_csUPNP);
if (error)
{
fRet = FALSE;
SetLastError(error);
}
return fRet;
}
/*
* UpnpRemoveDeviceImpl:
*
* - perform parameter checking and differ to delegate
* - pszDeviceName must be non-null and not the empty-string
*
*/
BOOL UpnpRemoveDeviceImpl(__in ce::marshal_arg<ce::copy_in, PCWSTR> pszDeviceName)
{
if(!pszDeviceName || !*pszDeviceName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return UpnpRemoveDeviceImpl((PCWSTR) pszDeviceName);
}
/*
* UpnpRemoveDeviceImpl:
*
* - find the HostedDeviceTree from the device name
* - remove the HostedDeviceTree from the device list
* - shutdown the device and cleanup resource allocations
*
*/
BOOL UpnpRemoveDeviceImpl(__in PCWSTR pszDeviceName)
{
HostedDeviceTree *pDevTree = NULL;
EnterCriticalSection(&g_csUPNP);
pDevTree = FindDevTreeByName(pszDeviceName);
if (!pDevTree)
{
SetLastError(ERROR_FILE_NOT_FOUND);
goto Finish;
}
pDevTree->RemoveFromList();
Finish:
LeaveCriticalSection(&g_csUPNP);
if (pDevTree)
{
pDevTree->Shutdown();
delete pDevTree;
return TRUE;
}
return FALSE;
}
/*
* UpnpPublishDeviceImpl:
*
* - perform parameter checking and differ to delegate
* - pszDeviceName must be non-null and not the empty-string
*
*/
BOOL UpnpPublishDeviceImpl(__in ce::marshal_arg<ce::copy_in, PCWSTR> pszDeviceName)
{
if(!pszDeviceName || !*pszDeviceName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return UpnpPublishDeviceImpl((PCWSTR) pszDeviceName);
}
/*
* UpnpPublishDeviceImpl:
*
* - publish the specified device
*
*/
BOOL UpnpPublishDeviceImpl(__in PCWSTR pszDeviceName)
{
BOOL fRet;
HostedDeviceTree *pDevTree;
pDevTree = FindDevTreeSafe(pszDeviceName);
fRet = FALSE;
if (pDevTree)
{
fRet = pDevTree->Publish();
pDevTree->DecRef();
}
return fRet;
}
/*
* UpnpUnpublishDeviceImpl:
*
* - perform parameter checking and differ to delegate
* - pszDeviceName must be non-null and not the empty-string
*
*/
BOOL UpnpUnpublishDeviceImpl(__in ce::marshal_arg<ce::copy_in, PCWSTR> pszDeviceName)
{
if(!pszDeviceName || !*pszDeviceName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return UpnpUnpublishDeviceImpl((PCWSTR) pszDeviceName);
}
/*
* UpnpUnpublishDeviceImpl:
*
* - unpublish the specified device
*
*/
BOOL UpnpUnpublishDeviceImpl(__in PCWSTR pszDeviceName)
{
BOOL fRet;
HostedDeviceTree *pDevTree;
pDevTree = FindDevTreeSafe(pszDeviceName);
fRet = FALSE;
if (pDevTree)
{
fRet = pDevTree->Unpublish();
pDevTree->DecRef();
}
return fRet;
}
/*
* UpnpGetUDNImpl:
*
* - ensure that the device name is not null or empty string
* - ensure that the UDN buffer count is not 0
* - ensure that the UDN buffer size pointer is not null
*
*/
BOOL
UpnpGetUDNImpl(
__in ce::marshal_arg<ce::copy_in, PCWSTR> pszDeviceName, // [in] local device name
__in ce::marshal_arg<ce::copy_in, PCWSTR> pszTemplateUDN, // [in, optional] the UDN element in the original device description
__out ce::marshal_arg<ce::copy_out, ce::psl_buffer_wrapper<PWSTR> > UDNBuf, // [out] UDN buffer
__out ce::marshal_arg<ce::copy_out, PDWORD> pcchBuf) // [out] size of buffer/ length filled (in WCHARs)
{
if(!pszDeviceName || !*pszDeviceName)
{
goto Finish;
}
if(!(UDNBuf.count()) || !pcchBuf)
{
goto Finish;
}
return UpnpGetUDNImpl((PCWSTR) pszDeviceName,
static_cast<PCWSTR>(pszTemplateUDN),
static_cast<ce::psl_buffer_wrapper<PWSTR> >(UDNBuf),
static_cast<PDWORD>(pcchBuf));
Finish:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/*
* UpnpGetUDNImpl:
*
* - get device UDN based on device name
* - copy UDN into the UDN buffer and indicate the size in pcchBuf
*
*/
BOOL UpnpGetUDNImpl(__in PCWSTR pszDeviceName, __in PCWSTR pszTemplateUDN, __out ce::psl_buffer_wrapper<PWSTR>& UDNBuf, __out PDWORD pcchBuf)
{
BOOL fRet = FALSE;
HostedDeviceTree *pDevTree;
pDevTree = FindDevTreeSafe(pszDeviceName);
if (pDevTree)
{
HostedDevice *pDev;
pDev = pDevTree->FindDeviceByOrigUDN(pszTemplateUDN);
if (pDev && pDev->UDN())
{
DWORD cch = wcslen(pDev->UDN())+1;
if (UDNBuf.count() >= cch)
{
wcscpy(UDNBuf.buffer(), pDev->UDN());
fRet = TRUE;
}
else
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -