/* **============================================================================== ** ** 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 #include #include #include #include #include #include #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, ® ); 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); } } }