📄 obexdevice.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.
//
// ObexDevice.cpp: implementation of the CObexDevice class.
//
//////////////////////////////////////////////////////////////////////
//#ERROR -- use fixed memory
#include "common.h"
#include "ObexDevice.h"
#include "ObexParser.h"
#include "ObexStream.h"
#include "ObexPacketInfo.h"
#include "HeaderEnum.h"
#include "HeaderCollection.h"
#include "ObexStrings.h"
#include <MD5.h>
#include <intsafe.h>
void MD5(void *dest, void *orig, int len)
{
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, (UCHAR *)orig, len);
MD5Final(&context);
memcpy(dest, context.digest, 16);
}
#if defined(DEBUG) || defined(_DEBUG)
#define SVSLOG_BPR 8
void DumpBuff (unsigned char *lpBuffer, unsigned int cBuffer)
{
WCHAR szLine[5 + 7 + 2 + 4 * SVSLOG_BPR];
for (int i = 0 ; i < (int)cBuffer ; i += SVSLOG_BPR) {
int bpr = cBuffer - i;
if (bpr > SVSLOG_BPR)
bpr = SVSLOG_BPR;
wsprintf (szLine, L"%04x ", i);
WCHAR *p = szLine + wcslen (szLine);
for (int j = 0 ; j < bpr ; ++j) {
WCHAR c = (lpBuffer[i + j] >> 4) & 0xf;
if (c > 9) c += L'a' - 10; else c += L'0';
*p++ = c;
c = lpBuffer[i + j] & 0xf;
if (c > 9) c += L'a' - 10; else c += L'0';
*p++ = c;
*p++ = L' ';
}
for ( ; j < SVSLOG_BPR ; ++j) {
*p++ = L' ';
*p++ = L' ';
*p++ = L' ';
}
*p++ = L' ';
*p++ = L' ';
*p++ = L' ';
*p++ = L'|';
*p++ = L' ';
*p++ = L' ';
*p++ = L' ';
for (j = 0 ; j < bpr ; ++j) {
WCHAR c = lpBuffer[i + j];
if ((c < L' ') || (c >= 127))
c = L'.';
*p++ = c;
}
for ( ; j < SVSLOG_BPR ; ++j)
*p++ = L' ';
*p++ = L'\n';
*p++ = L'\0';
SVSUTIL_ASSERT (p == szLine + sizeof(szLine)/sizeof(szLine[0]));
DEBUGMSG(OBEX_DUMP_PACKETS_ZONE, (L"%s", szLine));
}
}
#endif
//////////////////////////////////////////////////////////////////////
// Utility section
//////////////////////////////////////////////////////////////////////
static HRESULT MakeResponse (const WCHAR *_pszPassToUse, BYTE *bChallenge, BYTE *bResponse) {
INT cp = CP_UTF8;
UCHAR ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
if (! ucPassLen)
{
cp = CP_ACP;
ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
}
if (! ucPassLen)
return E_FAIL;
UINT uiEncodeSize = 16 + 1 + ucPassLen;
BYTE bEncodeBuffer[512];
BYTE *bToEncode = (uiEncodeSize > sizeof(bEncodeBuffer)) ? new BYTE[uiEncodeSize] : bEncodeBuffer;
if (! bToEncode)
return E_FAIL;
memcpy (bToEncode, bChallenge, 16);
bToEncode[16] = ':';
HRESULT hr = E_FAIL;
if (WideCharToMultiByte (cp, 0, _pszPassToUse, -1, (char *)(bToEncode + 17), ucPassLen, NULL, NULL))
{
MD5(bResponse, bToEncode, uiEncodeSize - 1); // -1 because we don't want terminating '\0'
hr = ERROR_SUCCESS;
}
if (bToEncode != bEncodeBuffer)
delete [] bToEncode;
return ERROR_SUCCESS;
}
static HRESULT MakeNonce (const WCHAR *_pszPassToUse, BYTE *bMyNonce)
{
SYSTEMTIME st;
GetSystemTime(&st);
INT cp = CP_UTF8;
UCHAR ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
if (! ucPassLen)
{
cp = CP_ACP;
ucPassLen = WideCharToMultiByte(cp, 0, _pszPassToUse, -1, NULL, 0, NULL, NULL);
}
if (! ucPassLen)
return E_FAIL;
UINT uiEncodeSize = 16 + 1 + ucPassLen;
BYTE bEncodeBuffer[512];
BYTE *bToEncode = (uiEncodeSize > sizeof(bEncodeBuffer)) ? new BYTE[uiEncodeSize] : bEncodeBuffer;
if (! bToEncode)
return E_FAIL;
//16 bytes plus NULL ... so its okay to directly write in bToEncode... the NULL will be replaced!
sprintf((char *)bToEncode, "%4.4d%2.2d%2.2dT%2.2d%2.2d%2.2dZ", st.wYear,st.wMonth,st.wDay, st.wHour,st.wMinute,st.wSecond);
SVSUTIL_ASSERT(16 == strlen((char *)bToEncode));
bToEncode[16] = ':';
HRESULT hr = E_FAIL;
if (WideCharToMultiByte (cp, 0, _pszPassToUse, -1, (char *)(bToEncode + 17), ucPassLen, NULL, NULL))
{
MD5(bMyNonce, bToEncode, uiEncodeSize - 1); // -1 because we don't want terminating '\0'
hr = ERROR_SUCCESS;
}
if (bToEncode != bEncodeBuffer)
delete [] bToEncode;
return hr;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CObexDevice::CObexDevice(IPropertyBag *_pPropBag, CLSID clsidTrans) :
_refCount(1),
pConnection(0),
pSocket(0),
uiConnectionId(OBEX_INVALID_CONNECTION),
uiMaxPacket(255 - OBEX_AUTH_HEADER_SIZE), //the min packet size for OBEX is 255... this value can get
// renegotiated during CONNECT
pPropBag(_pPropBag),
iPresent(g_iCredits),
iModified(g_iCredits),
uiUpdateStatus(0),
uiActiveStreamID(0xFFFFFFFF)
{
wcPassword[0] = '\0';
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::CObexDevice() -- propbag: 0x%x -- me: 0x%x\n",(int)_pPropBag, (int)this));
PREFAST_ASSERT(_pPropBag);
_pPropBag->AddRef();
clsidTransport = clsidTrans;
}
CObexDevice::~CObexDevice()
{
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::~CObexDevice() -- me: 0x%x\n", (int)this));
if(pConnection)
pConnection->Release();
if(pPropBag)
pPropBag->Release();
if(pSocket)
pSocket->Release();
}
HRESULT STDMETHODCALLTYPE
CObexDevice::Disconnect(LPHEADERCOLLECTION pHeaders)
{
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::Disconnect()\n"));
PREFAST_ASSERT(pHeaders);
//first if there is an ongoing stream, deactiveate it
uiActiveStreamID = 0xFFFFFFFF;
//make sure we have a connection ID
if(uiConnectionId != OBEX_INVALID_CONNECTION)
pHeaders->AddConnectionId(uiConnectionId);
HRESULT hRes = E_FAIL;
if(pHeaders)
{
UCHAR *pNewPacket = NULL;
ULONG uiNewPackSize;
//send off the packet
hRes = ObexSendRecv(pConnection, uiMaxPacket, (char)OBEX_OP_DISCONNECT, 0,0, pHeaders, &pNewPacket, &uiNewPackSize);
if (FAILED(hRes) || pNewPacket[0] != (OBEX_STAT_OK | OBEX_OP_ISFINAL))
hRes = E_FAIL;
else
{
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::Disconnect() -- failed? socket went down?\n"));
}
if(pNewPacket)
delete [] pNewPacket;
}
return hRes;
}
HRESULT STDMETHODCALLTYPE
CObexDevice::Get(LPHEADERCOLLECTION pHeaders, IStream **pStream)
{
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::Get()\n"));
//if a get is requested the old stream is marked invalid
// note: this will be replaced below once the stream is created
uiActiveStreamID =0xFFFFFFFF;
//if we have an obex device but dont have a connection, they have not
// used a connection point (and thus have not 'BoundToDevice'...
// do the transport connection for them
if(!pConnection && FAILED(ConnectSocket()))
return E_FAIL;
//return an obex stream
CObexStream *pOBEXStream = new CObexStream(pConnection, this, uiMaxPacket, uiConnectionId, wcPassword, &pHeaders);
if(pOBEXStream && pOBEXStream->IsInited())
{
*pStream = pOBEXStream;
uiActiveStreamID = pOBEXStream->GetStreamID();
return S_OK;
}
else if(pOBEXStream)
{
//pOBEXStream fails to initialize
delete pOBEXStream;
return E_OUTOFMEMORY;
}
else
return E_OUTOFMEMORY;
}
HRESULT STDMETHODCALLTYPE
CObexDevice::Put(LPHEADERCOLLECTION pHeaders, IStream **pStream)
{
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::Put()\n"));
//
// Make sure they arent trying to squeeze in a BODY or BODY_END
// with our interfaces, this is an error... they are using a
// STREAM and by definition that uses the BODY/BODY_END fields.
//
IHeaderEnum *pHeaderEnum;
OBEX_HEADER *myHeader;
ULONG ulFetched;
//if a Put is requested the old stream is not used anymore -- so release it
uiActiveStreamID = 0xFFFFFFFF;
pHeaders->EnumHeaders(&pHeaderEnum);
while(SUCCEEDED(pHeaderEnum->Next(1, &myHeader, &ulFetched)))
{
if(myHeader->bId == OBEX_HID_BODY || myHeader->bId == OBEX_HID_BODY_END)
{
DEBUGMSG(OBEX_OBEXSTREAM_ZONE,(L"CObexStream::Write() -- failed. CANT use BODY/BODY_END with a PUT!"));
pHeaderEnum->Release();
return E_FAIL;
}
}
pHeaderEnum->Release();
//if we have an obex device but dont have a connection, they have not
// used a connection point (and thus have not 'BoundToDevice'...
// do the transport connection for them
if(!pConnection && FAILED(ConnectSocket()))
return E_FAIL;
//return an obex stream
CObexStream *pOBEXStream = new CObexStream(pConnection, this, uiMaxPacket, uiConnectionId, wcPassword, pHeaders);
//if there is an existing stream, release it
if(pOBEXStream && pOBEXStream->IsInited())
{
*pStream = pOBEXStream;
uiActiveStreamID = pOBEXStream->GetStreamID();
return S_OK;
}
else if(pOBEXStream)
{
//pOBEXStream fails to initialize
delete pOBEXStream;
return E_OUTOFMEMORY;
}
else
return E_OUTOFMEMORY;
}
HRESULT STDMETHODCALLTYPE
CObexDevice::Abort(LPHEADERCOLLECTION pHeaders)
{
HRESULT hRes = S_OK;
//invalidate our stream
uiActiveStreamID = 0xFFFFFFFF;
//if we have an obex device but dont have a connection, they have not
// used a connection point (and thus have not 'BoundToDevice'...
// do the transport connection for them
if(!pConnection && FAILED(ConnectSocket()))
return E_FAIL;
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::Abort() -- sending OBEX Abort packet\n"));
if(uiConnectionId != OBEX_INVALID_CONNECTION)
pHeaders->AddConnectionId(uiConnectionId);
UCHAR *pNewPacket = NULL;
ULONG uiNewPackSize;
//send off the packet
hRes = ObexSendRecv(pConnection, uiMaxPacket, (char)OBEX_OP_ABORT, 0,0, pHeaders, &pNewPacket, &uiNewPackSize);
if (FAILED(hRes) || pNewPacket[0] != (OBEX_STAT_OK | OBEX_OP_ISFINAL))
hRes = E_FAIL;
delete [] pNewPacket;
return hRes;
}
HRESULT STDMETHODCALLTYPE
CObexDevice::SetPath(LPCWSTR szRemotePath, DWORD dwFlags, LPHEADERCOLLECTION pHeaders)
{
DEBUGMSG(OBEX_OBEXDEVICE_ZONE,(L"CObexDevice::SetPath()\n"));
PREFAST_ASSERT(szRemotePath);
//if a Put is requested the old stream is not used anymore -- so release it
uiActiveStreamID = 0xFFFFFFFF;
//if we have an obex device but dont have a connection, they have not
// used a connection point (and thus have not 'BoundToDevice'...
// do the transport connection for them
if(!pConnection && FAILED(ConnectSocket()))
return E_FAIL;
//sanity checks
SVSUTIL_ASSERT(szRemotePath);
if(!pHeaders)
pHeaders = new CHeaderCollection();
else
pHeaders->AddRef();
if(NULL == pHeaders)
return E_OUTOFMEMORY;
HRESULT hResult;
unsigned char cOpCode = OBEX_OP_SETPATH;
struct PUTFields
{
char flags;
char constants;
};
PUTFields fields;
memset(&fields, 0, sizeof(PUTFields));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -