📄 sdpns.cxx
字号:
c.sdp_Disconnect_Out = bthns_Disconnect_Out;
ei.sdp_StackEvent = bthns_StackEvent;
int iErr = SDP_EstablishDeviceContext(NULL,&ei,&c,&gpBthNS->sdp_if,&gpBthNS->hSDP);
if (iErr != ERROR_SUCCESS) {
IFDBG(DebugOut(DEBUG_ERROR, L"bthns_CreateDriverInstance couldn't plug into SDP, err=0x%08x\n",iErr));
gpBthNS->Unlock();
return iErr;
}
SVSUTIL_ASSERT(gpBthNS->hSDP);
// SDP lower layer determines whether or not the lower stack is running or not.
gpBthNS->eStage = Running;
gpBthNS->Unlock();
return ERROR_SUCCESS;
}
int bthns_CloseDriverInstance(void) {
IFDBG(DebugOut(DEBUG_SDP_TRACE,L"BTHNS_CloseDriverInstance entered\r\n"));
SDP_CloseDeviceContext(gpBthNS->hSDP);
if (! gpBthNS) {
IFDBG(DebugOut(DEBUG_ERROR,L"sdp_CloseDriverInstance: ERROR_SERVICE_NOT_ACTIVE\r\n"));
return ERROR_SERVICE_NOT_ACTIVE;
}
gpBthNS->Lock();
if ((gpBthNS->eStage != Running) && (gpBthNS->eStage != Initializing)) {
IFDBG(DebugOut(DEBUG_ERROR, L"SDP Close Driver Instance:: ERROR_SERVICE_NOT_ACTIVE\n"));
gpBthNS->Unlock();
return ERROR_SERVICE_NOT_ACTIVE;
}
gpBthNS->eStage = ShuttingDown;
while (gpBthNS->pCalls) {
SetEvent(gpBthNS->pCalls->hEvent);
gpBthNS->pCalls->iResult = ERROR_CANCELLED;
gpBthNS->pCalls = gpBthNS->pCalls->pNext;
}
while (gpBthNS->pBthNsHandles) {
DeleteBthNsHandle(gpBthNS->pBthNsHandles);
}
while (gpBthNS->GetRefCount() > 1) {
IFDBG(DebugOut (DEBUG_SDP_TRACE, L"Waiting for ref count in bthns_CloseDriverInstance\n"));
gpBthNS->Unlock ();
Sleep (200);
gpBthNS->Lock ();
}
if (gpBthNS->hSDP)
SDP_CloseDeviceContext(gpBthNS->hSDP);
if (gpBthNS->pfmdBthNsHandles)
svsutil_ReleaseFixedNonEmpty(gpBthNS->pfmdBthNsHandles);
if (gpBthNS->pfmdNSCAlls)
svsutil_ReleaseFixedNonEmpty(gpBthNS->pfmdNSCAlls);
gpBthNS->ReInit();
gpBthNS->Unlock();
return ERROR_SUCCESS;
}
int bthns_UninitializeOnce(void) {
IFDBG(DebugOut(DEBUG_SDP_INIT | DEBUG_SDP_TRACE,L"bthns_UninitializeOnce()\r\n"));
SVSUTIL_ASSERT(gpBthNS);
if (! gpBthNS) {
IFDBG(DebugOut(DEBUG_ERROR, L"bthns_UninitializeOnce:: ERROR_SERVICE_DOES_NOT_EXIST\n"));
return ERROR_SERVICE_DOES_NOT_EXIST;
}
gpBthNS->Lock();
if (gpBthNS->eStage != JustCreated) {
IFDBG(DebugOut(DEBUG_ERROR, L"bthns_UninitializeOnce:: ERROR_DEVICE_IN_USE\n"));
gpBthNS->Unlock();
return ERROR_DEVICE_IN_USE;
}
BthNs *pBthNs = gpBthNS;
gpBthNS = NULL;
pBthNs->Unlock();
delete pBthNs;
IFDBG(DebugOut(DEBUG_SDP_INIT, L"bthns_UninitializeOnce:: ERROR_SUCCESS\n"));
return ERROR_SUCCESS;
}
static DWORD WINAPI StackDisconnect (LPVOID pArg) {
IFDBG(DebugOut (DEBUG_SDP_TRACE, L"StackDisconnect\n"));
bthns_CloseDriverInstance ();
return NULL;
}
static int bthns_StackEvent(void *pUserContext, int iEvent, void *pEventContext) {
IFDBG(DebugOut(DEBUG_SDP_TRACE,L"bthns_StackEvent:: event = %d\r\n"));
// We only handle BTH_STACK_DISCONNECT at this layer. We just BthNsHandle into SDP
// in all cases and let it keep track of stack state beyond this.
if (iEvent == BTH_STACK_DISCONNECT)
btutil_ScheduleEvent (StackDisconnect, NULL);
return ERROR_SUCCESS;
}
//
// WSA Interface helpers.
//
void SDPAbortCall(HANDLE h, Call *pCall) {
DebugOut(DEBUG_SDP_TRACE,L"SDPAbortCall (0x%08x)\r\n",pCall);
BT_LAYER_ABORT_CALL pCallback = gpBthNS->sdp_if.sdp_AbortCall;
__try {
pCallback(h,pCall);
}
__except (1) {
;
}
}
int SDPConnectBlocking(Call *pCall, BD_ADDR *pba) {
IFDBG(DebugOut(DEBUG_SDP_TRACE,L"SDPConnectBlocking (0x%04x 0x%08x)\r\n",pba->NAP,pba->SAP));
int iRet;
HANDLE hEvent = pCall->hEvent;
HANDLE h = gpBthNS->hSDP;
SDP_Connect_In pCallback = gpBthNS->sdp_if.sdp_Connect_In;
gpBthNS->AddRef();
gpBthNS->Unlock();
__try {
iRet = pCallback(h,pCall,pba);
}
__except (1) {
;
}
// We don't have a timeout here because on connection lower layers handles timeouts.
if (ERROR_SUCCESS == iRet) {
if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,INFINITE)) {
SVSUTIL_ASSERT(0);
iRet = ERROR_OPERATION_ABORTED;
SDPAbortCall(h,pCall);
}
}
gpBthNS->Lock();
gpBthNS->DelRef();
return iRet;
}
int SDPDisconnect(Call *pCall, unsigned short cid) {
IFDBG(DebugOut(DEBUG_SDP_TRACE,L"SDPDisconnectBlocking (0x%08x,0x%04x)\r\n",pCall,cid));
int iRet;
HANDLE h = gpBthNS->hSDP;
HANDLE hEvent = pCall ? pCall->hEvent : 0;
SDP_Disconnect_In pCallback = gpBthNS->sdp_if.sdp_Disconnect_In;
gpBthNS->AddRef();
gpBthNS->Unlock();
__try {
iRet = pCallback(h,pCall,cid);
} __except(1) {
;
}
// We don't have a timeout here because on connection lower layers handles timeouts.
if ((ERROR_SUCCESS == iRet) && hEvent) {
if (WAIT_OBJECT_0 != WaitForSingleObject(hEvent,INFINITE)) {
SVSUTIL_ASSERT(0);
iRet = ERROR_OPERATION_ABORTED;
}
}
gpBthNS->Lock();
gpBthNS->DelRef();
return iRet;
}
int ServiceSearchBlocking(Call *pCall, unsigned short cid, SdpQueryUuid* pUUIDs, unsigned short cMaxHandles) {
SVSUTIL_ASSERT(gpBthNS->eStage == Running);
HANDLE hEvent = pCall->hEvent;
HANDLE h = gpBthNS->hSDP;
int iRet;
SDP_ServiceSearch_In pCallback = gpBthNS->sdp_if.sdp_ServiceSearch_In;
gpBthNS->AddRef();
gpBthNS->Unlock();
__try {
iRet = pCallback(h,pCall,cid,pUUIDs,cMaxHandles);
} __except(1) {
;
}
if (ERROR_SUCCESS == iRet) {
if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,g_dwSearchTimeout)) {
iRet = ERROR_OPERATION_ABORTED;
SDPAbortCall(h,pCall);
}
}
gpBthNS->Lock();
gpBthNS->DelRef();
return iRet;
}
int AttributeSearchBlocking(Call *pCall, unsigned short cid, unsigned long recordHandle, SdpAttributeRange *pAttribRange, int numAttributes) {
SVSUTIL_ASSERT(gpBthNS->eStage == Running);
HANDLE hEvent = pCall->hEvent;
HANDLE h = gpBthNS->hSDP;
int iRet;
SDP_AttributeSearch_In pCallback = gpBthNS->sdp_if.sdp_AttributeSearch_In;
gpBthNS->AddRef();
gpBthNS->Unlock();
__try {
iRet = pCallback(h,pCall,cid,recordHandle,pAttribRange,numAttributes);
} __except(1) {
;
}
if (ERROR_SUCCESS == iRet) {
if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,g_dwSearchTimeout)) {
iRet = ERROR_OPERATION_ABORTED;
SDPAbortCall(h,pCall);
}
}
gpBthNS->Lock();
gpBthNS->DelRef();
return iRet;
}
int ServiceAttributeSearchBlocking(Call *pCall, unsigned short cid, SdpQueryUuid* pUUIDs, SdpAttributeRange *pAttribRange, int numAttributes) {
SVSUTIL_ASSERT(gpBthNS->eStage == Running);
HANDLE hEvent = pCall->hEvent;
HANDLE h = gpBthNS->hSDP;
int iRet;
SDP_ServiceAttributeSearch_In pCallback = gpBthNS->sdp_if.sdp_ServiceAttributeSearch_In;
gpBthNS->AddRef();
gpBthNS->Unlock();
__try {
iRet = pCallback(h,pCall,cid,pUUIDs,pAttribRange,numAttributes);
} __except(1) {
;
}
if (ERROR_SUCCESS == iRet) {
if (WAIT_TIMEOUT == WaitForSingleObject(hEvent,g_dwSearchTimeout)) {
iRet = ERROR_OPERATION_ABORTED;
SDPAbortCall(h,pCall);
}
}
gpBthNS->Lock();
gpBthNS->DelRef();
return iRet;
}
typedef enum {
BTHNS_SET_SERVICE,
BTHNS_LOOKUP_SERVICE_BEGIN,
BTHNS_LOOKUP_SERVICE_NEXT
} BTHNS_WSA_CALL;
#define SDP_WSA_SERVICE_BEGIN_FLAGS (LUP_RES_SERVICE | LUP_CONTAINERS)
static BOOL CheckQuerySet(LPWSAQUERYSET pQuerySet, BTHNS_WSA_CALL BthNsHandleer, DWORD dwFlags, WSAESETSERVICEOP op=RNRSERVICE_DEREGISTER) {
if (!pQuerySet || pQuerySet->dwSize != sizeof(WSAQUERYSETA) || pQuerySet->dwNameSpace != NS_BTH)
return FALSE;
switch (BthNsHandleer) {
case BTHNS_SET_SERVICE: {
if (op != RNRSERVICE_REGISTER && op != RNRSERVICE_DELETE)
return FALSE;
if (dwFlags)
return FALSE;
// if (!pQuerySet->dwNumberOfCsAddrs || !pQuerySet->lpcsaBuffer)
// return FALSE;
PBTHNS_SETBLOB pSetBlob = (PBTHNS_SETBLOB) (pQuerySet->lpBlob ? pQuerySet->lpBlob->pBlobData : NULL);
if (!pSetBlob || !pSetBlob->pSdpVersion || (*pSetBlob->pSdpVersion != BTH_SDP_VERSION) || !pSetBlob->pRecordHandle || ((op == RNRSERVICE_REGISTER) && !pSetBlob->ulRecordLength))
return FALSE;
}
break;
case BTHNS_LOOKUP_SERVICE_BEGIN: {
PBTHNS_RESTRICTIONBLOB pResBlob = (PBTHNS_RESTRICTIONBLOB) (pQuerySet->lpBlob ? pQuerySet->lpBlob->pBlobData : NULL);
if (dwFlags & ~SDP_WSA_SERVICE_BEGIN_FLAGS)
return FALSE;
if (dwFlags & LUP_CONTAINERS) {
LPBLOB lpBlob = pQuerySet->lpBlob;
if (lpBlob && (lpBlob->cbSize != sizeof(BTHNS_INQUIRYBLOB)))
return FALSE;
return TRUE; // it's OK for lpBlob to be NULL or non-NULL when doing device inquiry.
}
// pQuerySet->lpServiceClassId can be set on Service or ServiceAttribute requests.
// If pResBlob is set we use it, it has more interesting info.
if (!pQuerySet->lpServiceClassId && !pResBlob)
return FALSE;
if (!(dwFlags & LUP_RES_SERVICE)) {
// lpcsaBuffer contains an AddrInfo and is supported only on WinCE, specifies remote device to query.
// pQuerySet->lpszContext contains a string representation of a bluetooth address of remote device to query, and is for XP compat.
if (!pQuerySet->lpszContext && !pQuerySet->lpcsaBuffer)
return FALSE;
// lpszContext will be checked when we try to do conversion, just do lpcsaBuffer now.
if (pQuerySet->lpcsaBuffer) {
if ((!pQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr || (pQuerySet->lpcsaBuffer->RemoteAddr.iSockaddrLength != sizeof(SOCKADDR_BTH)))) {
return FALSE;
}
#if defined (DEBUG) || defined (_DEBUG)
if (! __SDP_IS_ALIGNED(pQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr, 8))
DebugOut(DEBUG_SDP_TRACE, L"SDP: Unaligned remote address in structure - FIX THE APP!!\n");
#endif
}
}
if (pResBlob && !(dwFlags&LUP_CONTAINERS)) {
switch (pResBlob->type) {
case SDP_SERVICE_SEARCH_REQUEST:
break;
case SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
case SDP_SERVICE_ATTRIBUTE_REQUEST:
if (!pResBlob->numRange || ((pQuerySet->lpBlob->cbSize - sizeof(BTHNS_RESTRICTIONBLOB)) % sizeof(SdpAttributeRange)) ||
(((pQuerySet->lpBlob->cbSize - sizeof(BTHNS_RESTRICTIONBLOB)) / sizeof(SdpAttributeRange) + 1) != pResBlob->numRange))
return FALSE;
break;
default:
return FALSE;
}
}
}
break;
case BTHNS_LOOKUP_SERVICE_NEXT: {
if (!pQuerySet)
return FALSE;
}
break;
default:
SVSUTIL_ASSERT(0);
}
return TRUE;
}
int MapErrorCodeToWinsockErr(int iError, BOOL fFromSetService=FALSE) {
switch (iError) {
// either lower layer failed, SDP timed out, or BthNsLookupServiceEnd()
// was called on pending search thread.
case ERROR_OPERATION_ABORTED:
case ERROR_CONNECTION_ABORTED:
case ERROR_SHUTDOWN_IN_PROGRESS:
case ERROR_CANCELLED:
return WSA_E_CANCELLED;
case ERROR_INTERNAL_ERROR:
case ERROR_INVALID_PARAMETER:
return WSAEINVAL;
case ERROR_OUTOFMEMORY:
return WSA_NOT_ENOUGH_MEMORY;
case ERROR_NOT_FOUND:
return fFromSetService ? WSA_INVALID_HANDLE : WSANO_DATA;
case ERROR_SERVICE_NOT_ACTIVE:
return WSASERVICE_NOT_FOUND;
case ERROR_CONNECTION_UNAVAIL:
return WSAENOTCONN;
default:
SVSUTIL_ASSERT(0);
}
return WSAEINVAL;
}
//
// Public interface, equivalent to WSA Set/Lookup functions.
//
// NOTE: This is preliminary, pending official data structures from NT.
//
int BthNsSetService(LPWSAQUERYSET pSet, WSAESETSERVICEOP op, DWORD dwFlags) {
IFDBG(DebugOut(DEBUG_SDP_TRACE,L"BthNsSetService entered\r\n"));
if (! gpBthNS) {
IFDBG(DebugOut(DEBUG_ERROR, L"BthNsSetService:: ERROR_SERVICE_DOES_NOT_EXIST\n"));
SetLastError(WSASERVICE_NOT_FOUND);
return SOCKET_ERROR;
}
gpBthNS->Lock();
if (gpBthNS->eStage != Running) {
IFDBG(DebugOut(DEBUG_ERROR, L"BthNsSetService:: ERROR_SERVICE_NOT_ACTIVE\n"));
gpBthNS->Unlock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -