(file) Return to wsman.c CVS log (file) (dir) Up to [OMI] / omi / protocol

File: [OMI] / omi / protocol / Attic / wsman.c (download)
Revision: 1.3, Mon Jun 25 18:59:25 2012 UTC (11 years, 11 months ago) by mike
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +0 -0 lines
FILE REMOVED
1.0.2

/*
**==============================================================================
**
** Open Management Infrastructure (OMI)
**
** Copyright (c) Microsoft Corporation
** 
** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
** use this file except in compliance with the License. You may obtain a copy 
** of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
** MERCHANTABLITY OR NON-INFRINGEMENT. 
**
** See the Apache 2 License for the specific language governing permissions 
** and limitations under the License.
**
**==============================================================================
*/

#include <assert.h>
#include "wsman.h"
#include "wsbuf.h"
#include "wsmanparser.h"
#include "http.h"
#include <base/time.h>
#include <xml/xml.h>
#include <base/log.h>
#include <base/result.h>
#include <base/strings.h>
#include <base/user.h>
#include <base/io.h>
#include <base/base.h>

#include "wstags.h"

#define T MI_T
#define CR    MI_T("\n")

/*
**==============================================================================
**
** Local definitions:
**
**==============================================================================
*/
/* Maximum wsman envelope size */
#define WSMAN_MAX_ENVELOPE_SIZE     (128 * 1024)

/* aproximate repsonse header size */
#define WSMAN_APROX_ENUM_RESP_HEADER_SIZE     1024

static const MI_Uint32 _MAGIC = 0x1CF2BCB7;


/************************************************************************\
*   Local definitions
\************************************************************************/

typedef struct _WSMAN_ConnectionData    WSMAN_ConnectionData;
typedef struct _WSMAN_EnumerateContext  WSMAN_EnumerateContext;

/* These tags are used as magic numbers as well as to distinguish connection data strucutre from enumeration context */
#define DATA_TAG_CONNECTION_DATA        0x17CDDC11
#define DATA_TAG_ENUMERATION_CONTEXT    0xAB70900D

/* Maximum number of enumeration contexts stored at the same time 
    effectively limits number of concurent enumerations */
#define WSMAN_MAX_ENUM_CONTEXTS     64

struct _WSMAN
{
    MI_Uint32 magic;
    WSMANCallback callback;
    void* callbackData;
    Http* http;
    Selector* selector;

    /* configurable options */
    WSMAN_Options options;

    /* Array of enumeration contexts:
        each 'pull' will look for corresponding context
    */
    WSMAN_EnumerateContext* enumerateContexts[WSMAN_MAX_ENUM_CONTEXTS];

    /* Cached xml parser with all namespaces registered */
    XML xml;
};

/* Represents state of connection including buffers, unsent packets, states etc */
struct _WSMAN_ConnectionData
{
    /* Since message's data can point to either ConnectionData or EnumerationContext, 
        both strucutres need some generic base property - tag;
        in addition, tag used as magic number */
    MI_Uint32   tag;

    /* Link to http layer */
    void*   httpConnectionHandle;

    /* Requestor information */
    uid_t uid;
    gid_t gid;

    /* Attributes of the request */
    WSMAN_WSHeader  wsheader;
    union
    {
        /* Actual type is defined by wsheader.rqtAction field */
         WSMAN_WSEnumeratePullBody wsenumpullbody;
    }
    u;

    /* Request page (buffer for most pointers inside header/body structures) */
    Page*   page;

    /* for single-instance repsonses, we keep mesage until result received to avoid 
        conflicts with keep-alive enabled */
    PostInstanceMsg* single_message;

    /* Number of consumers of this structure: 
        connected client, outstanding request to the provider and timer */
    MI_Uint32   refcounter;

    /* response data */
    /* only valid for enumerate/pull requests */
    MI_Uint32   enumerateContextID;

    /* flag indicates that response was not sent yet to the client */
    MI_Boolean  outstandingRequest;
};

/* Enumeration context:
    'derived' from socket Handler, so it can subscribe for timeouts */

struct _WSMAN_EnumerateContext
{
    /* Since message's data can point to either ConnectionData or EnumerationContext, 
        both strucutres need some generic base property - tag;
        in addition, tag used as magic number */
    MI_Uint32   tag;

    /* based member - can be added to 'selector' for timeout support */
    Handler     base;

    /* response data */
    /* Linked list of messages to send */
    PostInstanceMsg* head;
    PostInstanceMsg* tail;

    /* Total size of all instances in response queue */
    MI_Uint32   totalResponseSize;

    /* NUmber of messages in repsonse queue */
    MI_Uint32   totalResponses;

    /* Number of consumers of this structure: 
       reference from enum-context-list in WSMAN, outstanding request to the provider and timer */
    MI_Uint32   refcounter;

    /* lower 16 bits is aninxed in self->enumerateContexts, upper 16 bits are random data (for validation) */
    MI_Uint32   enumerationContextID;
    MI_Result   finalResult;
    /* indicates that 'Result' recevied form provider and stored in finalResult */
    MI_Boolean  enumerationCompleted;
    /* Indicates that context has expired (either by timer or by Release request)
    and all repsonses form the provider has to be ignored */
    MI_Boolean  expired;

    /* pointer to current active connection - either Enumerate or Pull request */
    WSMAN_ConnectionData*   activeConnection;
};

/* forward declarations */
static void _CD_Release(
    WSMAN_ConnectionData* selfConnectionData);

static void _SendEnumPullResponse(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC);

static MI_Boolean _ProcessEnumResponse(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC,
    MI_Boolean attachingPullRequest);

static void _WSMAN_ReleaseEnumerateContext(
    WSMAN* self,
    MI_Uint32   enumerationContextID);

/************************************************************************\
*   Helper funcitons
\************************************************************************/
/* Converts Enumeration mode into "Message" struct flag */
MI_INLINE   MI_Uint32 _convertWSMANtoMsgEnumerationMode(
    MI_Uint32 enumerationMode )
{
    if (WSMANTAG_ENUM_MODE_EPR == enumerationMode)
        return WSMAN_EPRFlag;

    if (WSMANTAG_ENUM_MODE_OBJECT_AND_EPR == enumerationMode)
        return WSMAN_ObjectAndEPRFlag;

    return WSMAN_ObjectFlag;
}

/************************************************************************\
*   Enumeration Context operations
\************************************************************************/
static void _EC_ReleaseAllMessages(
    WSMAN_EnumerateContext* self)
{
    /* Delete all queued messages*/
    while (self->head)
    {
        PostInstanceMsg* msg = self->head;

        List_Remove(
            (ListElem**)&self->head, 
            (ListElem**)&self->tail, 
            (ListElem*)msg);
        PostInstanceMsg_Release(msg);
    }
    self->totalResponses = 0;
    self->totalResponseSize = 0;
}

static void _EC_SetActiveConnection(
    WSMAN_EnumerateContext* self,
    WSMAN_ConnectionData* selfCD)
{
    if (self->activeConnection)
        _CD_Release(self->activeConnection);

    self->activeConnection = selfCD;
    if (self->activeConnection)
    {
        self->activeConnection->refcounter++;
        self->activeConnection->enumerateContextID = self->enumerationContextID;
    }
}

static void _EC_Release(
    WSMAN_EnumerateContext* self,
    MI_Boolean freeAllMessages)
{
    if (--self->refcounter == 0)
    {
        /* Delete all queued messages*/
        _EC_ReleaseAllMessages(self);

        /* release active connection (if exist) */
        _EC_SetActiveConnection(self, 0);

#ifdef CONFIG_ENABLE_DEBUG
        /* invalidate struct */
        memset(self, 0xcd, sizeof(*self));
#endif
        free(self);
    }
    else if (freeAllMessages)
    {
        /* Delete all queued messages*/
        _EC_ReleaseAllMessages(self);
    }
}

static MI_Boolean _EC_TimeoutCallback(
    Selector* sel,
    Handler* handler,
    MI_Uint32 mask, 
    MI_Uint64 currentTimeUsec)
{
    /* since 'base' is not the first member in EC struct,
        adjust pointer as appropriate */
    WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)
        (((char*)handler) - offsetof(WSMAN_EnumerateContext, base));

    MI_UNUSED(sel);
    MI_UNUSED(currentTimeUsec);

    if (mask & SELECTOR_TIMEOUT)
    {
        /* remove context only from wsman list; selector will remove it automatically, 
            once 'false' returned */
        _WSMAN_ReleaseEnumerateContext(
            (WSMAN*)self->base.data, self->enumerationContextID);

        /* once 'false' returned, selector will remove handler,
            so actual handling happens in next 'if' */
        return MI_FALSE;
    }

    if (mask & (SELECTOR_REMOVE | SELECTOR_DESTROY))
    {
        _EC_Release(self, MI_TRUE);
    }

    return MI_TRUE;
}

/************************************************************************\
*   WSman operations
\************************************************************************/
static WSMAN_EnumerateContext* _WSMAN_AllocateEnumContext(
    WSMAN* self)
{
    MI_Uint32   enumerationContextID;
    WSMAN_EnumerateContext* enumContext;

    /* Find empty slot */
    for (enumerationContextID = 0; enumerationContextID < MI_COUNT(self->enumerateContexts); enumerationContextID++)
    {
        if (!self->enumerateContexts[enumerationContextID])
            break;
    }

    if (MI_COUNT(self->enumerateContexts) == enumerationContextID)
    {
        LOGW((T("Cannot allocate new enumerate context - too many concurrent enumerations") ));
        return 0;   /* no more slots available */
    }

    enumContext = (WSMAN_EnumerateContext*)calloc(1, sizeof(WSMAN_EnumerateContext));

    if (!enumContext)
        return 0;

    /* Store reference to a new context */
    self->enumerateContexts[enumerationContextID] = enumContext;

    /* set tag/magic */
    enumContext->tag = DATA_TAG_ENUMERATION_CONTEXT;

    /* Add random data to the context-id */
    enumerationContextID |= (rand() & 0xFFFF) << 16;
    enumContext->enumerationContextID = enumerationContextID;

    /* set ref-counter to 1, since it's referred by enumerateContexts array now */
    enumContext->refcounter = 1;
    return enumContext;
}

static WSMAN_EnumerateContext* _WSMAN_FindEnumContext(
    WSMAN* self,
    MI_Uint32   enumerationContextID)
{
    MI_Uint32 index = enumerationContextID & 0xFFFF;

    /* ATTN: add logging here! */
    /* verify that context exist and has the same id as required */
    if (index < MI_COUNT(self->enumerateContexts) &&
        self->enumerateContexts[index] &&
        self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
        return self->enumerateContexts[index];

    return 0;
}


static void _WSMAN_ReleaseEnumerateContext(
    WSMAN* self,
    MI_Uint32   enumerationContextID)
{
    MI_Uint32 index = enumerationContextID & 0xFFFF;

    if (index < MI_COUNT(self->enumerateContexts) &&
        self->enumerateContexts[index] &&
        self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
    {
        /* mark handler for removing:
            we cannot remove it directly since we are inside selector's callback;
            settign time to current will trigger timeout/context removal */
        MI_Uint64 currentTimeUsec = 0;

        Time_Now(&currentTimeUsec);
        self->enumerateContexts[index]->base.fireTimeoutAt = currentTimeUsec;
        self->enumerateContexts[index]->expired = MI_TRUE;

        /* dec-ref context: note: it can still be alive if porvider has outstanding request */
        _EC_Release(self->enumerateContexts[index], MI_FALSE);
        self->enumerateContexts[index] = 0;
    }
}

static void _WSMAN_ReleaseAllEnumerateContexts(
    WSMAN* self)
{
    MI_Uint32 index;

    for (index = 0; index < MI_COUNT(self->enumerateContexts); index++ )
    {
        if (self->enumerateContexts[index])
        {
            /* delete timer if was set */
            Selector_RemoveHandler(self->selector, &self->enumerateContexts[index]->base);

            /* dec-ref context: note: it can still be alive if porvider has outstanding request */
            _EC_Release(self->enumerateContexts[index], MI_FALSE);
            self->enumerateContexts[index] = 0;
        }
    }
}

static void _WSMAN_SetUpdateTimer(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC)
{
    /* check if timer was already added */
    if (!selfEC->base.fireTimeoutAt)
    {
        /* add timer - first time called */
        selfEC->base.sock = INVALID_SOCK;
        selfEC->base.data = self;
        selfEC->base.callback = _EC_TimeoutCallback;

        /* increment counter - will be decremented in callback/remove */
        if (MI_RESULT_OK == Selector_AddHandler(self->selector, &selfEC->base))
            selfEC->refcounter++;
    }

    /* extend time */
    {
        MI_Uint64 currentTimeUsec = 0;

        if (MI_RESULT_OK == Time_Now(&currentTimeUsec))
        {
            selfEC->base.fireTimeoutAt = 
                currentTimeUsec + self->options.timeoutEnumContextUsec;
        }
    }
}

/************************************************************************\
*   connection data operations
\************************************************************************/
MI_INLINE void _CD_SetPage(
    WSMAN_ConnectionData* selfConnectionData,
    Page*   page)
{
    if (selfConnectionData->page)
        free(selfConnectionData->page);

    selfConnectionData->page = page;
}

MI_INLINE void _CD_SetSingleMessage(
    WSMAN_ConnectionData* selfConnectionData,
    PostInstanceMsg* single_message)
{
    if (selfConnectionData->single_message)
        PostInstanceMsg_Release(selfConnectionData->single_message);

    selfConnectionData->single_message = single_message;

    if (selfConnectionData->single_message)
        Message_AddRef(&selfConnectionData->single_message->base);
}

static void _CD_Cleanup(
    WSMAN_ConnectionData* selfConnectionData)
{
    _CD_SetPage(selfConnectionData, 0);
    _CD_SetSingleMessage(selfConnectionData, 0);

    /* free allocated instance/batch */
    if (selfConnectionData->wsheader.instanceBatch)
    {
        /* destroying batch takes care of instance and instanceBatch members */
        Batch_Destroy(selfConnectionData->wsheader.instanceBatch);
        selfConnectionData->wsheader.instanceBatch = 0;
        selfConnectionData->wsheader.instance = 0;
    }
    memset(&selfConnectionData->wsheader, 0, sizeof(selfConnectionData->wsheader));
}

static void _CD_Release(
    WSMAN_ConnectionData* selfConnectionData)
{
    if (--selfConnectionData->refcounter == 0)
    {
        _CD_Cleanup(selfConnectionData);

        free(selfConnectionData);
    }
}


static void _SendFaultResponse(
    Http* http,
    WSMAN_ConnectionData* selfCD,
    WSBUF_FAULT_CODE faultCode,
    const MI_Char* descriptionText)
{
    Page* responsePage = WSBuf_CreateFaultResponsePage(
        faultCode,
        selfCD->wsheader.unknownMandatoryTag,
        selfCD->wsheader.rqtMessageID,
        descriptionText);
        
    //printf("\n\n%s\n\n", (char*)(responsePage+1));

    Http_SendResponse(http, selfCD->httpConnectionHandle,
        HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR, 
        &responsePage);

    selfCD->outstandingRequest = MI_FALSE;

    if (responsePage)
        free(responsePage);
}

static void _SendReleaseResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    Page* responsePage = WSBuf_CreateReleaseResponsePage(
        selfCD->wsheader.rqtMessageID);
        
    //printf("\n\n%s\n\n", (char*)(responsePage+1));

    Http_SendResponse(self->http, selfCD->httpConnectionHandle,
        HTTP_ERROR_CODE_OK, 
        &responsePage);

    selfCD->outstandingRequest = MI_FALSE;

    if (responsePage)
        free(responsePage);
}



static int _ValidateHeader(
    Http* http,
    WSMAN_ConnectionData* selfCD)
{
    if (selfCD->wsheader.unknownMandatoryTag)
    {
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_UNDERSTOOD, 0);
        return -1;
    }

    //DSP0226
    //1756 R6.2-4: Services should reject any MaxEnvelopeSize value less than 8192 octets. This number
    //1757 is the safe minimum in which faults can be reliably encoded for all character sets. If the requested
    //1758 size is less than this, the service should return a wsman:EncodingLimit fault with the following
    //1759 detail code:
    //1760 http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/MinimumEnvelopeLimit

    if (selfCD->wsheader.maxEnvelopeSize != 0 &&
        selfCD->wsheader.maxEnvelopeSize < 8192)
    {
        LOGW_CHAR(("wsman: requested envelope size (%d) is too small; "
            "expected at least 8K", (int)selfCD->wsheader.maxEnvelopeSize));

        _SendFaultResponse(http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, 0);
        return -1;
    }

    /* Limit envelope size to server's max */
    if (selfCD->wsheader.maxEnvelopeSize == 0 ||
        selfCD->wsheader.maxEnvelopeSize > WSMAN_MAX_ENVELOPE_SIZE)
    {
        selfCD->wsheader.maxEnvelopeSize = WSMAN_MAX_ENVELOPE_SIZE;
    }

    /* verify action for invoke */
    if (selfCD->wsheader.foundAction &&
        0 == selfCD->wsheader.rqtAction &&
        (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtMethod))
    {
        LOGW_CHAR(("wsman: unknown custom action"));

        _SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_SUPPORTED, 
            T("unknown custom action"));
        return -1;
    }

    return 0;
}

static int _ValidateEnumerateRequest(
    Http* http,
    WSMAN_ConnectionData* selfCD)
{
    /* If it has reference params, it must be an association request */
    MI_Instance* referenceParameters = 
        selfCD->u.wsenumpullbody.associationFilter.referenceParameters;

    if (referenceParameters)
    {
        selfCD->wsheader.rqtNamespace = referenceParameters->nameSpace;
        selfCD->wsheader.rqtClassname = referenceParameters->classDecl->name;
    }
    else if (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtNamespace)
    {
        LOGW_CHAR(("wsman: mandatory parameters (className, namespace) "
            "are missing for enumerate request"));

        _SendFaultResponse(
            http, 
            selfCD, 
            WSBUF_FAULT_INTERNAL_ERROR, 
            T("mandatory parameters (className, namespace) "
                "are missing for enumerate request"));
        return -1;
    }

    //R8.2.3; DSP226
    //wsmen:Enumerate/wsman:MaxElements
    //(optional) indicates the maximum number of items the consumer is willing to accept in the
    //EnumerateResponse
    //It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
    //implied value is 1.
    if (!selfCD->u.wsenumpullbody.maxElements)
        selfCD->u.wsenumpullbody.maxElements = 1;

    // if enumeration mode is not specified, use 'Objects'
    if (selfCD->u.wsenumpullbody.enumerationMode == 0)
        selfCD->u.wsenumpullbody.enumerationMode = WSMANTAG_ENUM_MODE_OBJECT;

    return 0;
}

static int _ValidatePullRequest(
    Http* http,
    WSMAN_ConnectionData* selfCD)
{
    MI_UNUSED(http);
    //R8.2.3; DSP226
    //wsmen:Enumerate/wsman:MaxElements
    //(optional) indicates the maximum number of items the consumer is willing to accept in the
    //EnumerateResponse
    //It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
    //implied value is 1.
    if (!selfCD->u.wsenumpullbody.maxElements)
        selfCD->u.wsenumpullbody.maxElements = 1;

    return 0;
}

static void _ProcessEnumerateRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    EnumerateInstancesReq* msg;
    WSMAN_EnumerateContext* enumContext;

    /* create EnumerateContext */
    enumContext = _WSMAN_AllocateEnumContext(self);

    if (!enumContext)
    {
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* link new context to current EnumRequest */
    _EC_SetActiveConnection(enumContext, selfCD);


    // Create new request.
    msg = EnumerateInstancesReq_New(/*_NextMsgID()*/ 1, 
        WSMANFlag | _convertWSMANtoMsgEnumerationMode(selfCD->u.wsenumpullbody.enumerationMode));

    if (!msg)
    {
        _WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
        selfCD->enumerateContextID = 0;
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* In case when client does not support optimized enumeration,
        send empty Enum-response with correct enumerate context */
    if (!selfCD->u.wsenumpullbody.allowOptimization)
    {   
        _SendEnumPullResponse(self, enumContext);
        _EC_SetActiveConnection(enumContext, 0);
        _WSMAN_SetUpdateTimer(self, enumContext);
    }

    msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
    msg->className = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtClassname);
    msg->deepInheritance = (selfCD->u.wsenumpullbody.polymorphismMode != WSMANTAG_ENUM_POLYMORPHISM_MODE_NONE);
    msg->basePropertiesOnly = (selfCD->u.wsenumpullbody.polymorphismMode == WSMANTAG_ENUM_POLYMORPHISM_MODE_EXCLUDE_PROPS);

    /* Set the query related fields */
    {
        if (selfCD->u.wsenumpullbody.dialect)
            msg->queryLanguage = Batch_Strdup2(msg->base.batch, selfCD->u.wsenumpullbody.dialect);

        if (selfCD->u.wsenumpullbody.filter)
            msg->queryExpression = Batch_Strdup2(msg->base.batch, selfCD->u.wsenumpullbody.filter);
    }

    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* attach client id */
    msg->base.clientID = PtrToUint64(enumContext);

    /* increment counter to keep it alive until provider replies */
    enumContext->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    EnumerateInstancesReq_Release(msg);
}

static void _ProcessAssociatorsRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    AssociatorsOfReq* msg;
    WSMAN_EnumerateContext* enumContext;
    MI_Uint32 enumerationMode;


    /* create EnumerateContext */
    enumContext = _WSMAN_AllocateEnumContext(self);

    if (!enumContext)
    {
        Http_SendErrorResponse(
            http, 
            httpConnectionHandle, 
            HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* link new context to current EnumRequest */
    _EC_SetActiveConnection(enumContext, selfCD);

    /* Extract teh enumeration mode */
    enumerationMode = _convertWSMANtoMsgEnumerationMode(
        selfCD->u.wsenumpullbody.enumerationMode);

    /* Create new request. */
    msg = AssociatorsOfReq_New(
        /*_NextMsgID()*/ 1, 
        WSMANFlag | enumerationMode);

    if (!msg)
    {
        _WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
        selfCD->enumerateContextID = 0;
        Http_SendErrorResponse(
            http, 
            httpConnectionHandle, 
            HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* In case when client does not support optimized enumeration,
     *  send empty Enum-response with correct enumerate context 
     */
    if (!selfCD->u.wsenumpullbody.allowOptimization)
    {
        _SendEnumPullResponse(self, enumContext);
        _EC_SetActiveConnection(enumContext, 0);
        _WSMAN_SetUpdateTimer(self, enumContext);
    }

    msg->nameSpace = Batch_Strdup2(
        msg->base.batch, 
        selfCD->wsheader.rqtNamespace);

    msg->className = Batch_Strdup2(
        msg->base.batch, 
        selfCD->wsheader.rqtClassname);

    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* Set messages fileds from association filter */
    {
        WSMAN_AssociationFilter* filter = 
            &selfCD->u.wsenumpullbody.associationFilter;

        msg->instance = filter->referenceParameters;
        msg->assocClass = filter->associationClassName;
        msg->resultClass = filter->resultClassName;
        msg->role = filter->role;
        msg->resultRole = filter->resultRole;
    }

    /* attach client id */
    msg->base.clientID = PtrToUint64(enumContext);

    /* increment counter to keep it alive until provider replies */
    enumContext->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    AssociatorsOfReq_Release(msg);
}

static void _ProcessPullRequest(
    Http* http,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    WSMAN_EnumerateContext* enumContext;

    /* find EnumerateContext */
    enumContext = _WSMAN_FindEnumContext(self, selfCD->u.wsenumpullbody.enumerationContextID);

    if (!enumContext)
    {
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_DESTINATION_UNREACHABLE, T("Enumeration context not found"));
        return;
    }

    /* link new context to the request */
    _EC_SetActiveConnection(enumContext, selfCD);

    _ProcessEnumResponse(self, enumContext, MI_TRUE);

}

static void _ProcessReleaseRequest(
    Http* http,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    WSMAN_EnumerateContext* enumContext;

    /* find EnumerateContext */
    enumContext = _WSMAN_FindEnumContext(self, selfCD->u.wsenumpullbody.enumerationContextID);

    if (!enumContext)
    {
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_DESTINATION_UNREACHABLE, T("Enumeration context not found"));
        return;
    }

    /* Remove context from the list */
    _WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);

    _SendReleaseResponse(self, selfCD);
}

static void _ParseValidateProcessEnumerateRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    /* ATTN: only used if enumeration contains an association filter. Find
     * some way to prevent creation in that case.
     */

    if (!selfCD->wsheader.instanceBatch)
    {
        selfCD->wsheader.instanceBatch = Batch_New(BATCH_MAX_PAGES);
    }

    /* Parse enumerate request/body */
    if (WS_ParseEnumerateBody(
        xml, 
        &selfCD->wsheader.instanceBatch, 
        &selfCD->u.wsenumpullbody) != 0)
    {
        LOGW_CHAR(("wsman: unable to parse incoming xml/ enumerate request body"));
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* Validate enumerate request body */
    if (_ValidateEnumerateRequest(http, selfCD) != 0)
    {
        /* appropriate error code was already sent to the client */
        return;
    }

    /* Process reqest */

    if (selfCD->u.wsenumpullbody.foundAssociationFilter)
    {
        _ProcessAssociatorsRequest(http,httpConnectionHandle,self,selfCD);
    }
    else
    {
        _ProcessEnumerateRequest(http,httpConnectionHandle,self,selfCD);
    }
}

static void _ParseValidateProcessInvokeRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    InvokeReq* msg = 0;

    /* if instance was created from batch, re-use exisintg batch to allocate message */
    if (selfCD->wsheader.instanceBatch)
    {
        /* Allocate heap space for message */
        msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(InvokeReq));

        if (!msg)
            goto failed;

        /* Set the tag */
        msg->base.tag = InvokeReqTag;

        /* Set the message id and flags */
        msg->base.msgID = 1;
        msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;

        /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
        msg->base.refCounter = 1;

        /* Copy batch onto message (released by delete method) */
        msg->base.batch = selfCD->wsheader.instanceBatch;

        msg->instance = selfCD->wsheader.instance;
        selfCD->wsheader.instanceBatch = 0;
        selfCD->wsheader.instance = 0;
    }
    else
        msg = InvokeReq_New(1, WSMANFlag | WSMAN_ObjectFlag);

    if (!msg)
        goto failed;

    /* Parse invoke request/body */
    if (WS_ParseInvokeBody(xml, msg->base.batch, &msg->instanceParams) != 0)
        goto failed;

    /* Extract/set relevant parameters */
    if (selfCD->wsheader.rqtNamespace)
        msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);

    msg->className = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtClassname);
    msg->function = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtMethod);

    /* attach client id */
    msg->base.clientID = PtrToUint64(selfCD);
    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* increment counter to keep it alive until provider replies */
    selfCD->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    InvokeReq_Release(msg);
    return;

failed:
    LOGW_CHAR(("wsman: unable to process invoke request"));
    Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;

    if (msg)
        InvokeReq_Release(msg);
}

static void _ParseValidateProcessGetRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    GetInstanceReq* msg = 0;

    MI_UNUSED(xml);

    /* Check if instance name parameter was specified */
    if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
    {
        LOGW_CHAR(("wsman: get-instance: instance name parameter is missing"));
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("get-instance: instance name parameter is missing"));

        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* if instance was created from batch, re-use exisintg batch to allocate message */
    /* Allocate heap space for message */
    msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(GetInstanceReq));

    if (!msg)
        goto failed;

    /* Set the tag */
    msg->base.tag = GetInstanceReqTag;

    /* Set the message id and flags */
    msg->base.msgID = 1;
    msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;

    /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
    msg->base.refCounter = 1;

    /* Copy batch into message (released by delete method) */
    msg->base.batch = selfCD->wsheader.instanceBatch;

    msg->instanceName = selfCD->wsheader.instance;

    /* clear batch/instance fields in header structure */
    selfCD->wsheader.instanceBatch = 0;
    selfCD->wsheader.instance = 0;

    /* Skip parsing get-request/body - assumed to be empty */

    /* Extract/set relevant parameters */
    if (selfCD->wsheader.rqtNamespace)
        msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);

    /* attach client id */
    msg->base.clientID = PtrToUint64(selfCD);
    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* increment counter to keep it alive until provider replies */
    selfCD->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    GetInstanceReq_Release(msg);
    return;

failed:
    LOGW_CHAR(("wsman: unable to process get-instance request"));
    Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;

    if (msg)
        GetInstanceReq_Release(msg);
}

static void _ParseValidateProcessPutRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    ModifyInstanceReq* msg = 0;

    MI_UNUSED(xml);

    /* Check if instance name parameter was specified */
    if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
    {
        LOGW_CHAR(("wsman: Put-instance: instance name parameter is missing"));
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("Put-instance: instance name parameter is missing"));

        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* if instance was created from batch, re-use exisintg batch to allocate message */
    /* Allocate heap space for message */
    msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(ModifyInstanceReq));

    if (!msg)
        goto failed;

    /* Set the tag */
    msg->base.tag = ModifyInstanceReqTag;

    /* Set the message id and flags */
    msg->base.msgID = 1;
    msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;

    /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
    msg->base.refCounter = 1;

    /* Copy batch into message (released by delete method) */
    msg->base.batch = selfCD->wsheader.instanceBatch;
    msg->instance = selfCD->wsheader.instance;

    /* clear batch/instance fields in header structure */
    selfCD->wsheader.instanceBatch = 0;
    selfCD->wsheader.instance = 0;

    /* re-use 'create' parser to parse 'Modify' request/body */
    if (WS_ParseCreateBody(xml, msg->base.batch, &msg->instance) != 0)
        goto failed;

    /* Extract/set relevant parameters */
    if (selfCD->wsheader.rqtNamespace)
        msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);

    /* attach client id */
    msg->base.clientID = PtrToUint64(selfCD);
    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* increment counter to keep it alive until provider replies */
    selfCD->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    ModifyInstanceReq_Release(msg);
    return;

failed:
    LOGW_CHAR(("wsman: unable to process Put-instance request"));
    Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;

    if (msg)
        ModifyInstanceReq_Release(msg);
}

static void _ParseValidateProcessDeleteRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    DeleteInstanceReq* msg = 0;

    MI_UNUSED(xml);

    /* Check if instance name parameter was specified */
    if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
    {
        LOGW_CHAR(("wsman: delete-instance: instance name parameter is missing"));
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("delete-instance: instance name parameter is missing"));

        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* if instance was created from batch, re-use exisintg batch to allocate message */
    /* Allocate heap space for message */
    msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(DeleteInstanceReq));

    if (!msg)
        goto failed;

    /* Set the tag */
    msg->base.tag = DeleteInstanceReqTag;

    /* Set the message id and flags */
    msg->base.msgID = 1;
    msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;

    /* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
    msg->base.refCounter = 1;

    /* Copy batch into message (released by delete method) */
    msg->base.batch = selfCD->wsheader.instanceBatch;

    msg->instanceName = selfCD->wsheader.instance;

    /* clear batch/instance fields in header structure */
    selfCD->wsheader.instanceBatch = 0;
    selfCD->wsheader.instance = 0;

    /* Skip parsing Delete-request/body - assumed to be empty */

    /* Extract/set relevant parameters */
    if (selfCD->wsheader.rqtNamespace)
        msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);

    /* attach client id */
    msg->base.clientID = PtrToUint64(selfCD);
    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* increment counter to keep it alive until provider replies */
    selfCD->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    DeleteInstanceReq_Release(msg);
    return;

failed:
    LOGW_CHAR(("wsman: unable to process delete-instance request"));
    Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;

    if (msg)
        DeleteInstanceReq_Release(msg);
}

static void _ParseValidateProcessCreateRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    CreateInstanceReq* msg = 0;

     msg = CreateInstanceReq_New(1, WSMANFlag | WSMAN_CreatedEPRFlag);

    if (!msg)
        goto failed;

    /* Parse create request/body */
    if (WS_ParseCreateBody(xml, msg->base.batch, &msg->instance) != 0)
        goto failed;

    /* Extract/set relevant parameters */
    if (selfCD->wsheader.rqtNamespace)
        msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);

    /* attach client id */
    msg->base.clientID = PtrToUint64(selfCD);
    msg->base.uid = selfCD->uid;
    msg->base.gid = selfCD->gid;

    /* increment counter to keep it alive until provider replies */
    selfCD->refcounter++;

    (*self->callback)(self, &msg->base, self->callbackData);

    CreateInstanceReq_Release(msg);
    return;

failed:
    LOGW_CHAR(("wsman: unable to process Create request"));
    Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;

    if (msg)
        CreateInstanceReq_Release(msg);
}

static void _ParseValidateProcessPullRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    /* Parse pull request/body */
    if (WS_ParsePullBody(xml, &selfCD->u.wsenumpullbody) != 0)
    {
        LOGW_CHAR(("wsman: unable to parse incoming xml/ Pull request body"));
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* Validate enumerate request body */
    if (_ValidatePullRequest(http, selfCD) != 0)
    {
        /* appropriate error code was already sent to the client */
        return;
    }

    /* Process reqest */
    _ProcessPullRequest(http,self,selfCD);
}

static void _ParseValidateProcessReleaseRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML*    xml)
{
    /* Parse pull request/body */
    if (WS_ParseReleaseBody(xml, &selfCD->u.wsenumpullbody) != 0)
    {
        LOGW_CHAR(("wsman: unable to parse incoming xml/ Release request body"));
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    /* Validate enumerate request body */
    /* no validation needed */

    /* Process reqest */
    _ProcessReleaseRequest(http,self,selfCD);
}

static void _SendIdentifyResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    WSBuf out;
    Page* responsePage = 0;
#   define MSG \
    "<soap:Envelope " \
    "xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " \
    "xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\">" CR \
    "<soap:Header/>" CR \
    "<soap:Body>" CR \
    "<soap:IdentifyResponse>" CR \
    "<wsmid:ProtocolVersion>" \
      "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" \
    "</wsmid:ProtocolVersion>" CR \
    "<wsmid:ProductVendor>" \
      CONFIG_FULLPRODUCT \
    "</wsmid:ProductVendor>" CR \
    "<wsmid:ProductVersion>" \
      CONFIG_VERSION \
    "</wsmid:ProductVersion>" CR \
    "<wsmid:SecurityProfiles>" CR \
    "<wsmid:SecurityProfileName>" \
    "http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/https/basic" \
    "</wsmid:SecurityProfileName>" CR \
    "</wsmid:SecurityProfiles>" CR \
    "</soap:IdentifyResponse>" CR \
    "</soap:Body>" CR \
    "</soap:Envelope>" CR

    if (WSBuf_Init(&out, 1024) != MI_RESULT_OK)
    {
        goto failed;
    }

    if (WSBuf_AddLit(&out, LIT(MSG)) != MI_RESULT_OK)
    {
        goto failed;
    }

    responsePage = WSBuf_StealPage(&out);

    if (!responsePage)
        goto failed;

    if (self->options.enableTracing)
    {
        printf("%s\n\n", (char*)(responsePage+1));
    }

    Http_SendResponse(
        self->http, 
        selfCD->httpConnectionHandle, 
        HTTP_ERROR_CODE_OK, 
        &responsePage);

    selfCD->outstandingRequest = MI_FALSE;

    if (responsePage)
        free(responsePage);

    return;

failed:
    WSBuf_Destroy(&out);
    Http_SendErrorResponse(
        self->http, 
        selfCD->httpConnectionHandle, 
        HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;
}

static void _HandleIdentifyRequest(
    Http* http,
    void* httpConnectionHandle,
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    XML* xml)
{
    /* Parse pull request/body */
    if (WS_ParseIdentifyBody(xml) != 0)
    {
        LOGW_CHAR(("wsman: found neither Action or Identify"));
        Http_SendErrorResponse(http, httpConnectionHandle, 
            HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        selfCD->outstandingRequest = MI_FALSE;
        return;
    }

    _SendIdentifyResponse(self, selfCD);
}

/************************************************************************\
*   Dispatcher calls processing
\************************************************************************/

static void _EC_GetMessageSubset(
    WSMAN_EnumerateContext* selfEC,
    WSMAN_ConnectionData* selfCD,
    PostInstanceMsg** subsetEnd,
    MI_Uint32*  totalSize)
{
    MI_Uint32 count = 0;
    *totalSize = 0;
    *subsetEnd = selfEC->head;

    while (*subsetEnd)
    {
        if (count + 1 > selfCD->u.wsenumpullbody.maxElements ||
            (*totalSize) + (*subsetEnd)->packedInstanceSize + WSMAN_APROX_ENUM_RESP_HEADER_SIZE > selfCD->wsheader.maxEnvelopeSize)
            break;

        (*totalSize) += (*subsetEnd)->packedInstanceSize;
        count++;
        (*subsetEnd) = (PostInstanceMsg*)(*subsetEnd)->base.next;
    }
}

/* Sends as many instances as posisble (based on envelope-size and instance counter) */
static void _SendEnumPullResponse(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC)
{
    WSBuf   outBufHeader, 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;


    /* Get message subset based on envelope size/ maxElements */
    _EC_GetMessageSubset(selfEC, selfCD, &subsetEnd, &messagesSize);

    /* 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)
    {
        LOGW_CHAR(("wsman: max-envelope is too small even for one message; message size %d", 
            (int)subsetEnd->packedInstanceSize ));
        _SendFaultResponse(self->http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, T("insufficient envelope size for instance transferring"));
        /* Note: leaving context 'as is' so advanced client can increase packet size and re-try */
        return;
    }

    /* Create EnumResponse */
    if (WSBuf_Init(&outBufHeader, WSMAN_APROX_ENUM_RESP_HEADER_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(T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse")), selfCD->wsheader.rqtMessageID))
            goto failed;
    }
    else
    {
        if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
            LIT(T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse")), selfCD->wsheader.rqtMessageID))
            goto failed;
    }

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

    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(T("<wsen:EnumerateResponse>"))))
            goto failed;
    }
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(T("<wsen:PullResponse>"))))
            goto failed;
    }

    if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
        LIT(T("<wsen:EnumerationContext>"))))
        goto failed;

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

    if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
        LIT(T("</wsen:EnumerationContext>"))))
        goto failed;

    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(T("<wsman:Items>"))))
            goto failed;
    }
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
            LIT(T("<wsen:Items>"))))
            goto failed;
    }



    /* trailer */
    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(T("</wsman:Items>"))))
            goto failed;
    }
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(T("</wsen:Items>"))))
            goto failed;
    }

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

    if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(T("</wsen:EnumerateResponse>"))))
            goto failed;
    }
    else
    {
        if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
            LIT(T("</wsen:PullResponse>"))))
            goto failed;
    }
    if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
        LIT(T("</SOAP-ENV:Body>")
        T("</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;

    responsePageCombined = (Page*)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;

        {
            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;
    }

    free(responsePageHeader); responsePageHeader = 0;
    free(responsePageTrailer); responsePageTrailer = 0;

    /* Trace the response XML */

    if (self->options.enableTracing)
    {
        printf("%s\n\n", (char*)(responsePageCombined+1));
    }

    /*{
        FILE* f = Fopen("out_test.xml", "a");
        fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
        fclose(f);
    }*/

    Http_SendResponse(
        self->http, 
        selfCD->httpConnectionHandle, 
        HTTP_ERROR_CODE_OK, 
        &responsePageCombined);

    selfCD->outstandingRequest = MI_FALSE;

    if (responsePageCombined)
        free(responsePageCombined);

    return;

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

    _EC_ReleaseAllMessages(selfEC);
    Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
    selfCD->outstandingRequest = MI_FALSE;
}

static void _SendInvokeResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    PostInstanceMsg* message)
{
    WSBuf   outBuf;
    Page*       responsePage = 0;
    MI_Char*    action = 0;
    MI_Uint32   actionLen;

    /* create action */
    actionLen = (MI_Uint32)(7 /* http:// */ +
        27 /* "/wbem/wscim/1/cim-schema/2/" */ +
        1 /* / between cn/meth */ +
        1 /* \0 at the end */ +
        strlen(selfCD->wsheader.rqtServer) +
        strlen(selfCD->wsheader.rqtClassname) +
        strlen(selfCD->wsheader.rqtMethod));

    action = (MI_Char*)malloc(actionLen * sizeof(MI_Char));

    if (!action)
        goto failed;

#if (MI_CHAR_TYPE == 1)
    //Snprintf(action, actionLen, T("http://%s/wbem/wscim/1/cim-schema/2/%s/%s"),
    //    selfCD->wsheader.rqtServer, selfCD->wsheader.rqtClassname, selfCD->wsheader.rqtMethod);
    {
        MI_Uint32 size;
        action[0] = 0;
        size = Strlcat(action, "http://", actionLen);
        size += Strlcat(action + size, selfCD->wsheader.rqtServer, actionLen - size);
        size += Strlcat(action + size, "/wbem/wscim/1/cim-schema/2/", actionLen - size);
        size += Strlcat(action + size, selfCD->wsheader.rqtClassname, actionLen - size);
        size += Strlcat(action + size, "/", actionLen - size);
        size += Strlcat(action + size, selfCD->wsheader.rqtMethod, actionLen - size);

        assert(size == (actionLen-1));
    }
#else
    Szprintf(action, actionLen, T("http://%S/wbem/wscim/1/cim-schema/2/%S/%S"),
        selfCD->wsheader.rqtServer, selfCD->wsheader.rqtClassname, selfCD->wsheader.rqtMethod);
#endif

    actionLen--;

    /* Create EnumResponse */
    if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
        goto failed;

    /* prepare response header */
    if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
        action, actionLen, selfCD->wsheader.rqtMessageID))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(T("</SOAP-ENV:Header>")
        T("<SOAP-ENV:Body>")
        T("<n1:ExecuteCommand_OUTPUT xmlns:n1=\"")
        )))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        action, actionLen))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(T("\">"))))
        goto failed;


    if (MI_RESULT_OK != WSBuf_AddCharLit(&outBuf,
        message->packedInstancePtr, message->packedInstanceSize))
        goto failed;

    /* trailer */
    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(
        T("</n1:ExecuteCommand_OUTPUT>")
        T("</SOAP-ENV:Body>")
        T("</SOAP-ENV:Envelope>"))))
        goto failed;

    /* all together */
    responsePage = WSBuf_StealPage(&outBuf);

    if (!responsePage)
        goto failed;

    /* Trace the response XML */

    if (self->options.enableTracing)
    {
        printf("%s\n\n", (char*)(responsePage+1));
    }

    /*{
        FILE* f = Fopen("out_test.xml", "a");
        fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
        fclose(f);
    }*/

    Http_SendResponse(
        self->http, 
        selfCD->httpConnectionHandle, 
        HTTP_ERROR_CODE_OK, 
        &responsePage);

    /* indicate that response was sent */
    selfCD->outstandingRequest = MI_FALSE;

    if (responsePage)
        free(responsePage);

    if (action) 
        free(action);

    return;

failed:
    WSBuf_Destroy(&outBuf);
    if (responsePage) free(responsePage);
    if (action) free(action);

    Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);

    /* indicate that response was sent */
    selfCD->outstandingRequest = MI_FALSE;
}

static void _SendSingleInstanceResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    PostInstanceMsg* message,
    const MI_Char* action,
    MI_Uint32 actionSize)
{
    WSBuf   outBuf;
    Page*       responsePage = 0;

    if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
        goto failed;

    if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
        action, actionSize, selfCD->wsheader.rqtMessageID))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(T("</SOAP-ENV:Header>")
        T("<SOAP-ENV:Body>")
        )))
        goto failed;


    if (MI_RESULT_OK != WSBuf_AddCharLit(&outBuf,
        message->packedInstancePtr, message->packedInstanceSize))
        goto failed;

    /* trailer */
    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(
        T("</SOAP-ENV:Body>")
        T("</SOAP-ENV:Envelope>"))))
        goto failed;

    /* all together */
    responsePage = WSBuf_StealPage(&outBuf);

    if (!responsePage)
        goto failed;

    /* Trace the response XML */

    if (self->options.enableTracing)
    {
        printf("%s\n\n", (char*)(responsePage+1));
    }

    /* {
        FILE* f = Fopen("out_test.xml", "a");
        fwrite((char*)(responsePage+1), 1, (size_t)responsePage->u.s.size, f);
        fclose(f);
    } */

    Http_SendResponse(
        self->http, 
        selfCD->httpConnectionHandle, 
        HTTP_ERROR_CODE_OK, 
        &responsePage);

    /* indicate that response was sent */
    selfCD->outstandingRequest = MI_FALSE;

    if (responsePage)
        free(responsePage);

    return;

failed:
    WSBuf_Destroy(&outBuf);
    if (responsePage) free(responsePage);

    Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);

    /* indicate that response was sent */
    selfCD->outstandingRequest = MI_FALSE;
}

static void _SendDeleteInstanceResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD)
{
    WSBuf   outBuf;
    Page*       responsePage = 0;

    if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE) != MI_RESULT_OK)
        goto failed;

    if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
        LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/DeleteResponse")), selfCD->wsheader.rqtMessageID))
        goto failed;

    if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
        LIT(T("</SOAP-ENV:Header>")
        T("<SOAP-ENV:Body/>")
        T("</SOAP-ENV:Envelope>")
        )))
        goto failed;

    /* all together */
    responsePage = WSBuf_StealPage(&outBuf);

    if (!responsePage)
        goto failed;

    /* Trace the response XML */

    if (self->options.enableTracing)
    {
        printf("%s\n\n", (char*)(responsePage+1));
    }

    /*{
        FILE* f = Fopen("out_test.xml", "a");
        fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
        fclose(f);
    }*/

    Http_SendResponse(
        self->http, 
        selfCD->httpConnectionHandle, 
        HTTP_ERROR_CODE_OK, 
        &responsePage);

    /* indicate that response was sent */
    selfCD->outstandingRequest = MI_FALSE;

    if (responsePage)
        free(responsePage);

    return;

failed:
    WSBuf_Destroy(&outBuf);
    if (responsePage) free(responsePage);

    Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);

    /* indicate that response was sent */
    selfCD->outstandingRequest = MI_FALSE;
}

static void _SendErrorResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD, 
    MI_Result result)
{
    WSBUF_FAULT_CODE faultCode;
    const MI_Char* description = 0;

    faultCode = WSBuf_CIMErrorToWSFault(result, &description);

    /* ATTN! consume text from cim_error if supplied */
    _SendFaultResponse(self->http, selfCD, faultCode, description);
}


/* Function processes backlog in enumeration context;
    returns true if message was sent to active connection;
    once last repsonse is sent, it deletes context */
static MI_Boolean _ProcessEnumResponse(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC,
    MI_Boolean attachingPullRequest)
{
    /* do we have connected cleint to send response to? */
    if (!selfEC->activeConnection)
        return MI_FALSE;

    if (selfEC->enumerationCompleted && selfEC->finalResult != MI_RESULT_OK)
    {
        _SendErrorResponse(self, selfEC->activeConnection, selfEC->finalResult);

        /* release context */
        _EC_SetActiveConnection(selfEC, 0);
        _WSMAN_ReleaseEnumerateContext(self, selfEC->enumerationContextID);
        selfEC = 0;
        return MI_TRUE;
    }

    /* Check if partial response has to be sent (or enumeration is completed) */
    /* Update: send anything that is available once client re-connects with pull */
    /* Send resposne now if:
        - enumeration is complete
        - queue has enough instances to fill entire packet (by size or number)
        - pull request arrives. Normally, network is lsower than providers,
            so once client returns with next pull request, lets send all messages
            we have in queue
        - server is stressed (too many instances)
    */
    if (selfEC->enumerationCompleted ||
        WSMAN_APROX_ENUM_RESP_HEADER_SIZE + selfEC->totalResponseSize > selfEC->activeConnection->wsheader.maxEnvelopeSize ||
        selfEC->totalResponses >= selfEC->activeConnection->u.wsenumpullbody.maxElements ||
        (attachingPullRequest && selfEC->head) ||
        (Selector_IsStressed(self->selector) && selfEC->head)
        )
    //if (selfEC->enumerationCompleted || selfEC->head)
    {
        //LOGW_CHAR(("processing responses %d", selfEC->totalResponses));

        _SendEnumPullResponse(self, selfEC);
        _EC_SetActiveConnection(selfEC, 0);
    }

    /* release context if last message was sent */
    if (selfEC->enumerationCompleted && !selfEC->head)
    {
        _EC_SetActiveConnection(selfEC, 0);
        _WSMAN_ReleaseEnumerateContext(self, selfEC->enumerationContextID);
        selfEC = 0;
    }
    else
    {
        /* set/update timer */
        _WSMAN_SetUpdateTimer(self, selfEC);
    }

    return MI_TRUE;
}

static void _ProcessResultEnumerationContext(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC,
    PostResultMsg* message )
{
    /* mark context as 'completed' */
    selfEC->enumerationCompleted = MI_TRUE;
    selfEC->finalResult = message->result;
    //ATTN!: process error text/messages

    _ProcessEnumResponse(self, selfEC, MI_FALSE);

    /* release context */
    _EC_Release(selfEC, MI_FALSE);
}


static void _ProcessInstanceResponse(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    PostInstanceMsg* message)
{
    /* send appropriate response */
    switch (selfCD->wsheader.rqtAction)
    {
    case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
        _SendInvokeResponse(self, selfCD, message);
        break;

    case WSMANTAG_ACTION_GET:
        _SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")));
        break;

    case WSMANTAG_ACTION_PUT:
        _SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse")));
        break;

    case WSMANTAG_ACTION_CREATE:
        _SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse")));
        break;

    default:
        /* unexpected */
        _SendFaultResponse(
            self->http, 
            selfCD, 
            WSBUF_FAULT_INTERNAL_ERROR, 
            T("unexpected internal state"));
        break;
    }
    selfCD->outstandingRequest = MI_FALSE;
}

static void _ProcessResultConnectionData(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    PostResultMsg* message )
{
    /* if response was not sent yet, send it now (error probably) */
    if (selfCD->outstandingRequest)
    {
        if (selfCD->single_message)
        {
            _ProcessInstanceResponse(self, selfCD, selfCD->single_message);
        }
        else if (MI_RESULT_OK == message->result &&
            WSMANTAG_ACTION_DELETE == selfCD->wsheader.rqtAction)
        {
            _SendDeleteInstanceResponse(self, selfCD);
        }
        else
        {
            _SendErrorResponse(self, selfCD, message->result);
        }

        selfCD->outstandingRequest = MI_FALSE;
    }

    /* release connection data */
    _CD_Release(selfCD);
}

static void _ProcessInstanceConnectionData(
    WSMAN* self,
    WSMAN_ConnectionData* selfCD,
    PostInstanceMsg* message)
{
    MI_UNUSED(self);

    /* Ignore expired contexts */
    if (!selfCD->outstandingRequest)
        return;

    _CD_SetSingleMessage(selfCD, message);
}

static void _ProcessInstanceEnumerationContext(
    WSMAN* self,
    WSMAN_EnumerateContext* selfEC,
    PostInstanceMsg* message )
{
    /* Ignore expired contexts */
    if (selfEC->expired)
        return;

    /* add-ref message to keep it alive */
    Message_AddRef( &message->base);

    /* Add it to the list to process when result is posted */
    List_Append(
        (ListElem**)&selfEC->head, 
        (ListElem**)&selfEC->tail, 
        (ListElem*)message);

    /* Increment total instance size */
    selfEC->totalResponseSize += message->packedInstanceSize;

    /* Increment total number of responses */
    selfEC->totalResponses++;

    /* Check if we need to send response to the client */
    _ProcessEnumResponse(self, selfEC, MI_FALSE);
}

/* HTTP callbacks */
static void _HttpCallbackOnNewConnection(
    Http* http,
    void* callbackData,
    void* httpConnectionHandle,
    void** connectionData)
{
    WSMAN_ConnectionData* selfConnectionData;
    MI_UNUSED(http);
    MI_UNUSED(callbackData);

    selfConnectionData = (WSMAN_ConnectionData*)calloc(1, sizeof(WSMAN_ConnectionData));

    if (!selfConnectionData)
        return /*MI_RESULT_FAILED*/;

    selfConnectionData->httpConnectionHandle = httpConnectionHandle;
    selfConnectionData->refcounter = 1;
    selfConnectionData->tag = DATA_TAG_CONNECTION_DATA;
    *connectionData = selfConnectionData;
}

static void _HttpCallbackOnCloseConnection(
    Http* http,
    void* callbackData,
    void* connectionData)
{
    MI_UNUSED(http);
    MI_UNUSED(callbackData);

    if (connectionData)
    {
        WSMAN_ConnectionData* selfConnectionData = (WSMAN_ConnectionData*)connectionData;
        selfConnectionData->httpConnectionHandle = 0;
        selfConnectionData->outstandingRequest = MI_FALSE;

        _CD_Release(selfConnectionData);
    }
}

static void _HttpCallbackOnRequest(
    Http* http,
    void* callbackData,
    void* connectionData,
    void* httpConnectionHandle,
    const HttpHeaders* headers,
    Page** page)
{
    WSMAN_ConnectionData* selfCD = (WSMAN_ConnectionData*)connectionData;
    WSMAN* self = (WSMAN*)callbackData;
    XML     xml = self->xml;

    /* Trace the request XML */

    if (self->options.enableTracing)
    {
        printf("%s\n\n", (const char*)((*page)+1));
    }

    /* Cleanup connection data, since it may still store allocated pointers 
        from previous operation */
    _CD_Cleanup(selfCD);

    /* Verify content type */
    if ( !headers->contentType ||
        (Strcasecmp(headers->contentType,"application/soap+xml") != 0 &&
            Strcasecmp(headers->contentType,"text/xml") != 0))
    {
        LOGW_CHAR(("wsman: invalid/missing content type in request [%s]", (const char*)((*page)+1) ));
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_BAD_REQUEST);
        return;
    }

    if (headers->charset &&
        Strcasecmp(headers->charset,"utf-8") != 0)
    {
        LOGW_CHAR(("wsman: charset is not supported [%s]", MI_GET_SAFE_PRINTF_STRING(headers->charset) ));
        _SendFaultResponse(http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, T("only utf 8 is supported"));
        return;
    }

    if (!headers->username || !headers->password ||
        0 != AuthenticateUser(headers->username, headers->password))
    {
        LOGW_CHAR(("wsman: authentication failed for user [%s]", MI_GET_SAFE_PRINTF_STRING(headers->username) ));
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_UNAUTHORIZED);
        return;
    }

    if (0 != LookupUser(headers->username, &selfCD->uid, &selfCD->gid))
    {
        LOGW_CHAR(("wsman: get user [%s] uid/gid", MI_GET_SAFE_PRINTF_STRING(headers->username) ));
        Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        return;
    }

    XML_SetText(&xml, (char*)((*page)+1));

    /* Parse header */
    if (WS_ParseSoapEnvelope(&xml) != 0 || 
        xml.status)
    {
        LOGW_CHAR(("wsman: failed to parse SOAP envelope"));
        Http_SendErrorResponse(http, httpConnectionHandle, 
            HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        return;
    }

    /* Parse WS header */
    if (WS_ParseWSHeader(&xml, &selfCD->wsheader) != 0 ||
        xml.status)
    {
        LOGW_CHAR(("wsman: failed to parse WS header"));
        Http_SendErrorResponse(http, 
            httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
        return;
    }

    /* Validate header */
    if (_ValidateHeader(http, selfCD) != 0)
    {
        return;
    }

    /* See if this is a Identify request */

    if (!selfCD->wsheader.foundAction)
    {
        _HandleIdentifyRequest(
            http, 
            httpConnectionHandle, 
            self, 
            selfCD,
            &xml);
        return;
    }

    /* keep reference to the page to keep xml object/ cached strings like msgID valid */
    _CD_SetPage(selfCD, *page);
    *page = 0;

    selfCD->outstandingRequest = MI_TRUE;

    /* Parse body and send request to the dispatcher */
    switch (selfCD->wsheader.rqtAction)
    {
        case WSMANTAG_ACTION_ENUMERATE:
        {
            _ParseValidateProcessEnumerateRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case WSMANTAG_ACTION_PULL:
        {
            _ParseValidateProcessPullRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case WSMANTAG_ACTION_RELEASE:
        {
            _ParseValidateProcessReleaseRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case WSMANTAG_ACTION_GET:
        {
            _ParseValidateProcessGetRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case WSMANTAG_ACTION_PUT:
        {
            _ParseValidateProcessPutRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case WSMANTAG_ACTION_DELETE:
        {
            _ParseValidateProcessDeleteRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case WSMANTAG_ACTION_CREATE:
        {
            _ParseValidateProcessCreateRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
        {
            _ParseValidateProcessInvokeRequest(http, httpConnectionHandle, self, selfCD, &xml);
            break;
        }
        default:
        {
            /* unsupported action */
            LOGW_CHAR(("wsman: unsupported action [%d] ", selfCD->wsheader.rqtAction ));
            _SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_SUPPORTED, 0);
            selfCD->outstandingRequest = MI_FALSE;
            break;
        }
    }
}

/*
**==============================================================================
**
** Public definitions:
**
**==============================================================================
*/
MI_Result WSMAN_New_Listener(
    WSMAN** selfOut,
    Selector* selector, /*optional, maybe NULL*/
    unsigned short http_port,   /* 0 to disable */
    unsigned short https_port,  /* 0 to disable */
    WSMANCallback callback,
    void* callbackData)
{
    WSMAN* self;
    MI_Result r;

    /* Check parameters */
    if (!selfOut)
        return MI_RESULT_INVALID_PARAMETER;

    /* Clear output parameter */
    *selfOut = NULL;

    /* Allocate structure */
    {
        self = (WSMAN*)calloc(1, sizeof(WSMAN));

        if (!self)
            return MI_RESULT_FAILED;
    }

    /* Save the callback and callbackData */
    self->callback = callback;
    self->callbackData = callbackData;

    /*ATTN! slector can be null!*/
    self->selector = selector;

    /* options */
    {
        WSMAN_Options options = DEFAULT_WSMAN_OPTIONS;

        self->options = options;
    }

    /* Set the magic number */
    self->magic = _MAGIC;

    /* create a server */
    r = Http_New_Server(
        &self->http, selector, http_port, https_port,
        _HttpCallbackOnNewConnection,
        _HttpCallbackOnCloseConnection,
        _HttpCallbackOnRequest, self);

    if (MI_RESULT_OK != r)
    {
        WSMAN_Delete(self);
        return r;
    }

    /* Initialize xml parser */
    XML_Init(&self->xml);

    XML_RegisterNameSpace(&self->xml, 's', 
        "http://www.w3.org/2003/05/soap-envelope");

    XML_RegisterNameSpace(&self->xml, 'a', 
        "http://schemas.xmlsoap.org/ws/2004/08/addressing");

    XML_RegisterNameSpace(&self->xml, 'w', 
        "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd");

    XML_RegisterNameSpace(&self->xml, 'n', 
        "http://schemas.xmlsoap.org/ws/2004/09/enumeration");

    XML_RegisterNameSpace(&self->xml, 'b', 
        "http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd");

    XML_RegisterNameSpace(&self->xml, 'p', 
        "http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd");

    XML_RegisterNameSpace(&self->xml, 'i',
        "http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd");

    *selfOut = self;

    return MI_RESULT_OK;
}

MI_Result WSMAN_Delete(
    WSMAN* self)
{
    /* Check parameters */
    if (!self)
        return MI_RESULT_INVALID_PARAMETER;

    /* Check magic number */
    if (self->magic != _MAGIC)
        return MI_RESULT_INVALID_PARAMETER;

    Http_Delete(self->http);

    /* clear all outstanding contexts */
    _WSMAN_ReleaseAllEnumerateContexts(self);

    /* Clear magic number */
    self->magic = 0xDDDDDDDD;

    /* Free self pointer */
    free(self);

    return MI_RESULT_OK;
}

MI_Result WSMAN_Run(
    WSMAN* self,
    MI_Uint64 timeoutUsec)
{
    /* Run the selector */
    return Http_Run(self->http, timeoutUsec);
}

static MI_Result _SendIN_IO_thread(
    void* self_,
    Message* message)
{
    WSMAN* self = (WSMAN*)self_;
    WSMAN_ConnectionData* selfCD = 0;
    WSMAN_EnumerateContext* selfEC = 0;

    /* check params */
    if (!self || !message )
        return MI_RESULT_INVALID_PARAMETER;

    if (self->magic != _MAGIC)
    {
        LOGW((T("_SendIN_IO_thread: invalid magic!") ));
        return MI_RESULT_INVALID_PARAMETER;
    }

    /* find where to send it */
    selfCD = (WSMAN_ConnectionData*)Uint64ToPtr(message->clientID);
    selfEC = (WSMAN_EnumerateContext*)Uint64ToPtr(message->clientID);

    if (selfCD && selfCD->tag != DATA_TAG_CONNECTION_DATA)
    {
        selfCD = 0;
    }
    if (selfEC && selfEC->tag != DATA_TAG_ENUMERATION_CONTEXT)
    {
        selfEC = 0;
    }
    if (!selfCD && !selfEC)
    {
        LOGW((T("_SendIN_IO_thread: clientID!") ));
        return MI_RESULT_INVALID_PARAMETER;
    }

    /* ATTN! validate handler */

    /* Process response message */
    switch (message->tag)
    {
    case PostResultMsgTag:
        if (selfCD)
            _ProcessResultConnectionData(self, selfCD, (PostResultMsg*)message );
        else
            _ProcessResultEnumerationContext(self, selfEC, (PostResultMsg*)message );

        break;

    case PostInstanceMsgTag:
        if (selfCD)
            _ProcessInstanceConnectionData(self, selfCD, (PostInstanceMsg*)message );
        else
            _ProcessInstanceEnumerationContext(self, selfEC, (PostInstanceMsg*)message );

        break;

    default:
        LOGW((T("wsman: _SendIN_IO_thread: unexpected message tag %d"), message->tag ));
        return MI_RESULT_INVALID_PARAMETER;
    }

    return MI_RESULT_OK;
}

/* Signature must not have return type so we created this wrapper */
static void _SendIN_IO_thread_wrapper(void* self, Message* message)
{
    MI_Result r;
    r = _SendIN_IO_thread(self, message);

    /* ATTN: log failed result? */
}


MI_Result WSMAN_Send(
    WSMAN* self,
    Message* message)
{
    return Selector_CallInIOThread(
        self->selector, _SendIN_IO_thread_wrapper, self, message );
}

MI_Result WSMAN_SetOptions(
    WSMAN* self,
    const WSMAN_Options* options)
{
    /* check params */
    if (!self || !options)
        return MI_RESULT_INVALID_PARAMETER;

    /* Check magic number */
    if (self->magic != _MAGIC)
    {
        LOGW((T("invalid magic!") ));
        return MI_RESULT_INVALID_PARAMETER;
    }

    self->options = *options;
    return MI_RESULT_OK;
}

ViewCVS 0.9.2