📄 cbtarget.cpp
字号:
static BOOL
LPCFinish()
{
// signal the stopped flag
g_Stopped = TRUE;
TraceTag(ttidDevice,"%s: Stopping LPCInvokeRequestHandler Thread\n", __FUNCTION__);
// wait for the listen thread exit
if (g_hLPCThread)
{
DWORD dwWait;
CancelCallbacks();
dwWait = WaitForSingleObject(g_hLPCThread, 10000);
if (dwWait == WAIT_TIMEOUT)
{
// This is to handle a couple of possible race conditions:
// 1- The callback thread is blocked in LockList() while processing a callback
// 2- CancelCallbacks() was called too early, before the callback thread had a chance to
// call into the UPNPSVC process.
// No harm done in either case, apart from the 10 second delay
TraceTag(ttidError,"CallbackThread did not exit after 10 secs, abandoning..\n");
CancelCallbacks();
}
CloseHandle(g_hLPCThread);
g_hLPCThread = NULL;
TraceTag(ttidDevice,"%s: Thread Handle Closed and Shutdown Signalled\n", __FUNCTION__);
}
// delete any remaining callbacks
CallbackTarget::CleanupList();
return TRUE;
}
BOOL
InitCallbackTarget(PCWSTR pszName, PUPNPCALLBACK pfCallback, PVOID pvContext, DWORD *phCallback)
{
CallbackTarget *pNewCallback;
TraceTag(ttidDevice, "%s: Adding Callback for %S\n", __FUNCTION__, pszName);
if (!pszName || !pfCallback)
return FALSE;
// create a new callback target
pNewCallback = NULL;
CallbackTarget::LockList();
if (!g_hLPCThread)
{
LPCInit();
}
if (g_hLPCThread && CallbackTarget::SearchByName(pszName) == NULL)
{
pNewCallback = new CallbackTarget(pszName, pfCallback, pvContext);
if (pNewCallback)
{
if (pNewCallback->Name())
{
CallbackTarget::Link(pNewCallback);
if (phCallback)
*phCallback = pNewCallback->Handle();
}
else
{
// init error
delete pNewCallback;
pNewCallback = NULL;
}
}
}
else if (g_hLPCThread)
SetLastError(ERROR_FILE_EXISTS);
else
SetLastError(ERROR_OUTOFMEMORY);
if (g_hLPCThread && IsListEmpty(&CallbackTarget::list))
{
// error case
// there are no other targets on the list, so clean up the thread
LPCFinish();
}
CallbackTarget::UnlockList();
return (pNewCallback != NULL);
}
BOOL
StopCallbackTarget(PCWSTR pszName)
{
CallbackTarget *pCallback;
TraceTag(ttidDevice, "%s: Removing Callback for %S\n", __FUNCTION__, pszName);
// delete the callback target
CallbackTarget::LockList();
pCallback = CallbackTarget::SearchByName(pszName);
if (pCallback)
{
CallbackTarget::Unlink(pCallback); // remove from list
delete pCallback;
}
if (g_hLPCThread && IsListEmpty(&CallbackTarget::list))
{
// if this was the last target, clean up the callback thread
LPCFinish();
}
CallbackTarget::UnlockList();
return (pCallback != NULL);
}
const WCHAR c_szDefaultSOAPFault [] =
L"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n"
L" <SOAP-ENV:Body>\r\n"
L" <SOAP-ENV:Fault>\r\n"
L" <faultcode>SOAP-ENV: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>501</errorCode>\r\n"
L" <errorDescription>Action Failed</errorDescription>\r\n"
L" </UPnPError>\r\n"
L" </detail>\r\n"
L" </SOAP-ENV:Fault>\r\n"
L" </SOAP-ENV:Body>\r\n"
L"</SOAP-ENV:Envelope>";
const WCHAR c_szSOAPRespOK[] = 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"
L" </s:Body>\r\n"
L"</s:Envelope>\r\n";
SOAPHandler::SOAPHandler(DWORD hSource, PCWSTR pszUDN, PCWSTR pszServiceId, PCWSTR pszRequestXML)
:
m_hSource(hSource),
m_pszServiceType(NULL),
m_pszUDN(pszUDN),
m_pszServiceId(pszServiceId),
m_pszRequestXML(pszRequestXML),
m_pszAction(NULL),
m_cParams(0),
m_cArgsMax(0),
m_pParams(NULL),
m_fResponse(FALSE),
m_bParsingBody(false),
m_bParsingAction(false),
m_bParsingArgument(false)
{
}
// Parse
BOOL SOAPHandler::Parse()
{
HRESULT hr = E_UNEXPECTED;
if(m_pReader->valid())
{
(*m_pReader)->putContentHandler(this);
VARIANT vt;
vt.vt = VT_BSTR;
vt.bstrVal = SysAllocString(m_pszRequestXML);
hr = (*m_pReader)->parse(vt);
if(FAILED(hr))
TraceTag(ttidError, "SAXXMLReader::parse returned error 0x%08x", hr);
(*m_pReader)->putContentHandler(NULL);
// avoid VariantClear to minimize dependency on oleaut32
SysFreeString(vt.bstrVal);
}
else
hr = m_pReader->Error();
if(SUCCEEDED(hr))
{
// map the UPNPSERVICECONTROL pointers
m_SvcCtl.pszRequestXML = m_pszRequestXML;
m_SvcCtl.pszUDN = m_pszUDN;
m_SvcCtl.pszSID = m_pszServiceId;
m_SvcCtl.pszServiceType = m_pszServiceType;
m_SvcCtl.pszAction = m_pszAction;
m_SvcCtl.cInArgs = m_cParams;
m_SvcCtl.pInArgs = m_pParams;
// back pointer for locating the ControlRequest from the SvcCtl
m_SvcCtl.Reserved1 = this;
return true;
}
else
return false;
}
static wchar_t* pwszEnvelopeElement =
L"<http://schemas.xmlsoap.org/soap/envelope/>"
L"<Envelope>";
static wchar_t* pwszBodyElement =
L"<http://schemas.xmlsoap.org/soap/envelope/>"
L"<Envelope>"
L"<http://schemas.xmlsoap.org/soap/envelope/>"
L"<Body>";
static wchar_t* pwszControlNamespace =
L"urn:schemas-upnp-org:control-1-0";
// startElement
HRESULT STDMETHODCALLTYPE SOAPHandler::startElement(
/* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
/* [in] */ int cchNamespaceUri,
/* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
/* [in] */ int cchLocalName,
/* [in] */ const wchar_t __RPC_FAR *pwchQName,
/* [in] */ int cchQName,
/* [in] */ ISAXAttributes __RPC_FAR *pAttributes)
{
SAXContentHandler::startElement(pwchNamespaceUri, cchNamespaceUri, pwchLocalName, cchLocalName, pwchQName, cchQName, pAttributes);
// Envelope element
if(pwszEnvelopeElement == m_strFullElementName)
{
// verify that we understand the encoding scheme
const wchar_t* pwchEncodingStyle;
int cbEncodingStyle;
if(FAILED(pAttributes->getValueFromName(pwchNamespaceUri, cchNamespaceUri, L"encodingStyle", 13, &pwchEncodingStyle, &cbEncodingStyle)) ||
0 != wcsncmp(L"http://schemas.xmlsoap.org/soap/encoding/", pwchEncodingStyle, cbEncodingStyle))
{
return E_FAIL;
}
}
// argument element - either no namespace (actions) or "control" namespace (QueryStateVariable)
if(m_bParsingAction && !m_bParsingArgument && 0 == wcsncmp(pwchNamespaceUri, pwszControlNamespace, cchNamespaceUri))
{
// reallocate arguments array if needed
if (m_cParams == m_cArgsMax)
{
UPNPPARAM *pParamsTmp;
if(m_cArgsMax)
m_cArgsMax *= 2;
else
m_cArgsMax = 2;
if(!(pParamsTmp = new UPNPPARAM [m_cArgsMax]))
return ERROR_OUTOFMEMORY;
memcpy(pParamsTmp, m_pParams, m_cParams * sizeof(UPNPPARAM));
delete [] m_pParams;
m_pParams = pParamsTmp;
}
// copy argument name
if(LPWSTR pszName = new WCHAR[cchLocalName + 1])
{
wcsncpy(pszName, pwchLocalName, cchLocalName);
pszName[cchLocalName] = L'\x0';
m_pParams[m_cParams].pszName = pszName;
}
else
m_pParams[m_cParams].pszName = NULL;
// argument value to be set later
m_pParams[m_cParams].pszValue = NULL;
m_strArgumentValue.resize(0);
m_bParsingArgument = true;
m_strArgumentElement = m_strFullElementName;
}
// action element
if(m_bParsingBody && !m_bParsingAction)
{
// copy service type
Assert(!m_pszServiceType);
if(m_pszServiceType = new WCHAR[cchNamespaceUri + 1])
{
wcsncpy(m_pszServiceType, pwchNamespaceUri, cchNamespaceUri);
m_pszServiceType[cchNamespaceUri] = L'\x0';
}
// copy action name
Assert(!m_pszAction);
if(m_pszAction = new WCHAR[cchLocalName + 1])
{
wcsncpy(m_pszAction, pwchLocalName, cchLocalName);
m_pszAction[cchLocalName] = L'\x0';
}
m_bParsingAction = true;
m_strActionElement = m_strFullElementName;
}
// Body element
if(pwszBodyElement == m_strFullElementName)
m_bParsingBody = true;
return S_OK;
}
// endElement
HRESULT STDMETHODCALLTYPE SOAPHandler::endElement(
/* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
/* [in] */ int cchNamespaceUri,
/* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
/* [in] */ int cchLocalName,
/* [in] */ const wchar_t __RPC_FAR *pwchQName,
/* [in] */ int cchQName)
{
// argument element
if(m_strArgumentElement == m_strFullElementName)
{
// trim white spaces
m_strArgumentValue.trim(L"\n\r\t ");
// set argument value
m_pParams[m_cParams].pszValue = StrDupW(m_strArgumentValue);
// increment arguments count
m_cParams++;
m_bParsingArgument = false;
}
// action element
if(m_strActionElement == m_strFullElementName)
m_bParsingAction = false;
// Body element
if(pwszBodyElement == m_strFullElementName)
m_bParsingBody = false;
return SAXContentHandler::endElement(pwchNamespaceUri, cchNamespaceUri, pwchLocalName, cchLocalName, pwchQName, cchQName);
}
// characters
HRESULT STDMETHODCALLTYPE SOAPHandler::characters(
/* [in] */ const wchar_t __RPC_FAR *pwchChars,
/* [in] */ int cchChars)
{
if(m_strArgumentElement == m_strFullElementName)
m_strArgumentValue.append(pwchChars, cchChars);
return S_OK;
}
SOAPHandler::~SOAPHandler()
{
DWORD i;
m_SvcCtl.Reserved1 = NULL; // this helps catch bogus callbacks after we're gone
delete [] m_pszServiceType;
delete [] m_pszAction;
for (i=0; i < m_cParams; i++)
{
delete [] const_cast<LPWSTR>(m_pParams[i].pszName);
delete [] const_cast<LPWSTR>(m_pParams[i].pszValue);
}
delete [] m_pParams;
}
BOOL
SOAPHandler::SetResponse(DWORD dwHttpStatus, PCWSTR pszResp)
{
return (m_fResponse = (ERROR_SUCCESS == proxy.call(UPNP_IOCTL_SET_RAW_CONTROL_RESPONSE, m_hSource, dwHttpStatus, pszResp)));
}
//
// This method is called at the end of request handling to send a default response, if necessary
BOOL
SOAPHandler::Done(BOOL fRet)
{
//
// only set the response if the device implementation has not already called SetRawControlResponse
//
if (!m_fResponse)
{
if (fRet)
{
// default success response
int cch = wcslen(m_pszAction) + wcslen(m_pszServiceType) + celems(c_szSOAPRespOK);
PWCHAR pszRawResp = new WCHAR [cch];
if (pszRawResp)
{
cch -= wsprintfW(pszRawResp,c_szSOAPRespOK,m_pszAction, m_pszServiceType);
Assert(cch > 0);
fRet = SetResponse(HTTP_STATUS_OK, pszRawResp);
delete[] pszRawResp;
}
}
else
{
// default failure response
fRet = SetResponse(HTTP_STATUS_SERVER_ERROR, c_szDefaultSOAPFault);
}
m_fResponse = TRUE;
}
else
fRet = TRUE;
return fRet;
}
//
// Called from the device implementation, while processing the UPnP control request
// Locate the owning ControlRequest from the UPNPSERVICECONTROL structure and
// set the response bytes that are to be returned to the control point.
//
BOOL
WINAPI
UpnpSetRawControlResponse(UPNPSERVICECONTROL *pSvcCtl, DWORD dwHttpStatus, PCWSTR pszResp)
{
SOAPHandler *pSoapReq;
BOOL fRet;
__try {
pSoapReq = (SOAPHandler *)pSvcCtl->Reserved1;
// check that this is an actual ControlRequest
if (&pSoapReq->m_SvcCtl != pSvcCtl)
{
// failed the sanity check
Assert(FALSE);
fRet = FALSE;
__leave;
}
fRet = pSoapReq->SetResponse( dwHttpStatus, pszResp);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
fRet = FALSE;
}
return fRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -