📄 sdpns.cxx
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
//------------------------------------------------------------------------------
//
// Bluetooth SDP Name Space Layer
//
//
// Module Name:
//
// sdpns.cxx
//
// Abstract:
//
// This file implements SDP Name Space handling and inquiry.
//
//
//------------------------------------------------------------------------------
#include "common.h"
#include <winsock2.h>
#include <svsutil.hxx>
#include <bt_debug.h>
// declarations and global data
static int bthns_ServiceSearch_Out(void *pCallContext, unsigned long status, unsigned short cReturnedHandles, unsigned long *pHandles);
static int bthns_AttributeSearch_Out(void *pCallContext, unsigned long status, unsigned char *pOutBuf, unsigned long cOutBuf);
static int bthns_ServiceAttributeSearch_Out(void *pCallContext, unsigned long status, unsigned char *pOutBuf, unsigned long cOutBuf);
static int bthns_StackEvent(void *pUserContext, int iEvent, void *pEventContext);
static int bthns_Connect_Out(void *pCallContext, unsigned long status, unsigned short cid);
static int bthns_Disconnect_Out(void *pCallContext, unsigned long status);
// On searching, number of milliseconds to wait for a response before canceling search.
#define SPD_SEARCH_DEFAULT_TIMEOUT 30000
static DWORD g_dwSearchTimeout;
static const TCHAR g_szSDPBaseKey[] = TEXT("Software\\Microsoft\\Bluetooth\\SDP");
static const TCHAR g_szTimeoutVal[] = TEXT("SearchTimeOut");
struct Call {
Call *pNext;
HANDLE hEvent;
// Return values to SDP calls. Note: Call does NOT free buffers
int iResult;
unsigned short cid;
unsigned char *pClientBuf; // client output buffer
unsigned long cClientBuf; // sizeof client output buffer.
};
#define INQUIRY_PENDING 1
#define INQUIRY_INPROGRESS 2
#define INQUIRY_COMPLETED 3
struct BthNsHandle {
// BthNsHandle internals
BthNsHandle *pNext;
Call *pCall;
// BthNsHandle's initial values.
DWORD dwFlags;
PBTHNS_RESTRICTIONBLOB pResBlob;
BD_ADDR b;
// ServiceClassId and Range are only used when lpServiceClassId != NULL and no RestrcitionBlob set in WSALookupServiceBegin()
GUID ServiceClassId;
unsigned int fLocal : 1; // search to be done on local device
unsigned int fNetSearchComplete : 1; // has search been sent across the wire
unsigned int fNoMoreData : 1; // when all data has been sent up to Winsock level.
unsigned int fXPCompatMode : 1; // TRUE if we use XP bluetooth data structures, FALSE if we use legacy WinCE structs.
unsigned int fInquiryStatus : 2; // PENDING/INPROGRESS/DONE
unsigned char *pClientBuf; // client output buffer
unsigned long cClientBuf; // sizeof client output buffer.
unsigned long LAP;
unsigned int cDuration;
unsigned int cMaxResp;
// results from a device inquiry.
BthInquiryResult *pInquiryResults;
unsigned int cDevices;
unsigned int iDeviceIterator; // when iterating through device list in BthNsLookupServiceNext
};
enum BTHNS_STAGE {
JustCreated = 0,
Initializing,
Running,
ShuttingDown
};
class BthNs : public SVSSynch, public SVSRefObj {
public:
FixedMemDescr *pfmdBthNsHandles;
FixedMemDescr *pfmdNSCAlls;
BthNsHandle *pBthNsHandles;
Call *pCalls;
SDP_INTERFACE sdp_if;
HANDLE hSDP;
BTHNS_STAGE eStage;
void ReInit(void) {
pfmdBthNsHandles = NULL;
pfmdNSCAlls = NULL;
pBthNsHandles = NULL;
pCalls = NULL;
hSDP = NULL;
memset(&sdp_if,0,sizeof(sdp_if));
eStage = JustCreated;
}
BthNs(void) {
ReInit();
}
};
BthNs *gpBthNS = NULL;
static BOOL DeleteBthNsHandle(BthNsHandle *pBthNsHandle) {
SVSUTIL_ASSERT(gpBthNS->IsLocked());
BOOL fRet = TRUE;
if (pBthNsHandle == gpBthNS->pBthNsHandles)
gpBthNS->pBthNsHandles = pBthNsHandle->pNext;
else {
BthNsHandle *pParent = gpBthNS->pBthNsHandles;
while (pParent && (pParent->pNext != pBthNsHandle))
pParent = pParent->pNext;
if (pParent)
pParent->pNext = pBthNsHandle->pNext;
else
fRet = FALSE;
}
if (fRet) {
if (pBthNsHandle->pClientBuf)
ExFreePool(pBthNsHandle->pClientBuf);
if (pBthNsHandle->pResBlob)
g_funcFree(pBthNsHandle->pResBlob,g_pvAllocData);
if (pBthNsHandle->pInquiryResults)
g_funcFree(pBthNsHandle->pInquiryResults,g_pvAllocData);
svsutil_FreeFixed(pBthNsHandle, gpBthNS->pfmdBthNsHandles);
}
return fRet;
}
static void DeleteCall(Call *pCall) {
BOOL fFound = TRUE;
if (pCall == gpBthNS->pCalls)
gpBthNS->pCalls = pCall->pNext;
else {
Call *pParent = gpBthNS->pCalls;
while (pParent && (pParent->pNext != pCall))
pParent = pParent->pNext;
if (pParent)
pParent->pNext = pCall->pNext;
else
fFound = FALSE;
}
if (fFound) {
CloseHandle(pCall->hEvent);
if (pCall->pClientBuf)
g_funcFree(pCall->pClientBuf,g_pvAllocData);
svsutil_FreeFixed(pCall, gpBthNS->pfmdNSCAlls);
}
}
static BOOL ConvertStringToBdAddr(WCHAR *szAddress, BD_ADDR *pb) {
DWORD i;
LPWSTR p = szAddress;
for (i=0; i<6 && *p; i++) {
if (i==0 && *p==L'(') {
p++;
}
while (*p && ((*p>=L'0' && *p<=L'9') ||
(*p>=L'a' && *p<=L'f') ||
(*p>=L'A' && *p<=L'F')))
{
((PUCHAR)pb)[5-i] *= 16;
if (*p>=L'0' && *p<=L'9') {
((PUCHAR)pb)[5-i] += *p - L'0';
}
else if (*p>=L'a' && *p<=L'f') {
((PUCHAR)pb)[5-i] += *p + 10 - L'a';
}
else {
((PUCHAR)pb)[5-i] += *p + 10 - L'A';
}
p++;
}
if (*p==L'(') {
// This can occur at the start of the string
// But we're not at the start
return FALSE;
}
else if (*p==L')') {
// This can occur at the end only
if (i<5) {
return FALSE;
}
p++;
}
else if (*p==L'.' || *p==L':') {
p++;
}
else if (!*p) {
if (i<5) {
return FALSE;
}
}
else {
return WSAEINVAL;
}
}
return TRUE;
}
static BthNsHandle * AllocBthNsHandle(LPWSAQUERYSET pQuerySet, DWORD dwFlags, int *piError) {
SVSUTIL_ASSERT(gpBthNS->IsLocked());
PBTHNS_RESTRICTIONBLOB pResBlob = (PBTHNS_RESTRICTIONBLOB) ( pQuerySet->lpBlob ? pQuerySet->lpBlob->pBlobData : NULL);
BOOL fSucces = FALSE;
BthNsHandle *pBthNsHandle = (BthNsHandle *)svsutil_GetFixed(gpBthNS->pfmdBthNsHandles);
if (!pBthNsHandle)
goto done;
memset(pBthNsHandle,0,sizeof(*pBthNsHandle));
pBthNsHandle->dwFlags = dwFlags;
// Get the remote address
if (dwFlags & LUP_RES_SERVICE) {
pBthNsHandle->fLocal = TRUE;
}
else if (! (dwFlags & LUP_CONTAINERS)) {
if (pQuerySet->lpcsaBuffer) {
// Legacy CE mode, in which lpcsaBuffer is passed.
SOCKADDR_BTH *pSockBT = (SOCKADDR_BTH *) pQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr;
#if defined (DEBUG) || defined (_DEBUG)
if (! __SDP_IS_ALIGNED(pSockBT, 8))
DebugOut(DEBUG_SDP_TRACE, L"SDP: Unaligned remote address in structure - FIX THE APP!\n");
#endif
memcpy(&pBthNsHandle->b,(void *)&pSockBT->btAddr,sizeof(pBthNsHandle->b));
}
else {
// On Windows XP, address is passed as a readable string in lpszContext. Implement for compat.
if (! ConvertStringToBdAddr(pQuerySet->lpszContext,&pBthNsHandle->b))
goto done;
pBthNsHandle->fXPCompatMode = TRUE;
}
}
// figure out what to query on remote device
if (! (dwFlags & LUP_CONTAINERS)) {
if (pResBlob) {
if (NULL == (pBthNsHandle->pResBlob = (PBTHNS_RESTRICTIONBLOB) g_funcAlloc(pQuerySet->lpBlob->cbSize,g_pvAllocData)))
goto done;
memcpy(pBthNsHandle->pResBlob,pResBlob,pQuerySet->lpBlob->cbSize);
}
else {
memcpy(&pBthNsHandle->ServiceClassId,pQuerySet->lpServiceClassId,sizeof(GUID));
}
}
pBthNsHandle->pNext = gpBthNS->pBthNsHandles;
gpBthNS->pBthNsHandles = pBthNsHandle;
fSucces = TRUE;
done:
if (!fSucces) {
if (pBthNsHandle) {
SVSUTIL_ASSERT(pBthNsHandle != gpBthNS->pBthNsHandles);
SVSUTIL_ASSERT(!pBthNsHandle->pResBlob);
svsutil_FreeFixed(pBthNsHandle, gpBthNS->pfmdBthNsHandles);
pBthNsHandle = NULL;
*piError = WSAEINVAL;
}
else
*piError = WSA_NOT_ENOUGH_MEMORY;
}
return pBthNsHandle;
}
static Call * AllocCall(BthNsHandle *pBthNsHandle) {
SVSUTIL_ASSERT(gpBthNS->IsLocked());
Call *pCall = (Call *)svsutil_GetFixed(gpBthNS->pfmdNSCAlls);
if (!pCall)
return NULL;
memset(pCall,0,sizeof(*pCall));
if (NULL == (pCall->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL))) {
svsutil_FreeFixed(pCall, gpBthNS->pfmdNSCAlls);
}
pCall->pNext = gpBthNS->pCalls;
gpBthNS->pCalls = pCall;
pBthNsHandle->pCall = pCall;
return pCall;
}
static BthNsHandle * FindBthNsHandle (BthNsHandle *pBthNsHandle) {
BthNsHandle *pTrav = gpBthNS->pBthNsHandles;
while (pTrav && pBthNsHandle != pTrav)
pTrav = pTrav->pNext;
return pTrav;
}
static Call * FindCall (Call *pCall) {
Call *pTrav = gpBthNS->pCalls;
while (pTrav && pCall != pTrav)
pTrav = pTrav->pNext;
return pTrav;
}
//
// Driver Interface functions
//
int bthns_InitializeOnce(void) {
IFDBG(DebugOut(DEBUG_SDP_INIT | DEBUG_SDP_TRACE,L"bthns_InitializeOnce()\r\n"));
if (gpBthNS) {
IFDBG(DebugOut(DEBUG_ERROR,L"bthns_InitializeOnce:: ERROR_ALREADY_EXISTS\r\n"));
return ERROR_ALREADY_EXISTS;
}
gpBthNS = new BthNs;
if (!gpBthNS) {
IFDBG(DebugOut(DEBUG_ERROR,L"bthns_InitializeOnce:: ERROR_OUTOFMEMORY\r\n"));
return ERROR_OUTOFMEMORY;
}
return ERROR_SUCCESS;
}
int bthns_CreateDriverInstance(void) {
HKEY hKey;
IFDBG(DebugOut(DEBUG_SDP_TRACE,L"bthns_CreateDriverInstance entered\r\n"));
if (! gpBthNS) {
IFDBG(DebugOut(DEBUG_ERROR, L"bthns_CreateDriverInstance:: ERROR_SERVICE_DOES_NOT_EXIST\n"));
return ERROR_SERVICE_DOES_NOT_EXIST;
}
gpBthNS->Lock();
if (gpBthNS->eStage != JustCreated) {
IFDBG(DebugOut(DEBUG_ERROR, L"bthns_CreateDriverInstance:: ERROR_SERVICE_ALREADY_RUNNING\n"));
gpBthNS->Unlock();
return ERROR_SERVICE_ALREADY_RUNNING;
}
gpBthNS->eStage = Initializing;
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, g_szSDPBaseKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
DWORD dwType;
DWORD dwSize;
if ((RegQueryValueEx (hKey, g_szTimeoutVal, 0, &dwType, (LPBYTE)&g_dwSearchTimeout, &dwSize) != ERROR_SUCCESS) ||
(dwType != REG_DWORD) || (dwSize != sizeof(g_dwSearchTimeout))) {
g_dwSearchTimeout = SPD_SEARCH_DEFAULT_TIMEOUT;
}
RegCloseKey (hKey);
}
else
g_dwSearchTimeout = SPD_SEARCH_DEFAULT_TIMEOUT;
IFDBG(DebugOut(DEBUG_SDP_INIT,L"SDP Default search timeout = 0x%08x milliseconds\r\n",g_dwSearchTimeout));
SVSUTIL_ASSERT(g_dwSearchTimeout);
SVSUTIL_ASSERT(! (gpBthNS->pfmdBthNsHandles && gpBthNS->pfmdNSCAlls &&
gpBthNS->pBthNsHandles && gpBthNS->pCalls));
gpBthNS->pfmdBthNsHandles = svsutil_AllocFixedMemDescr(sizeof(BthNsHandle), 10);
gpBthNS->pfmdNSCAlls = svsutil_AllocFixedMemDescr(sizeof(Call), 10);
if (!gpBthNS->pfmdBthNsHandles || !gpBthNS->pfmdNSCAlls) {
IFDBG(DebugOut(DEBUG_ERROR, L"bthns_CreateDriverInstance:: ERROR_OUTOFMEMORY\n"));
gpBthNS->Unlock();
return ERROR_OUTOFMEMORY;
}
SDP_CALLBACKS c;
SDP_EVENT_INDICATION ei;
memset(&c,0,sizeof(c));
c.sdp_Connect_Out = bthns_Connect_Out;
c.sdp_ServiceSearch_Out = bthns_ServiceSearch_Out;
c.sdp_AttributeSearch_Out = bthns_AttributeSearch_Out;
c.sdp_ServiceAttributeSearch_Out = bthns_ServiceAttributeSearch_Out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -