⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btsdpcon.cpp

📁 三星2440原版bsp
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    tmpStream += cs.GetTotalSize();
    ASSERT((tmpStream - stream) == totalSize);
#endif // DBG

    SdpPrint(SDP_DBG_CLIENT_INFO, ("sending initial request for service attribute search\n"));

    return SendInitialRequestToServer(pIrp, stream, (USHORT) totalSize, pdu.pduId);

Error:
    if (stream) {
        ExFreePool(stream);
    }

    if (pTreeService) {
        SdpFreeTree(pTreeService);
    }

    if (pTreeAttrib) {
        SdpFreeTree(pTreeAttrib);
    }

    ReleaseAndProcessNextRequest(pIrp);

    return status;
}

#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
BOOLEAN
SdpConnection::_RegisterConnectionOnTimer(
    SdpConnection *pConnection,
    BOOLEAN Register
    )
{
    BOOLEAN empty;
    BOOLEAN res = TRUE;
    static BOOLEAN firstCall = TRUE;

    if (firstCall) {
        firstCall = FALSE;
        InitializeListHead(&_TimeoutListHead);
        KeInitializeSpinLock(&_TimeoutListLock);
        KeInitializeTimerEx(&_TimeoutTimer, NotificationTimer);
        KeInitializeDpc(&_TimeoutTimerDpc,
                        _TimeoutTimerDpcProc,
                        NULL);
    }

    KIRQL irql;
    KeAcquireSpinLock(&_TimeoutListLock, &irql);

    if (Register == FALSE) {
        SdpConnection *pConFind = NULL;
        PLIST_ENTRY pEntry;

        res = FALSE;

        SdpPrint(SDP_DBG_TO_INFO,
                 ("trying to unregister connection %p\n", pConnection));
        pEntry = _TimeoutListHead.Flink;
        while (pEntry != &_TimeoutListHead) {
            pConFind = CONTAINING_RECORD(pEntry, SdpConnection, timerEntry);

            if (pConFind == pConnection) {
                res = TRUE;
                RemoveEntryList(&pConnection->timerEntry);
                pConnection->Release(&_TimeoutTimerDpc);

                SdpPrint(SDP_DBG_TO_INFO, ("found it in list, removing\n"));
                break;
            }

            pEntry = pEntry->Flink;
        }

        if (IsListEmpty(&_TimeoutListHead)) {
            SdpPrint(SDP_DBG_TO_TRACE, ("stopping timeout timer\n"));
            KeCancelTimer(&_TimeoutTimer);
        }
    }
    else {
        empty = IsListEmpty(&_TimeoutListHead);

        InsertTailList(&_TimeoutListHead, &pConnection->timerEntry);

        pConnection->timeoutTime = 0x0;
        pConnection->Acquire(&_TimeoutTimerDpc);

        SdpPrint(SDP_DBG_TO_INFO, ("adding connection %p to timeout list\n", pConnection));

        if (empty) {
            LARGE_INTEGER scanTime;

            SdpPrint(SDP_DBG_TO_TRACE, ("starting timeout timer\n"));

            scanTime = RtlConvertLongToLargeInteger(-10*1000*1000 * SDP_SCAN_INTERVAL);

            KeSetTimerEx(&_TimeoutTimer,
                         scanTime,
                         SDP_SCAN_INTERVAL * 1000, // in ms
                         &_TimeoutTimerDpc);
        }
    }

    KeReleaseSpinLock(&_TimeoutListLock, irql);

    return res;
}

void
SdpConnection::_TimeoutTimerDpcProc(
    IN PKDPC Dpc,
    IN PVOID DeviceObject,
    IN PVOID Context1,
    IN PVOID Context2
    )
{
    CList<SdpConnection, FIELD_OFFSET(SdpConnection, timerEntry)> list;

    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Context1);
    UNREFERENCED_PARAMETER(Context2);

    KIRQL irql;

    KeAcquireSpinLock(&_TimeoutListLock, &irql);

    SdpPrint(SDP_DBG_TO_TRACE, ("entering timeout timer DPC\n"))

    SdpConnection *pCon = NULL;
    PLIST_ENTRY pEntry;

    pEntry = _TimeoutListHead.Flink;

    while (pEntry != &_TimeoutListHead) {
        LONG count;

        pCon = CONTAINING_RECORD(pEntry, SdpConnection, timerEntry);
        count = InterlockedIncrement(&pCon->timeoutTime);

        SdpPrint(SDP_DBG_TO_INFO,
                 ("connection %p has elapsed %d s, will timeout at %d s\n",
                  pCon, count, pCon->maxTimeout));
        //
        // Advance to the next element first and foremost
        //
        pEntry = pEntry->Flink;

        //
        // If we have timed out or the requestor has cancelled their request
        // we will yank it out of the timer list and cancel the underlying
        // read request.  In the read completion routine we will process accordingly
        //
        // NOTE:  letting the user cancel the request before we get a response
        //        is tricky b/c we are only allowed on pended request to th server
        //        and cancelling the underlying read means we need to shut down
        //        entire connection and that is not fair for all the other applications
        //        that are piggybacking this connection
        //
        if (count == pCon->maxTimeout /* || pCon->pRequestorIrp->Cancel*/) {
            //
            // Then remove this element from the list and then add it to our
            // local list
            //
            RemoveEntryList(&pCon->timerEntry);
            list.AddTail(pCon);
        }
    }

    KeReleaseSpinLock(&_TimeoutListLock, irql);

    while (!list.IsEmpty()) {
        pCon = list.RemoveHead();

        SdpPrint(SDP_DBG_TO_INFO,
                 ("cancelling irp %p on connection %p\n", pCon->pReadIrp, pCon));

        IoCancelIrp(pCon->pReadIrp);
        pCon->Release(&_TimeoutTimerDpc);
    }
}

NTSTATUS
SdpConnection::_TimeoutDisconnectComplete(
    PDEVICE_OBJECT pDeviceObject,
    PIRP pIrp,
    PVOID pContext
    )
{
    SdpConnection *pCon = (SdpConnection *) pContext;

    SdpPrint(SDP_DBG_TO_TRACE, ("timeout disconnection complete\n"));

    //
    // By setting the address to zero, we are allowing new connections to be
    // created to this device (b/c we will not find an active connection in the
    // SdpInterface list)
    //
    pCon->btAddress = 0x0;
    pCon->Release(pIrp);

    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS
SdpConnection::_ReadAsyncCompletion(
    PDEVICE_OBJECT pDeviceObject,
    PIRP pIrp,
    PVOID pContext
    )
{
    SdpPrint(SDP_DBG_BRB_TRACE, ("read async complete, status = 0x%x\n",
                                pIrp->IoStatus.Status));

    UNREFERENCED_PARAMETER(pDeviceObject);
    UNREFERENCED_PARAMETER(pIrp);

    SdpConnection *pCon = (SdpConnection*) pContext;

    BOOLEAN removed;

    //
    // Will only be in the timer queue if the read is from a client connection
    //
    if (pCon->IsClient()) {
        removed = _RegisterConnectionOnTimer(pCon, FALSE);
    }
    else {
        removed = TRUE;
    }

    //
    // If we have successfully removed the conneciton from the timer, then the
    // timer did not have a change to timeout our I/O and we can proceed.  If
    // the remove failed, then the timer has fired and cancelled our I/O.  There
    // is an edge condition where the I/O completes and have removed the connection
    // from the timer list in the timer (to cancel it) but have not yet actually
    // cancelled the irp.  Because of this, we must allocate a new irp to do the
    // disconnect (but we can still reuse our read brb).
    //
    if (removed == FALSE) {
        SdpPrint(SDP_DBG_TO_INFO,
                 ("read async complete, connection NOT in timer queue\n"));

        //
        // The user must close the connection up receiving this error code.  We
        // shall disconnect from the device but keep the SdpConnection in the
        // SdpInterface list until all clients close down their handles.
        //
        KIRQL irql;

        
        //
        // By setting the channel state to closed, SdpInterface::AcquireConnection
        // will gracefully fail, not allowing any new queries to go out on the
        // wire.
        //
        pCon->LockState(&irql);
        pCon->channelState = SdpChannelStateClosed;
        pCon->UnlockState(irql);

        //
        // Can't complete the client requests here b/c we free pool when we do so
        // and we could be at DPC freeing paged pool.  Just drop into the worker
        // item and do it there.
        //
    }

    pCon->ReadAsyncComplete();

    return STATUS_MORE_PROCESSING_REQUIRED;
}

void SdpConnection::ReadAsyncComplete()
{
    ExInitializeWorkItem(&readWorkItem, _ReadWorkItemCallback, (PVOID) this);
    ExQueueWorkItem(&readWorkItem, DelayedWorkQueue);
}

void SdpConnection::_ReadWorkItemCallback(IN PVOID Parameter)
{
    ((SdpConnection*) Parameter)->ReadWorkItemWorker();
}

void SdpConnection::ReadWorkItemWorker()
{
    if (GetChannelState() == SdpChannelStateClosed) {
        //
        // Channel is closed, clean up
        //
        // Passing STATIS_IO_TIMEOUT will complete all of the pended irps as
        // well
        //
        CompleteClientRequest(0, STATUS_IO_TIMEOUT);

        //
        // The timer could have this connection in its local list and cancel cancel
        // this read irp....so we can use pCon->pReadIrp...BUT we can use
        // pCon->pWriteIrp b/c it is in no timer queue and thus cannot be
        // cancelled
        //
        BRB *pBrb = pReadBrb;
        RtlZeroMemory(pBrb, sizeof(BRB));

        pBrb->BrbHeader.Length = sizeof (_BRB_L2CA_DISCONNECT_REQ);
        pBrb->BrbHeader.Type = BRB_L2CA_DISCONNECT_REQ;
        pBrb->BrbHeader.Status = STATUS_SUCCESS;
        pBrb->BrbL2caDisconnectReq.hConnection = hConnection;

        IoReuseIrp(pWriteIrp, STATUS_SUCCESS);

        Acquire(pWriteIrp);
        SendBrbAsync(pBrb, _TimeoutDisconnectComplete, pWriteIrp, (PVOID) this);
    }
    else if (!NT_SUCCESS(pReadIrp->IoStatus.Status)) {
        if (IsClient()) {
            CompleteClientRequest(0, pReadIrp->IoStatus.Status);
        }
        else {
                        Release(pReadIrp);
        }
    }
    else if (pReadBrb->BrbL2caAclTransfer.BufferSize < sizeof(SdpPDU)) {
        if (IsClient()) {
            CompleteClientRequest(0, STATUS_INVALID_NETWORK_RESPONSE);
        }
        else {
            USHORT transactionId;

            if (pReadBrb->BrbL2caAclTransfer.BufferSize >=
                 (sizeof(UCHAR) + sizeof(USHORT))) {

                RtlRetrieveUshort(&transactionId,
                                  (((PUCHAR) pReadBrb->BrbL2caAclTransfer.Buffer)+1));
                transactionId = RtlUshortByteSwap(transactionId);
            }
            else {
                //
                // Is there a good value for this?
                //
                transactionId = 0x00;
            }

            WriteSdpError(transactionId , SDP_ERROR_INVALID_PDU_SIZE);
        }
    }
    else {
        PUCHAR pResponse;
        SdpPDU pdu;

        pResponse = (PUCHAR) pdu.Read(pReadBrb->BrbL2caAclTransfer.Buffer);

        ULONG_PTR info = 0;
        NTSTATUS status = STATUS_SUCCESS;
        SDP_ERROR sdpError;

        if (IsClient()) {

            if (pRequestorIrp->Cancel) {
                CompleteClientRequest(0, STATUS_CANCELLED);
                return;
            }

            switch (pdu.pduId) {
            case SdpPDU_ServiceSearchResponse:
                status = OnServiceSearchResponse(&pdu, pResponse, &info);
                break;

            case SdpPDU_ServiceAttributeResponse:
                status = OnServiceAttributeResponse(&pdu, pResponse, &info);
                break;

            case SdpPDU_ServiceSearchAttributeResponse:
                status = OnServiceSearchAttributeResponse(&pdu, pResponse, &info);
                break;

            case SdpPDU_Error:
            default:
                status = STATUS_INVALID_NETWORK_RESPONSE;
                break;
            }

            if (status != STATUS_PENDING) {
                CompleteClientRequest(info, status);
            }
        }
        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);
            }
        }
    }
}
#else  // UNDER_CE

NTSTATUS SdpConnection::ReadWorkItemWorker(PUCHAR pResponse, USHORT usSize)  {
    SdpPDU pdu;
    ULONG_PTR info = 0;  // ignored by WinCE.
    NTSTATUS status = STATUS_SUCCESS;
    SDP_ERROR sdpError;

    if (usSize < sizeof(SdpPDU))  {
        if (IsClient())  {
            return ERROR_INVALID_PARAMETER;
        }
        else {
            USHORT transactionId;
            if (usSize >= sizeof(UCHAR) + sizeof(USHORT))  {
                RtlRetrieveUshort(&transactionId,pResponse+1);
                transactionId = RtlUshortByteSwap(transactionId);
            }
            else {
                transactionId = 0x00;
            }
            WriteSdpError(transactionId , SDP_ERROR_INVALID_PDU_SIZE);
        }
    }

    pResponse = (PUCHAR) pdu.Read(pResponse); 

    if (IsClient()) {
        switch (pdu.pduId) {
        case SdpPDU_ServiceSearchResponse:
            status = OnServiceSearchResponse(&pdu, pResponse, &info);
            break;

        case SdpPDU_ServiceAttributeResponse:
            status = OnServiceAttributeResponse(&pdu, pResponse, &info);
            break;

        case SdpPDU_ServiceSearchAttributeResponse:
            status = OnServiceSearchAttributeResponse(&pdu, pResponse, &info);
            break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -