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

File: [OMI] / omi / disp / disp.c (download)
Revision: 1.1.1.1 (vendor branch), Wed May 30 21:47:39 2012 UTC (12 years ago) by mike
Branch: TOG
CVS Tags: OMI_1_0_2_Branch, OMI_1_0_1_PRE, OMI_1_0_0
Changes since 1.1: +0 -0 lines
Initial Import

/*
**==============================================================================
**
** 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 <base/strings.h>
#include <base/messages.h>
#include <base/log.h>
#include <base/strings.h>
#include <base/paths.h>
#include <base/io.h>
#include <wql/wql.h>
#include "disp.h"

#define T MI_T

/*
**==============================================================================
**
** Data structures
**
**==============================================================================
*/

/*
    subscription item - represents single subscription;
*/
typedef struct _DispSubscriptionItem
{
    struct _DispSubscriptionItem* next;
    struct _DispSubscriptionItem* prev;

    /* The batch this context was allocated from */
    Batch batch;

    /* filter */
    MI_ConstString  filter;
    MI_ConstString  language;

    /* unique id of the sub */
    MI_Uint64       subscriptionID;

    /* Client identifier if supported */
    MI_Uint64 clientID;

}
DispSubscriptionItem;


/* subscriptions context -
    used to track indicaiton providers
    and store indications for 'pull' operation
    one context per ns/cn pair
*/
typedef struct _DispIndicationContext
{
    struct _DispIndicationContext* next;
    struct _DispIndicationContext* prev;

    /* The batch this context was allocated from */
    Batch batch;

    /* namespace/cn */
    MI_ConstString  nameSpace;
    MI_ConstString  className;

    /* unique id of the context (used by ProvMgr) */
    MI_Uint64       ctxID;

    /* provider info */
    const ProvRegEntry* provEntry;

    /* exisitng subscriptions */
    DispSubscriptionItem* headSubscriptions;
    DispSubscriptionItem* tailSubscriptions;
}
DispIndicationContext;


/*
**==============================================================================
**
** Local definitions
**
**==============================================================================
*/
static MI_Result _SendErrorResponse(
    Message* req,
    MI_Result r);

static DispIndicationContext* _FindIndCtxByNScn(
    Disp* self,
    MI_ConstString  nameSpace,
    MI_ConstString  className)
{
    DispIndicationContext* current = (DispIndicationContext*)self->headIndCtx;

    while (current)
    {
        if (0 == Zcasecmp(nameSpace, current->nameSpace) &&
            0 == Zcasecmp(className, current->className))
            break;

        current = current->next;
    }
    return current;
}

static DispIndicationContext* _FindIndCtxByID(
    Disp* self,
    MI_Uint64 id)
{
    DispIndicationContext* current = (DispIndicationContext*)self->headIndCtx;

    while (current)
    {
        if (id == current->ctxID)
            break;

        current = current->next;
    }
    return current;
}

static DispSubscriptionItem* _FindSubscriptionItem(
    DispIndicationContext* ctx,
    MI_Uint64 subscriptionID)
{
    DispSubscriptionItem* item = ctx->headSubscriptions;

    while (item)
    {
        if (item->subscriptionID == subscriptionID)
            break;

        item = item->next;
    }
    return item;
}


static void _DestroySubscriptionItem(
    DispSubscriptionItem* item)
{
    Batch_Destroy(&item->batch);
}
static void _DestroyIndCtx(
    DispIndicationContext* ctx)
{
    DispSubscriptionItem* item = ctx->headSubscriptions;

    while (item)
    {
        DispSubscriptionItem* next = item->next;

        _DestroySubscriptionItem(item);
        item = next;
    }
    Batch_Destroy(&ctx->batch);
}


static MI_Result _FindCreateIndCtx(
    Disp* self,
    SubscribeReq* req,
    ProvRegEntry const** reg)
{
    /* look for exisiting first */
    DispIndicationContext* ctx = _FindIndCtxByNScn( self, req->nameSpace, req->className );

    if (!ctx)
    {
        Batch batch = BATCH_INITIALIZER;

        /* Allocate heap space for message */
        ctx = (DispIndicationContext*) Batch_GetClear(&batch, sizeof(DispIndicationContext) );

        if (!ctx)
            return MI_RESULT_FAILED;

        /* Copy batch into context (released by _Destroy method) */
        memcpy(&ctx->batch, &batch, sizeof(batch));

        ctx->className = Batch_Zdup(&batch, req->className);
        ctx->nameSpace = Batch_Zdup(&batch, req->nameSpace);

        if (!ctx->className || !ctx->nameSpace)
        {
            _DestroyIndCtx(ctx);
            return MI_RESULT_FAILED;
        }
        ctx->ctxID = ++self->nextID;

        /* Look for provider info */
        ctx->provEntry = ProvReg_FindProviderForClass(&self->provreg, 
            req->nameSpace, req->className);

        if (!ctx->provEntry)
        {
            _DestroyIndCtx(ctx);
            return MI_RESULT_INVALID_NAMESPACE;
        }

        /* add context to the list */
        List_Append(&self->headIndCtx, &self->tailIndCtx, (ListElem*)ctx);
    }

    /* Update request with correct IDs */
    req->ctxID = ctx->ctxID;
    req->subscriptionID = ++self->nextID;

    /* Set out parameter */
    *reg = ctx->provEntry;

    return MI_RESULT_OK;
}

static MI_Result _UpdateIndicationCtxWithSub(
    Disp* self,
    SubscribeReq* dispReq)
{
    DispIndicationContext* ctx;
    DispSubscriptionItem* subItem;

    ctx = _FindIndCtxByID( self, dispReq->ctxID );

    /* unlikely, but it can be removed by other operation */
    if (!ctx)
        return MI_RESULT_FAILED;

    /* */
    subItem = _FindSubscriptionItem(ctx, dispReq->subscriptionID);

    if (subItem)
        return MI_RESULT_ALREADY_EXISTS;

    {
        Batch batch = BATCH_INITIALIZER;

        /* Allocate heap space for message */
        subItem = (DispSubscriptionItem*) Batch_GetClear(&batch, sizeof(DispSubscriptionItem) );

        if (!subItem)
            return MI_RESULT_FAILED;

        /* Copy batch into context (released by _Destroy method) */
        memcpy(&subItem->batch, &batch, sizeof(batch));

        subItem->filter = Batch_Zdup(&batch, dispReq->filter);
        subItem->language = Batch_Zdup(&batch, dispReq->language);

        if (!subItem->filter || !subItem->language)
        {
            _DestroySubscriptionItem(subItem);
            return MI_RESULT_FAILED;
        }
        subItem->subscriptionID = dispReq->subscriptionID;
        subItem->clientID = dispReq->base.request->clientID;

        /* add item to the context */
        List_Append(
            (ListElem**)&ctx->headSubscriptions, 
            (ListElem**)&ctx->tailSubscriptions, 
            (ListElem*)subItem);
    }
    
    return MI_RESULT_OK;
}

static void _ProcessSubscribeResponse(
    Disp* self,
    PostResultMsg* rsp)
{
    MI_Result r;
    SubscribeReq* dispReq = (SubscribeReq*)rsp->base.request;


    /* Find context, create subscription struct */
    Mutex_Lock(&self->mt);

    r = _UpdateIndicationCtxWithSub( self, dispReq );

    Mutex_Unlock(&self->mt);

    /* check if error was detected */
    if (MI_RESULT_OK != r)
    {
        _SendErrorResponse(rsp->base.request->request, r);
    }

    /* send subscription response */
    {
        SubscribeRes* resp;
        char s[50];

        resp = SubscribeRes_New( rsp->base.request->request->msgID );

        if (!resp)
            return ;

        Snprintf(s, MI_COUNT(s), UINT64_FMT "," UINT64_FMT, 
            dispReq->ctxID,
            dispReq->subscriptionID);

        resp->subscriptionID = Batch_Strdup2(resp->base.batch, s);

        Message_SetRequest(&resp->base,rsp->base.request->request);
        (*rsp->base.request->request->callback)(&resp->base, rsp->base.request->request->callbackData);

        SubscribeRes_Release(resp);
    }

}

static void _ProviderToDispatcherCallback(
    Message* msg, 
    void* callbackData)
{
    switch ( msg->tag )
    {
        case PostResultMsgTag:
        {
            PostResultMsg* rsp = (PostResultMsg*)msg;

            if (msg->request && msg->request->request &&  msg->request->request->tag == DispResultMsgTag)
            {
                DispResultMsg* dispStateMsg = (DispResultMsg*)msg->request->request;

                if (rsp->result != MI_RESULT_OK && dispStateMsg->result == MI_RESULT_OK)
                {
                    dispStateMsg->result = rsp->result;
                }

                if ( AtomicDec(&dispStateMsg->requestCounter) )
                {   /* last result - forward it to the net stack */
                    rsp->result = dispStateMsg->result;
                }
                else    /* not the last result - skip it */
                    return;

            }
            else if (msg->request && msg->request->tag == SubscribeReqTag)
            {
                /* process subscription response */
                if (MI_RESULT_OK != rsp->result )
                    break;

                /* 
                    validate parameter msg->request->request is a parameter received from network transport;
                    msg->request is a message created by disp for provmgr
                */
                if (msg->request->request)
                {
                    _ProcessSubscribeResponse((Disp*)callbackData, rsp);
                    return;
                }
            }
        }
        break;

        default:
            break;
    }

    /* forward message to the other side */
    if (msg->request && msg->request->request)
    {
        /* delegate message to protocol stack */
        msg->clientID = msg->request->request->clientID;
        (*msg->request->request->callback)(msg, msg->request->request->callbackData);
    } 
    else if (msg->request)
    {
        /* delegate message to protocol stack */
        msg->clientID = msg->request->clientID;
        (*msg->request->callback)(msg, msg->request->callbackData);
    } 
    else 
    {
        (*msg->callback)(msg, msg->callbackData);
    }
}

static MI_Boolean _DispatchEnumerateInstancesReq(
    Disp* self,
    const MI_Char* className, 
    const EnumerateInstancesReq* req,
    DispResultMsg* dispStateMsg)
{
    const ProvRegEntry* entry;
    EnumerateInstancesReq* msg;
    MI_Result r;

    /* Attempt to find a provider for this class */
    {
        entry = ProvReg_FindProviderForClass(&self->provreg, 
            req->nameSpace, className);

        if (!entry)
            return MI_FALSE;
    }

    /* Create new request to send to provider */
    msg = EnumerateInstancesReq_New(req->base.msgID, req->base.flags);
    msg->base.clientID = req->base.clientID;
    msg->base.uid = req->base.uid;
    msg->base.gid = req->base.gid;
    msg->nameSpace = Batch_Zdup(msg->base.batch, req->nameSpace);
    msg->className = Batch_Zdup(msg->base.batch, className);

    /* Clone the query fields (if any) */
    if (req->queryLanguage)
        msg->queryLanguage = Batch_Zdup(msg->base.batch, req->queryLanguage);

    if (req->queryExpression)
        msg->queryExpression = Batch_Zdup(msg->base.batch,req->queryExpression);

    if (req->wql)
        msg->wql = WQL_Clone(req->wql, msg->base.batch);

    /* Save request's class name to allow porvmgr pack back only base properties */
    if (req->basePropertiesOnly)
        msg->requestClassName = Batch_Zdup(msg->base.batch, req->className);

    AtomicInc(&dispStateMsg->requestCounter);
    Message_SetRequest(&msg->base, &dispStateMsg->base);

    /* Setup callback */
    msg->base.callback = _ProviderToDispatcherCallback;
    msg->base.callbackData = self;

    /* Send the request to provider manager */
    r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, entry);

    /* Release the original message */
    EnumerateInstancesReq_Release(msg);

    /* Log failure */
    if (r != MI_RESULT_OK)
    {
        LOGW((T("AgentMgr_HandleRequest() failed: %u: %s"), r, 
            Result_ToString(r)));
        
        AtomicDec(&dispStateMsg->requestCounter);
        return MI_FALSE;
    }


    return MI_TRUE;
}

static MI_Boolean _DispatchAssocReq(
    Disp* self,
    const MI_Char* className, 
    const AssociatorsOfReq* req,
    DispResultMsg* dispStateMsg)
{
    const ProvRegEntry* entry;
    AssociatorsOfReq* msg;
    MI_Result r;
    
    /* Attempt to find a provider for this class */
    {
        entry = ProvReg_FindProviderForClass(&self->provreg, 
            req->nameSpace, className);

        if (!entry)
            return MI_FALSE;
    }

    /* Create new request to send to provider */
    msg = AssociatorsOfReq_New(req->base.msgID, req->base.flags);
    msg->base.clientID = req->base.clientID;
    msg->base.uid = req->base.uid;
    msg->base.gid = req->base.gid;
    /* original request will be kept for the request duration, so perform shallow copy only */
    /*ATTN! perform full copy*/
    msg->nameSpace = req->nameSpace;
    msg->assocClass = req->assocClass;
    msg->resultClass = req->resultClass;
    msg->role = req->role;
    msg->resultRole = req->resultRole;
    msg->instance = req->instance;
    msg->packedInstancePtr = req->packedInstancePtr;
    msg->packedInstanceSize = req->packedInstanceSize;

    msg->className = className;

    AtomicInc(&dispStateMsg->requestCounter);
    Message_SetRequest(&msg->base, &dispStateMsg->base);

    /* Setup callback */
    msg->base.callback = _ProviderToDispatcherCallback;
    msg->base.callbackData = self;

    /* Send the request to provider manager */
    r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, entry);

    /* Release the original message */
    AssociatorsOfReq_Release(msg);

    /* Log failure */
    if (r != MI_RESULT_OK)
    {
        LOGW((T("AgentMgr_HandleRequest() failed: %u: %s"), r, 
            Result_ToString(r)));
        
        AtomicDec(&dispStateMsg->requestCounter);
        return MI_FALSE;
    }

    return MI_TRUE;
}

static MI_Boolean _DispatchRefReq(
    Disp* self,
    const MI_Char* className, 
    const ReferencesOfReq* req,
    DispResultMsg* dispStateMsg)
{
    const ProvRegEntry* entry;
    ReferencesOfReq* msg;
    MI_Result r;
    
    /* Attempt to find a provider for this class */
    {
        entry = ProvReg_FindProviderForClass(&self->provreg, 
            req->nameSpace, className);

        if (!entry)
            return MI_FALSE;
    }

    /* Create new request to send to provider */
    msg = ReferencesOfReq_New(req->base.msgID, req->base.flags);
    msg->base.clientID = req->base.clientID;
    msg->base.uid = req->base.uid;
    msg->base.gid = req->base.gid;
    /* original request will be kept for the request duration, so perform shallow copy only */
    /*ATTN! perform full copy*/
    msg->nameSpace = req->nameSpace;
    msg->assocClass = req->assocClass;
    msg->role = req->role;
    msg->instance = req->instance;
    msg->packedInstancePtr = req->packedInstancePtr;
    msg->packedInstanceSize = req->packedInstanceSize;

    msg->className = className;

    AtomicInc(&dispStateMsg->requestCounter);
    Message_SetRequest(&msg->base, &dispStateMsg->base);

    /* Setup callback */
    msg->base.callback = _ProviderToDispatcherCallback;
    msg->base.callbackData = self;

    /* Send the request to provider manager */
    r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, entry);

    /* Release the original message */
    ReferencesOfReq_Release(msg);

    /* Log failure */
    if (r != MI_RESULT_OK)
    {
        LOGW((T("AgentMgr_HandleRequest() failed: %u: %s"), r, 
            Result_ToString(r)));
        
        AtomicDec(&dispStateMsg->requestCounter);
        return MI_FALSE;
    }

    return MI_TRUE;
}

static MI_Result _SendErrorResponse(
    Message* req,
    MI_Result r
    )
{
    PostResultMsg* resp;

    resp = PostResultMsg_New( req->msgID );

    if (!resp)
        return MI_RESULT_FAILED;

    resp->result = r;
    Message_SetRequest(&resp->base,req);
    (*req->callback)(&resp->base, req->callbackData);

    PostResultMsg_Release(resp);

    return MI_RESULT_OK;
}

static MI_Result _HandleEnumerateInstancesReq(
    Disp* self,
    EnumerateInstancesReq* req)
{
    ProvRegPosition pos;
    MI_Result r;
    MI_Boolean sentOk = MI_FALSE;
    DispResultMsg* dispStateMsg;

    /* Validate input parameters */
    if (!req->className || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    /* create a state message that will keep track of results from providers */
    dispStateMsg = DispResultMsg_New(req->base.msgID);
    if (!dispStateMsg)
        return MI_RESULT_FAILED;

    /* add one for sending thread so first 'fast' provider will not send its response all the way */
    AtomicInc(&dispStateMsg->requestCounter);
    
    dispStateMsg->base.clientID = req->base.clientID;
    /* Setup callback */
    dispStateMsg->base.callback = req->base.callback;
    dispStateMsg->base.callbackData = req->base.callbackData;

    /* Precompile the query */
    if (req->queryLanguage || req->queryExpression)
    {
        /* Fail if either query language or expression is missing */
        if (!req->queryLanguage || !req->queryExpression)
        {
            LOGW((T("queryLanguage or queryExpression is missing")));
            r = MI_RESULT_INVALID_QUERY;
            goto sendErrorBack;
        }

        /* Reject non-WQL queries */
        if (Zcmp(req->queryLanguage, T("WQL")) != 0)
        {
            LOGW((T("unknown query language: %s"), req->queryLanguage));
            r = MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED;
            goto sendErrorBack;
        }

        /* Compile the query */
        {
            req->wql = WQL_Parse(req->queryExpression, req->base.batch);

            if (!req->wql)
            {
                LOGW((T("invalid query expression: %s"), req->queryExpression));
                r = MI_RESULT_INVALID_QUERY;
                goto sendErrorBack;
            }
        }

        /* Verify that the query classname matches the enumeration classname */
        if (Zcmp(req->wql->className, req->className) != 0)
        {
            LOGW((T("query/enumeration class name mismatch: %s/%s"), 
                req->className, req->className));
            r = MI_RESULT_INVALID_QUERY;
            goto sendErrorBack;
        }
    }

    /* Send to direct name */
    if (_DispatchEnumerateInstancesReq(self, req->className, req, dispStateMsg))
        sentOk = MI_TRUE;

    if (req->deepInheritance)
    {
        /* Begin enumeration of classes for this request */
        {
            r = ProvReg_BeginClasses(&self->provreg, req->nameSpace, 
                req->className, MI_TRUE, &pos);

            if (MI_RESULT_OK != r)
            {
                LOGD((T("ProvReg_BeginClasses() failed: %u: %s"), 
                    r, Result_ToString(r)));

                LOGI((T("unknown class in enumerate request: %s:%s"), 
                    req->nameSpace, req->className));

                /* send error back to caller */
                goto sendErrorBack;
            }
        }

        /* While more classes */
        for (;;)
        {
            const MI_Char* derived = NULL;
            MI_Boolean done;

            r = ProvReg_NextClass(&pos, &derived, &done);

            if (done)
                break;

            if (MI_RESULT_OK != r)
            {
                LOGD((T("ProvReg_NextClass() failed: %u: %s"), 
                    r, Result_ToString(r)));

                LOGI((T("unknown class in enumerate request: %s:%s"), 
                    req->nameSpace, req->className));

                /* send error back to caller */
                goto sendErrorBack;
            }

            if (_DispatchEnumerateInstancesReq(self, derived, req, dispStateMsg))
                sentOk = MI_TRUE;
        }

        /* Finalize enumeration */
        {
            r = ProvReg_EndClasses(&pos);

            if (MI_RESULT_OK != r)
            {
                LOGD((T("ProvReg_EndClasses() failed: %u: %s"), 
                    r, Result_ToString(r)));
                /* send error back to caller */
                goto sendErrorBack;
            }
        }
    } /* if deep*/

    /* Fail if no provider was found for request */
    if (!sentOk)
    {
        LOGD((T("found no providers for class: %s"), MI_GET_SAFE_PRINTF_STRING(req->className)));
        r = MI_RESULT_NOT_FOUND;
        goto sendErrorBack;
    }

    if ( AtomicDec(&dispStateMsg->requestCounter) )
    {   /* last result - forward it to the net stack */
        r = dispStateMsg->result;
        goto sendErrorBack;
    }

    DispResultMsg_Release(dispStateMsg);
    return MI_RESULT_OK;

sendErrorBack:
    DispResultMsg_Release(dispStateMsg);
    return _SendErrorResponse(&req->base,r);
}


static MI_Result _HandleGetInstanceReq(
    Disp* self,
    GetInstanceReq* req)
{
    MI_Result r;
    const ProvRegEntry* reg;

    /* Validate input parameters */
    if (!req->instanceName || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    // Find a provider for this class.
    reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, 
        req->instanceName->classDecl->name );

    if (!reg)
    {
        r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/
        LOGD((T("cannot find provider for class: %s/%s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace), 
            MI_GET_SAFE_PRINTF_STRING(req->instanceName->classDecl->name)));
        goto sendErrorBack;
    }

    // Send the request to provider manager.
    r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg);

    if (r != MI_RESULT_OK)
    {
        LOGD((T("AgentMgr_HandleRequest for namespace: %s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace)));
        goto sendErrorBack;
    }

    return MI_RESULT_OK;

sendErrorBack:
    return _SendErrorResponse(&req->base,r);
}

static MI_Result _HandleCreateInstanceReq(
    Disp* self,
    CreateInstanceReq* req)
{
    MI_Result r;
    const ProvRegEntry* reg;

    /* Validate input parameters */
    if (!req->instance || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    // Find a provider for this class.
    reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, 
        req->instance->classDecl->name );

    if (!reg)
    {
        r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/
        LOGD((T("cannot find provider for class: %s/%s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace), 
            MI_GET_SAFE_PRINTF_STRING(req->instance->classDecl->name)));
        goto sendErrorBack;
    }

    // Send the request to provider manager.
    r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg);

    if (r != MI_RESULT_OK)
    {
        LOGD((T("AgentMgr_HandleRequest for namespace: %s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace)));
        goto sendErrorBack;
    }

    return MI_RESULT_OK;

sendErrorBack:
    return _SendErrorResponse(&req->base,r);
}

static MI_Result _HandleModifyInstanceReq(
    Disp* self,
    ModifyInstanceReq* req)
{
    MI_Result r;
    const ProvRegEntry* reg;

    /* Validate input parameters */
    if (!req->instance || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    // Find a provider for this class.
    reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, 
        req->instance->classDecl->name );

    if (!reg)
    {
        r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/
        LOGD((T("cannot find provider for class: %s/%s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace), 
            MI_GET_SAFE_PRINTF_STRING(req->instance->classDecl->name)));
        goto sendErrorBack;
    }

    // Send the request to provider manager.
    r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg);

    if (r != MI_RESULT_OK)
    {
        LOGD((T("AgentMgr_HandleRequest for namespace: %s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace)));
        goto sendErrorBack;
    }

    return MI_RESULT_OK;

sendErrorBack:
    return _SendErrorResponse(&req->base,r);
}

static MI_Result _HandleDeleteInstanceReq(
    Disp* self,
    DeleteInstanceReq* req)
{
    MI_Result r;
    const ProvRegEntry* reg;

    /* Validate input parameters */
    if (!req->instanceName || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    // Find a provider for this class.
    reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, 
        req->instanceName->classDecl->name);

    if (!reg)
    {
        r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/
        LOGD((T("cannot find provider for class: %s/%s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace), 
            MI_GET_SAFE_PRINTF_STRING(req->instanceName->classDecl->name)));
        goto sendErrorBack;
    }

    // Send the request to provider manager.
    r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg);

    if (r != MI_RESULT_OK)
    {
        LOGD((T("AgentMgr_HandleRequest for namespace: %s"), 
            MI_GET_SAFE_PRINTF_STRING(req->nameSpace)));
        goto sendErrorBack;
    }

    return MI_RESULT_OK;

sendErrorBack:
    return _SendErrorResponse(&req->base,r);
}

static MI_Result _HandleSubscribeReq(
    Disp* self,
    SubscribeReq* req)
{
    MI_Result r;
    const ProvRegEntry* reg = 0;
    SubscribeReq* msg = 0;

    /* Validate input parameters */
    if (!req->className || !req->nameSpace || !req->language || !req->filter)
        return MI_RESULT_INVALID_PARAMETER;

    // Duplicate incoming request to substitute callback pointer
    msg = SubscribeReq_New(req->base.msgID, req->base.flags);

    msg->base.uid = req->base.uid;
    msg->base.gid = req->base.gid;
    msg->nameSpace = Batch_Zdup(msg->base.batch, req->nameSpace);
    msg->className = Batch_Zdup(msg->base.batch, req->className);
    msg->filter = Batch_Zdup(msg->base.batch, req->filter);
    msg->language = Batch_Zdup(msg->base.batch, req->language);

    msg->base.clientID = req->base.clientID;

    Message_SetRequest(&msg->base, &req->base);

    /* Setup callback */
    msg->base.callback = _ProviderToDispatcherCallback;
    msg->base.callbackData = self;

    // Find a indication context by ns/cn
    Mutex_Lock(&self->mt);

    r = _FindCreateIndCtx( self, msg, &reg );

    Mutex_Unlock(&self->mt);

    /* check if error was detected */
    if (MI_RESULT_OK != r)
        goto sendErrorBack;

    /* empty reg with OK means context is being initialized;
        sub command will be processed later, once EnableIndicaitons is processed */
    if (!reg)
        return MI_RESULT_OK;

    // Send the request to provider manager.
    r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, reg);

    if (r != MI_RESULT_OK)
    {
        LOGD((T("AgentMgr_HandleRequest for namespace: %s"), MI_GET_SAFE_PRINTF_STRING(req->nameSpace)));
        goto sendErrorBack;
    }

    if (msg)
        SubscribeReq_Release(msg);

    return MI_RESULT_OK;

sendErrorBack:
    if (msg)
        SubscribeReq_Release(msg);

    return _SendErrorResponse(&req->base,r);
}

static MI_Result _HandleInvokeReq(
    Disp* self,
    InvokeReq* req)
{
    MI_Result r;
    const ProvRegEntry* reg;
    MI_ConstString cn = 0;

    /* Validate input parameters */
    if (!req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    if (req->className)
        cn = req->className;
    else if (req->instance)
        cn = req->instance->classDecl->name;

    if (!cn)
    {
        r = MI_RESULT_INVALID_CLASS;
        LOGD((T("class name is expected for invoke\n")));
        goto sendErrorBack;
    }


    // Find a provider for this class.
    reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, cn);

    if (!reg)
    {
        r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/
        LOGD((T("cannot find provider for class: %s"), MI_GET_SAFE_PRINTF_STRING(cn)));
        goto sendErrorBack;
    }

    // Send the request to provider manager.
    r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg);

    if (r != MI_RESULT_OK)
    {
        LOGD((T("AgentMgr_HandleRequest for namespace: %s"), MI_GET_SAFE_PRINTF_STRING(req->nameSpace)));
        goto sendErrorBack;
    }

    return MI_RESULT_OK;

sendErrorBack:
    return _SendErrorResponse(&req->base,r);
}


static MI_Result _HandleAssociatorsOfReq(
    Disp* self,
    AssociatorsOfReq* req)
{
    MI_Result r;
    MI_ConstString cn = 0;
    DispResultMsg* dispStateMsg;
    ProvRegAssocPosition pos;
    MI_Boolean sentOk = MI_FALSE;

    /* Validate input parameters */
    if (!req->instance || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    /* create a state message that will keep track of results from providers */
    dispStateMsg = DispResultMsg_New(req->base.msgID);
    if (!dispStateMsg)
        return MI_RESULT_FAILED;

    /* add one for sending thread so first 'fast' provider will not send its response all the way */
    AtomicInc(&dispStateMsg->requestCounter);
    
    dispStateMsg->base.clientID = req->base.clientID;
    /* Setup callback */
    dispStateMsg->base.callback = req->base.callback;
    dispStateMsg->base.callbackData = req->base.callbackData;
    Message_SetRequest(&dispStateMsg->base, &req->base);

    r = ProvReg_BeginAssocClasses(&self->provreg, req->nameSpace, 
        req->instance->classDecl->name,
        req->assocClass, req->resultClass, &pos);

    if (MI_RESULT_OK != r)
    {
        LOGD((T("ProvReg_BeginAssocClasses() failed: %u: %s"), 
            r, Result_ToString(r)));

        /* send error back to caller */
        goto sendErrorBack;
    }

    /* While more classes */
    for (;;)
    {
        MI_Boolean done;
        r = ProvReg_NextAssocClass(&pos, &cn, &done);

        if (done)
            break;

        if (MI_RESULT_OK != r)
        {
            LOGD((T("ProvReg_NextAssocClass() failed: %u: %s"), 
                r, Result_ToString(r)));
            /* send error back to caller */
            goto sendErrorBack;
        }

        if (_DispatchAssocReq(self, cn, req, dispStateMsg))
            sentOk = MI_TRUE;
    }

    /* Finalize enumeration */
    {
        r = ProvReg_EndAssocClasses(&pos);

        if (MI_RESULT_OK != r)
        {
            LOGD((T("ProvReg_EndAssocClasses() failed: %u: %s"), 
                r, Result_ToString(r)));
            /* send error back to caller */
            goto sendErrorBack;
        }
    }

    /* Fail if no provider was found for request */
    if (!sentOk)
    {
        LOGD((T("found no providers for class: %s"), req->instance->classDecl->name));
        r = MI_RESULT_NOT_FOUND;
        goto sendErrorBack;
    }

    if ( AtomicDec(&dispStateMsg->requestCounter) )
    {   /* last result - forward it to the net stack */
        r = dispStateMsg->result;
        goto sendErrorBack;
    }

    DispResultMsg_Release(dispStateMsg);
    return MI_RESULT_OK;

sendErrorBack:
    DispResultMsg_Release(dispStateMsg);
    return _SendErrorResponse(&req->base,r);
}

static MI_Result _HandleReferencesOfReq(
    Disp* self,
    ReferencesOfReq* req)
{
    MI_Result r;
    MI_ConstString cn = 0;
    DispResultMsg* dispStateMsg;
    ProvRegAssocPosition pos;
    MI_Boolean sentOk = MI_FALSE;

    /* Validate input parameters */
    if (!req->instance || !req->nameSpace)
        return MI_RESULT_INVALID_PARAMETER;

    /* create a state message that will keep track of results from providers */
    dispStateMsg = DispResultMsg_New(req->base.msgID);
    if (!dispStateMsg)
        return MI_RESULT_FAILED;

    /* add one for sending thread so first 'fast' provider will not send its response all the way */
    AtomicInc(&dispStateMsg->requestCounter);
    
    dispStateMsg->base.clientID = req->base.clientID;
    /* Setup callback */
    dispStateMsg->base.callback = req->base.callback;
    dispStateMsg->base.callbackData = req->base.callbackData;
    Message_SetRequest(&dispStateMsg->base, &req->base);

    r = ProvReg_BeginAssocClasses(&self->provreg, req->nameSpace, 
        req->instance->classDecl->name,
        req->assocClass, 0, &pos);

    if (MI_RESULT_OK != r)
    {
        LOGD((T("ProvReg_BeginAssocClasses() failed: %u: %s"), 
            r, Result_ToString(r)));

        /* send error back to caller */
        goto sendErrorBack;
    }

    /* While more classes */
    for (;;)
    {
        MI_Boolean done;
        r = ProvReg_NextAssocClass(&pos, &cn, &done);

        if (done)
            break;

        if (MI_RESULT_OK != r)
        {
            LOGD((T("ProvReg_NextAssocClass() failed: %u: %s"), 
                r, Result_ToString(r)));
            /* send error back to caller */
            goto sendErrorBack;
        }

        if (_DispatchRefReq(self, cn, req, dispStateMsg))
            sentOk = MI_TRUE;
    }

    /* Finalize enumeration */
    {
        r = ProvReg_EndAssocClasses(&pos);

        if (MI_RESULT_OK != r)
        {
            LOGD((T("ProvReg_EndAssocClasses() failed: %u: %s"), 
                r, Result_ToString(r)));
            /* send error back to caller */
            goto sendErrorBack;
        }
    }

    /* Fail if no provider was found for request */
    if (!sentOk)
    {
        LOGD((T("found no providers for class: %s"), req->instance->classDecl->name));
        r = MI_RESULT_NOT_FOUND;
        goto sendErrorBack;
    }

    if ( AtomicDec(&dispStateMsg->requestCounter) )
    {   /* last result - forward it to the net stack */
        r = dispStateMsg->result;
        goto sendErrorBack;
    }

    DispResultMsg_Release(dispStateMsg);
    return MI_RESULT_OK;

sendErrorBack:
    DispResultMsg_Release(dispStateMsg);
    return _SendErrorResponse(&req->base,r);
}

/*
**==============================================================================
**
** Public definitions
**
**==============================================================================
*/

MI_Result Disp_Init(Disp* self, Selector* selector)
{
    /* Check parameters */
    if (!self)
        return MI_RESULT_INVALID_PARAMETER;

    memset(self, 0, sizeof(Disp));

#if 0
    /* Initialize the provider registry */
    MI_RETURN_ERR(ProvReg_Init(&self->provreg, GetPath(ID_REGISTERFILE)));
#else
    MI_RETURN_ERR(ProvReg_Init2(&self->provreg));
#endif

    /* Initialize the provider manager */
    MI_RETURN_ERR(AgentMgr_Init(&self->agentmgr, selector));

    /* Initialize indications part */
    MI_RETURN_ERR(Mutex_Init(&self->mt));

    return MI_RESULT_OK;
}

MI_Result Disp_Destroy(Disp* self)
{
    MI_RETURN_ERR(AgentMgr_Destroy(&self->agentmgr));
    ProvReg_Destroy(&self->provreg);

    /*ATTN! remove indication contexts! */
    Mutex_Destroy(&self->mt);
    return MI_RESULT_OK;
}

MI_Result Disp_HandleRequest(
    Disp* self,
    Message* msg)
{
    switch (msg->tag)
    {
        case EnumerateInstancesReqTag:
        {
            EnumerateInstancesReq* req = (EnumerateInstancesReq*)msg;
            return _HandleEnumerateInstancesReq(self, req);
        }

        case GetInstanceReqTag:
        {
            GetInstanceReq* req = (GetInstanceReq*)msg;
            return _HandleGetInstanceReq(self, req);
        }

        case CreateInstanceReqTag:
        {
            CreateInstanceReq* req = (CreateInstanceReq*)msg;
            return _HandleCreateInstanceReq(self, req);
        }

        case ModifyInstanceReqTag:
        {
            ModifyInstanceReq* req = (ModifyInstanceReq*)msg;
            return _HandleModifyInstanceReq(self, req);
        }

        case DeleteInstanceReqTag:
        {
            DeleteInstanceReq* req = (DeleteInstanceReq*)msg;
            return _HandleDeleteInstanceReq(self, req);
        }

        case InvokeReqTag:
        {
            InvokeReq* req = (InvokeReq*)msg;
            return _HandleInvokeReq(self, req);
        }

        case AssociatorsOfReqTag:
        {
            AssociatorsOfReq* req = (AssociatorsOfReq*)msg;
            return _HandleAssociatorsOfReq(self, req);
        }

        case ReferencesOfReqTag:
        {
            ReferencesOfReq* req = (ReferencesOfReq*)msg;
            return _HandleReferencesOfReq(self, req);
        }

        case SubscribeReqTag:
        {
            SubscribeReq* req = (SubscribeReq*)msg;
            return _HandleSubscribeReq(self, req);
        }

        default:
        {
            /* Unsupported mesage type */
            return _SendErrorResponse(msg,MI_RESULT_NOT_SUPPORTED);
        }
    }
}

ViewCVS 0.9.2