📄 btsdpcon.cpp
字号:
case SdpPDU_Error:
default:
status = STATUS_INVALID_NETWORK_RESPONSE;
break;
}
}
else {
switch (pdu.pduId) {
case SdpPDU_ServiceSearchRequest:
ASSERT(!IsClient());
status = OnServiceSearchRequest(&pdu, pResponse, &sdpError);
break;
case SdpPDU_ServiceAttributeRequest:
ASSERT(!IsClient());
status = OnServiceAttributeRequest(&pdu, pResponse, &sdpError);
break;
case SdpPDU_ServiceSearchAttributeRequest:
ASSERT(!IsClient());
status = OnServiceSearchAttributeRequest(&pdu, pResponse, &sdpError);
break;
default:
sdpError = SDP_ERROR_INVALID_REQUEST_SYNTAX;
status = STATUS_UNSUCCESSFUL;
}
if (!NT_SUCCESS(status)) {
ReadAsync();
WriteSdpError(pdu.transactionId, sdpError);
}
}
return status;
}
#endif // UNDER_CE
NTSTATUS
SdpConnection::SendInitialRequestToServer(
PIRP pClientIrp,
PVOID pRequest,
USHORT requestLength,
UCHAR pduId
)
{
u.Client.lastPduRequest = pduId;
ASSERT (!u.Client.pRequest); // non-NULL here indicates mem leak
//
// raw request length is the guts of the request w/out the PDU header and
// without the ContinuationState of zero
//
u.Client.rawParametersLength = requestLength - sizeof(SdpPDU) - sizeof(UCHAR);
u.Client.pRequest = pRequest;
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
// In WinCE on initial request we queue it up.
IoMarkIrpPending(pClientIrp);
pRequestorIrp = pClientIrp;
//
// Send the read down before we send out the request in case the response
// is super fast
//
ReadAsync();
_RegisterConnectionOnTimer(this, TRUE);
//
// Store the request buffer so that we can resend if the response needs
// to be segmented
//
Write(pRequest, requestLength);
return STATUS_PENDING;
#else // UNDER_CE
return SendOrQueueRequest();
#endif
}
void
SdpConnection::CompleteClientRequest(
ULONG_PTR info,
NTSTATUS status
)
{
if (u.Client.pRequest)
ExFreePool(u.Client.pRequest);
// PIRP pIrp = pRequestorIrp;
FlushClientRequestCache(status);
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
//
// If the buffer is too small, we must conver this to success so that we
// can send the requestor the correct amount of data
//
if (status == STATUS_BUFFER_TOO_SMALL) {
status = STATUS_SUCCESS;
}
if (status == STATUS_IO_TIMEOUT) {
CIRP_LIST list;
Release(pIrp);
clientQueue.Cleanup(&list);
PIRP irp;
while (!list.IsEmpty()) {
irp = list.RemoveHead();
Release(irp);
irp->IoStatus.Information = 0;
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
}
else {
ReleaseAndProcessNextRequest(pIrp);
}
pIrp->IoStatus.Information = info;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
#endif // UNDER_CE
}
void
SdpConnection::CleanUpServerSearchResults()
{
if (u.Server.pOriginalAlloc) {
ExFreePool(u.Server.pOriginalAlloc);
}
if (u.Server.pClientRequest) {
ExFreePool(u.Server.pClientRequest);
}
RtlZeroMemory(&u.Server, sizeof(u.Server));
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
NTSTATUS
SdpConnection::ReadAsync(
BOOLEAN shortOk
)
{
IoReuseIrp(pReadIrp, STATUS_SUCCESS);
RtlZeroMemory(pReadBrb, sizeof(BRB));
pReadBrb->BrbHeader.Length = sizeof (_BRB_L2CA_ACL_TRANSFER);
pReadBrb->BrbHeader.Type = BRB_L2CA_ACL_TRANSFER;
pReadBrb->BrbL2caAclTransfer.BufferMDL = NULL;
pReadBrb->BrbL2caAclTransfer.Buffer = pReadBuffer;
pReadBrb->BrbL2caAclTransfer.BufferSize = inMtu;
pReadBrb->BrbL2caAclTransfer.hConnection = hConnection;
pReadBrb->BrbL2caAclTransfer.TransferFlags = BTHPORT_TRANSFER_DIRECTION_IN;
if (shortOk) {
pReadBrb->BrbL2caAclTransfer.TransferFlags |= BTHPORT_SHORT_TRANSFER_OK;
}
pReadBrb->BrbHeader.Status = STATUS_SUCCESS;
return SendBrbAsync(pReadBrb,
_ReadAsyncCompletion,
pReadIrp,
(PVOID) this);
}
NTSTATUS
SdpConnection::SendBrbAsync(
PBRB pBrb,
PIO_COMPLETION_ROUTINE Routine,
PIRP pIrp,
PVOID pContext,
PVOID pArg1,
PVOID pArg2,
PVOID pArg3,
PVOID pArg4)
{
PIO_STACK_LOCATION stack;
KEVENT event;
NTSTATUS status;
stack = IoGetNextIrpStackLocation(pIrp);
stack->Parameters.Others.Argument1 = pArg1;
stack->Parameters.Others.Argument2 = pArg2;
stack->Parameters.Others.Argument3 = pArg3;
stack->Parameters.Others.Argument4 = pArg4;
IoSetNextIrpStackLocation(pIrp);
stack = IoGetNextIrpStackLocation(pIrp);
stack->Parameters.Others.Argument1 = pBrb;
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_BTH_SUBMIT_BRB;
IoSetCompletionRoutine(pIrp,
Routine,
pContext,
TRUE,
TRUE,
TRUE);
return IoCallDriver(pDevice->m_Struct.FunctionalDeviceObject, pIrp);
}
NTSTATUS SdpConnection::SendBrb(PBRB pBrb, PIRP pIrp)
{
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
BOOLEAN ownIrp = FALSE;
PIO_STACK_LOCATION stack;
KEVENT event;
if (pIrp == NULL) {
pIrp = IoAllocateIrp(pDevice->m_Struct.FunctionalDeviceObject->StackSize,
FALSE);
ownIrp = TRUE;
if (pIrp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
else {
IoReuseIrp(pIrp, STATUS_SUCCESS);
}
stack = IoGetNextIrpStackLocation(pIrp);
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_BTH_SUBMIT_BRB;
stack->Parameters.Others.Argument1 = pBrb;
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(pIrp,
SendBrbCompletion,
(PVOID) &event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver(pDevice->m_Struct.FunctionalDeviceObject, pIrp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
status = pIrp->IoStatus.Status;
}
if (ownIrp) {
IoFreeIrp(pIrp);
}
return status;
}
NTSTATUS
SdpConnection::Write(
PVOID pBuffer,
ULONG length
)
{
PIO_STACK_LOCATION stack;
RtlZeroMemory(&writeBrb, sizeof(writeBrb));
writeBrb.BrbHeader.Length = sizeof (_BRB_L2CA_ACL_TRANSFER);
writeBrb.BrbHeader.Type = BRB_L2CA_ACL_TRANSFER;
writeBrb.BrbL2caAclTransfer.BufferMDL = NULL;
writeBrb.BrbL2caAclTransfer.Buffer = pBuffer;
writeBrb.BrbL2caAclTransfer.BufferSize = length;
writeBrb.BrbL2caAclTransfer.hConnection = hConnection;
writeBrb.BrbL2caAclTransfer.TransferFlags = 0;
writeBrb.BrbHeader.Status = STATUS_SUCCESS;
IoReuseIrp(pWriteIrp, STATUS_SUCCESS);
// return SendBrb(&writeBrb, pWriteIrp);
stack = IoGetNextIrpStackLocation(pWriteIrp);
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_BTH_SUBMIT_BRB;
stack->Parameters.Others.Argument1 = &writeBrb;
IoSetCompletionRoutine(pWriteIrp,
SendBrbCompletion,
NULL,
TRUE,
TRUE,
TRUE);
return IoCallDriver(pDevice->m_Struct.FunctionalDeviceObject, pWriteIrp);
}
#endif // UNDER_CE
NTSTATUS
SdpConnection::WriteSdpError(
USHORT transactionId,
SDP_ERROR sdpErrorValue
)
{
SdpPDU pdu;
UCHAR buffer[sizeof(SdpPDU) + sizeof(USHORT)];
USHORT param;
//
// write an error back
//
pdu.pduId = SdpPDU_Error;
pdu.transactionId = transactionId;
pdu.parameterLength = sizeof(USHORT);
pdu.Write(buffer);
param = sdpErrorValue;
param = RtlUshortByteSwap(param);
RtlCopyMemory(buffer + sizeof(SdpPDU), ¶m, sizeof(param));
return Write(buffer, sizeof(buffer));
}
void
SdpConnection::FlushClientRequestCache(
NTSTATUS status
)
{
if (status != STATUS_BUFFER_TOO_SMALL) {
if (u.Client.pLastRange) {
delete[] u.Client.pLastRange;
}
if (u.Client.AttributeSearch.pResponse) {
delete[] u.Client.AttributeSearch.pResponse;
}
}
RtlZeroMemory(&u.Client, sizeof(u.Client));
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
NTSTATUS
SdpConnection::IsPreviousRequest(
PIRP pIrp,
UCHAR pduId,
SdpQueryUuid *pUuid,
SdpAttributeRange *pRange,
ULONG numRange,
ULONG_PTR* pInfo
)
/*++
Right now, only the last query is saved. If more than one application is
trying to query the server, the following will occur:
App A runs query, output buffer too small, result is cached
App B runs query, blows away cached result
App A resends query, instead of getting cached version, must go over the wire
One solution to this is to store the cached results in the file object.
That way, the results are stored on an app by app basis. This limits the
caching to one per file handle.
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
if (u.Client.lastPduRequest == pduId && pduId != SdpPDU_ServiceSearchRequest) {
ASSERT(u.Client.pLastRange != NULL);
ULONG rangeSize = numRange * sizeof(SdpAttributeRange);
//
// Always compare ranges b/c the 2 response we cache both have ranges
// in their requests
//
if (numRange == u.Client.numRange &&
(rangeSize ==RtlCompareMemory(pRange, u.Client.pLastRange, rangeSize))) {
//
// If this is a service + attribute search, check the UUIDS
// otherwise just drop in b/c the attribs already matched
//
if ((pduId == SdpPDU_ServiceSearchAttributeRequest &&
sizeof(u.Client.lastUuid) !=
RtlCompareMemory(pUuid, u.Client.lastUuid, sizeof(u.Client.lastUuid)))
||
pduId == SdpPDU_ServiceAttributeRequest) {
BthSdpStreamResponse *pResponse;
PIO_STACK_LOCATION stack;
ULONG outLen, responseSize, toCopy;
stack = IoGetCurrentIrpStackLocation(pRequestorIrp);
pResponse = (BthSdpStreamResponse *)
pRequestorIrp->AssociatedIrp.SystemBuffer;
outLen = stack->Parameters.DeviceIoControl.OutputBufferLength;
responseSize =
outLen - (sizeof(*pResponse) - sizeof(pResponse->response));
*pInfo = sizeof(pResponse) - sizeof(pResponse->response);
pResponse->requiredSize = u.Client.AttributeSearch.responseLength;
if (u.Client.AttributeSearch.responseLength > responseSize) {
toCopy = responseSize;
status = STATUS_BUFFER_TOO_SMALL;
}
else {
toCopy = u.Client.AttributeSearch.responseLength;
status = STATUS_SUCCESS;
}
pResponse->responseSize = toCopy;
*pInfo += toCopy;
RtlCopyMemory(pResponse->response,
u.Client.AttributeSearch.pResponse,
toCopy);
}
}
}
FlushClientRequestCache(status);
//
// We want to give the request the answer, but we must return success for
// any of the data to propagate back up. We don't do this before the flush
// cache call b/c otherwise we would blow away the cached data.
//
if (status == STATUS_BUFFER_TOO_SMALL) {
status = STATUS_SUCCESS;
}
return status;
}
#endif // UNDER_CE
NTSTATUS
SdpConnection::SendContinuationRequestToServer(
ContinuationState *pContState
)
{
if (sizeof(SdpPDU) + u.Client.rawParametersLength + pContState->GetTotalSize() >
outMtu) {
DbgPrint("----: could not fit request in a packet!!!\n");
return STATUS_INVALID_NETWORK_RESPONSE;
}
SdpPDU pdu;
pdu.Read(u.Client.pRequest);
pdu.transactionId = transactionId++;
pdu.parameterLength = u.Client.rawParametersLength + pContState->GetTotalSize();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -