static void _SendEnumPullResponse()

in Unix/wsman/wsman.c [2589:2932]


static void _SendEnumPullResponse(
    _In_    WSMAN_EnumerateContext* selfEC,
            MI_Boolean              fromRequest )
{
    WSBuf outBufHeader;
    WSBuf outBufTrailer;
    Page* responsePageCombined = 0;
    Page* responsePageHeader = 0;
    Page* responsePageTrailer = 0;
    MI_Uint32 totalSize, messagesSize = 0;
    WSMAN_ConnectionData* selfCD = selfEC->activeConnection;
    PostInstanceMsg* subsetEnd = 0;
    MI_Boolean endOfSequence = selfEC->enumerationCompleted;
    MI_Result result;
    MI_ConstString bookmarkToSend = NULL;

    DEBUG_ASSERT( NULL != selfCD );

#ifndef DISABLE_INDICATION
    /* SubscribeResponse messages should NOT contain any indications if they
     * have arrived before the SubscribeResponse message. */
    if (selfCD->wsheader.rqtAction != WSMANTAG_ACTION_SUBSCRIBE)
#endif
    {
        /* Get message subset based on envelope size/ maxElements */
        _EC_GetMessageSubset(selfEC, selfCD, &subsetEnd, &messagesSize, &bookmarkToSend);
    }

    /* validate if all mesages can be sent */
    if (endOfSequence && subsetEnd)
    {
        endOfSequence = MI_FALSE;
    }

    /* check if we can put at least one message in response */
    if (NULL != selfEC->head && subsetEnd == selfEC->head)
    {
        trace_Wsman_MaxEnvelopeIsTooSmall((int)subsetEnd->packedInstanceSize);
        _CD_SendFaultResponse(selfCD, fromRequest ? NULL : selfEC , WSBUF_FAULT_ENCODING_LIMIT, ZT("insufficient envelope size for instance transferring"));
        /* Note: leaving context 'as is' so advanced client can increase packet size and re-try */
        _EC_CloseLeft( selfEC, MI_FALSE );
        /* This also releases the context on WSMAN
         * The response should not be sent while a timer is running.
         * The timer must be stopped first */
        _EC_CheckCloseRight( selfEC );
        return;
    }

    /* Create EnumResponse */
    if (WSBuf_Init(&outBufHeader, APPROX_ENUM_RESP_ENVELOPE_SIZE) != MI_RESULT_OK)
    {
        outBufTrailer.page = 0;
        GOTO_FAILED;
    }

    if (WSBuf_Init(&outBufTrailer, 256) != MI_RESULT_OK)
        GOTO_FAILED;

    /* prepare response header */
    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
            LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse")), selfCD->wsheader.rqtMessageID))
            GOTO_FAILED;
    }
#ifndef DISABLE_INDICATION
    else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
    {
        if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
            LIT(ZT("http://schemas.xmlsoap.org/ws/2004/08/eventing/SubscribeResponse")), selfCD->wsheader.rqtMessageID))
            goto failed;
    }
#endif /* ifndef DISABLE_INDICATION */
    else
    {
        if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
            LIT(ZT("http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse")), selfCD->wsheader.rqtMessageID))
            GOTO_FAILED;

#ifndef DISABLE_INDICATION
        if (selfEC->sendBookmarks)
        {
            if (NULL == bookmarkToSend)
            {
                /* A bookmark was requested by the client, but not supplied
                 * by the provider.  Pass along the default value. */
                bookmarkToSend = ZT("http://schemas.dmtf.org/wbem/wsman/1/wsman/bookmark/earliest");  // TODO: Appropriate to do?
            }

            if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
                LIT(ZT("<wsman:Bookmark>"))))
                GOTO_FAILED;

            if (MI_RESULT_OK != WSBuf_AddString(&outBufHeader,
                bookmarkToSend))
                GOTO_FAILED;

            if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
                LIT(ZT("</wsman:Bookmark>"))))
                GOTO_FAILED;
        }
#endif
    }

    if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
        LIT(ZT("</SOAP-ENV:Header>")
        ZT("<SOAP-ENV:Body>"))))
        GOTO_FAILED;

    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(ZT("<wsen:EnumerateResponse>"))))
            GOTO_FAILED;
    }
#ifndef DISABLE_INDICATION
    else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
    {
        if (MI_RESULT_OK != _WSMAN_AddSubscribeResponse(&outBufHeader, selfEC))
            GOTO_FAILED;
    }
#endif /* ifndef DISABLE_INDICATION */
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(ZT("<wsen:PullResponse>"))))
            GOTO_FAILED;
    }

    if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
        LIT(ZT("<wsen:EnumerationContext>"))))
        GOTO_FAILED;

    if (MI_RESULT_OK != WSBuf_AddUint32(&outBufHeader,selfEC->enumerationContextID))
        GOTO_FAILED;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
        LIT(ZT("</wsen:EnumerationContext>"))))
        GOTO_FAILED;

    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(ZT("<wsman:Items>"))))
            GOTO_FAILED;
    }
#ifndef DISABLE_INDICATION
    else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
    {
    }
#endif /* ifndef DISABLE_INDICATION */
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(ZT("<wsen:Items>"))))
            GOTO_FAILED;
    }

    /* trailer */
    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(ZT("</wsman:Items>"))))
            GOTO_FAILED;
    }
#ifndef DISABLE_INDICATION
    else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
    {
    }
#endif /* ifndef DISABLE_INDICATION */
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(ZT("</wsen:Items>"))))
            GOTO_FAILED;
    }

    if (endOfSequence)
    {
        if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
        {
            if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
                LIT(ZT("<wsman:EndOfSequence/>"))))
                GOTO_FAILED;
        }
        else
        {
            if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
                LIT(ZT("<wsen:EndOfSequence/>"))))
                GOTO_FAILED;
        }
    }

    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(ZT("</wsen:EnumerateResponse>"))))
            GOTO_FAILED;
    }
#ifndef DISABLE_INDICATION
    else if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_SUBSCRIBE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(MI_T("</e:SubscribeResponse>"))))
            goto failed;
    }
#endif /* ifndef DISABLE_INDICATION */
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(ZT("</wsen:PullResponse>"))))
            GOTO_FAILED;
    }
    if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
        LIT(ZT("</SOAP-ENV:Body>")
        ZT("</SOAP-ENV:Envelope>"))))
        GOTO_FAILED;

    /* all together */
    responsePageHeader = WSBuf_StealPage(&outBufHeader);
    responsePageTrailer = WSBuf_StealPage(&outBufTrailer);

    if (!responsePageTrailer || !responsePageHeader)
        GOTO_FAILED;

    /* calculate size */
    totalSize = (MI_Uint32)(responsePageHeader->u.s.size + responsePageTrailer->u.s.size) + messagesSize;

    if (sizeof(Page) + totalSize + 1 > WSMAN_ALLOCATION_LIMIT)
    {
        trace_Wsman_Malloc_Error(sizeof(Page) + totalSize + 1);
        GOTO_FAILED;        
    }

    responsePageCombined = (Page*)PAL_Malloc(sizeof(Page) + totalSize + 1);

    if (!responsePageCombined)
        GOTO_FAILED;

    {
        char* data = (char*) (responsePageCombined + 1);
        data[totalSize] = 0;

        memcpy(data, responsePageHeader+1, responsePageHeader->u.s.size);
        data += responsePageHeader->u.s.size;

#ifndef DISABLE_INDICATION
        /* SubscribeResponse messages should NOT contain any indications if they
         * have arrived before the SubscribeResponse message. */
        if (selfCD->wsheader.rqtAction != WSMANTAG_ACTION_SUBSCRIBE)
#endif
        {
            PostInstanceMsg* msg = selfEC->head;
            while (msg != subsetEnd)
            {
                PostInstanceMsg* next = (PostInstanceMsg*)msg->base.next;

                memcpy(data, msg->packedInstancePtr, msg->packedInstanceSize);
                data += msg->packedInstanceSize;

                /* remove message from the list */
                selfEC->totalResponses--;
                selfEC->totalResponseSize -= msg->packedInstanceSize;
                List_Remove(
                    (ListElem**)&selfEC->head,
                    (ListElem**)&selfEC->tail,
                    (ListElem*)msg);
                PostInstanceMsg_Release(msg);

                msg = next;
            }
        }

        memcpy(data, responsePageTrailer+1, responsePageTrailer->u.s.size);
        data += responsePageTrailer->u.s.size;

        responsePageCombined->u.s.size = totalSize;
        responsePageCombined->u.s.next = 0;
    }

    PAL_Free(responsePageHeader); responsePageHeader = 0;
    PAL_Free(responsePageTrailer); responsePageTrailer = 0;

    if( fromRequest )
    {
        STRAND_ASSERTONSTRAND(&selfCD->strand.base);

        result = _CD_SendResponse(
            selfCD,
            HTTP_ERROR_CODE_OK,
            responsePageCombined);
    }
    else
    {
        STRAND_ASSERTONSTRAND(&selfEC->strand.base);

        result = _EC_SendResponse(
            selfEC,
            HTTP_ERROR_CODE_OK,
            responsePageCombined);
    }

    _EC_StartHeartbeatTimer( selfEC );

    goto Done;

failed:
    WSBuf_Destroy(&outBufHeader);
    WSBuf_Destroy(&outBufTrailer);
    if (responsePageCombined) PAL_Free(responsePageCombined);
    if (responsePageHeader) PAL_Free(responsePageHeader);
    if (responsePageTrailer) PAL_Free(responsePageTrailer);

    if( fromRequest )
    {
        STRAND_ASSERTONSTRAND(&selfCD->strand.base);

        // There should be no responses at this point
        DEBUG_ASSERT( NULL == selfEC->head );

        result = _CD_SendFailedResponse(selfCD);
    }
    else
    {
        STRAND_ASSERTONSTRAND(&selfEC->strand.base);

        _EC_ReleaseAllMessages(selfEC);

        result = _EC_SendResponse(
            selfEC,
            HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR,
            NULL);
    }

Done:
    if (result != MI_RESULT_OK)
    {
        DEBUG_ASSERT( MI_RESULT_OK == result );
    }

    _EC_CloseLeft( selfEC, fromRequest );

    _EC_ProcessPendingMessage( selfEC );
}