version 1.3, 2015/04/20 18:10:11
|
version 1.4, 2015/04/20 18:19:51
|
|
|
**============================================================================== | **============================================================================== |
*/ | */ |
| |
#include <base/strings.h> |
#include <pal/strings.h> |
|
#include <pal/format.h> |
#include <base/messages.h> | #include <base/messages.h> |
|
#include <base/Strand.h> |
#include <base/log.h> | #include <base/log.h> |
#include <base/strings.h> |
|
#include <base/paths.h> | #include <base/paths.h> |
#include <base/io.h> |
#include <pal/hashmap.h> |
#include <base/hashtable.h> |
#include <base/naming.h> |
#include <wql/wql.h> | #include <wql/wql.h> |
#include "disp.h" | #include "disp.h" |
|
#include <omi_error/errorutil.h> |
| |
#define T MI_T |
/* |
|
**============================================================================== |
|
*/ |
|
|
|
#define DISPENUMPARENT_STRANDAUX_ENUMDONE 0 |
|
|
|
STRAND_DEBUGNAME1( DispEnumParent, EnumDone ); |
|
STRAND_DEBUGNAME( DispEnumEntry ); |
| |
/* | /* |
**============================================================================== | **============================================================================== |
|
|
typedef struct _ClassNameBucket /* derives from HashBucket */ | typedef struct _ClassNameBucket /* derives from HashBucket */ |
{ | { |
struct _ClassNameBucket* next; | struct _ClassNameBucket* next; |
char* key; |
ZChar* key; |
} | } |
ClassNameBucket; | ClassNameBucket; |
| |
|
|
/* Note: this algorithm has a poor distribution */ | /* Note: this algorithm has a poor distribution */ |
ClassNameBucket* bucket = (ClassNameBucket*)bucket_; | ClassNameBucket* bucket = (ClassNameBucket*)bucket_; |
size_t h = 0; | size_t h = 0; |
char* key = bucket->key; |
ZChar* key = bucket->key; |
| |
while (*key) | while (*key) |
{ | { |
|
|
{ | { |
ClassNameBucket* bucket1 = (ClassNameBucket*)bucket1_; | ClassNameBucket* bucket1 = (ClassNameBucket*)bucket1_; |
ClassNameBucket* bucket2 = (ClassNameBucket*)bucket2_; | ClassNameBucket* bucket2 = (ClassNameBucket*)bucket2_; |
return Strcasecmp(bucket1->key, bucket2->key) == 0; |
return Tcscasecmp(bucket1->key, bucket2->key) == 0; |
} | } |
| |
static void ClassNameRelease( | static void ClassNameRelease( |
|
|
{ | { |
ClassNameBucket* bucket = (ClassNameBucket*)bucket_; | ClassNameBucket* bucket = (ClassNameBucket*)bucket_; |
| |
free(bucket->key); |
PAL_Free(bucket->key); |
free(bucket); |
PAL_Free(bucket); |
} | } |
| |
/* | /* |
**============================================================================== | **============================================================================== |
** | ** |
** Data structures |
** Local definitions |
** | ** |
**============================================================================== | **============================================================================== |
*/ | */ |
| |
/* |
typedef struct _DispEnumParent |
subscription item - represents single subscription; |
|
*/ |
|
typedef struct _DispSubscriptionItem |
|
{ | { |
struct _DispSubscriptionItem* next; |
StrandMany strand; |
struct _DispSubscriptionItem* prev; |
Disp* disp; |
|
RequestMsg* baseRequest; |
/* The batch this context was allocated from */ |
MI_Result result; |
Batch batch; |
MI_Boolean done; |
|
|
/* filter */ |
|
MI_ConstString filter; |
|
MI_ConstString language; |
|
|
|
/* unique id of the sub */ |
|
MI_Uint64 subscriptionID; |
|
|
|
/* Client identifier if supported */ |
|
MI_Uint64 clientID; |
|
|
|
} | } |
DispSubscriptionItem; |
DispEnumParent; |
| |
|
typedef struct _EnumEntry EnumEntry; |
| |
/* subscriptions context - |
struct _EnumEntry |
used to track indicaiton providers |
|
and store indications for 'pull' operation |
|
one context per ns/cn pair |
|
*/ |
|
typedef struct _DispIndicationContext |
|
{ | { |
struct _DispIndicationContext* next; |
StrandEntry strand; |
struct _DispIndicationContext* prev; |
const ZChar* className; |
|
EnumEntry* next; // Links the entries that are about to be dispatched |
/* The batch this context was allocated from */ |
// We cannot use list on StrandMany as that one can get modify in the meantime |
Batch batch; |
// as the interactions are being dinamically closed themselves |
|
// (that is why that list requires to be in the strand to use it) |
/* namespace/cn */ |
}; |
MI_ConstString nameSpace; |
|
MI_ConstString className; |
MI_INLINE void _DispEnumParent_Delete( |
|
_In_ DispEnumParent* self) |
/* unique id of the context (used by ProvMgr) */ |
{ |
MI_Uint64 ctxID; |
trace_DispDeleteInteraction(self); |
|
Message_Release( &self->baseRequest->base ); |
/* provider info */ |
StrandMany_Delete(&self->strand); |
const ProvRegEntry* provEntry; |
} |
|
|
/* exisitng subscriptions */ |
// interaction is already opened, we can have left the Strand or not indicated by leftStrand |
DispSubscriptionItem* headSubscriptions; |
static void _SendErrorResponse_Opened( |
DispSubscriptionItem* tailSubscriptions; |
_Inout_ InteractionOpenParams* interactionParams, |
} |
_In_ DispEnumParent* self, |
DispIndicationContext; |
_In_ MI_Result r, |
|
MI_Boolean leftStrand |
|
) |
/* |
|
**============================================================================== |
|
** |
|
** 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; |
PostResultMsg* openResp = PostResultMsg_NewAndSerialize( &self->baseRequest->base, NULL, NULL, MI_RESULT_TYPE_MI, r); |
| |
while (current) |
if( openResp ) |
{ | { |
if (0 == Zcasecmp(nameSpace, current->nameSpace) && |
if( leftStrand ) |
0 == Zcasecmp(className, current->className)) |
{ |
break; |
StrandMany_SchedulePost( &self->strand, &openResp->base ); |
|
StrandMany_ScheduleClose( &self->strand ); |
current = current->next; |
|
} |
|
return current; |
|
} | } |
|
else |
static DispIndicationContext* _FindIndCtxByID( |
|
Disp* self, |
|
MI_Uint64 id) |
|
{ | { |
DispIndicationContext* current = (DispIndicationContext*)self->headIndCtx; |
Strand_Post( &self->strand.strand, &openResp->base ); |
|
Strand_Close( &self->strand.strand ); |
while (current) |
Strand_Leave( &self->strand.strand ); |
|
} |
|
PostResultMsg_Release(openResp); |
|
} |
|
else |
{ | { |
if (id == current->ctxID) |
// delete the object directly |
break; |
_DispEnumParent_Delete( self ); |
| |
current = current->next; |
interactionParams->msg = NULL; // Null this out since we have already sent an Ack |
|
interactionParams->origin= NULL; // Null this out since we have already left origin strand |
|
Strand_FailOpenWithResult(interactionParams, r, PostResultMsg_NewAndSerialize); |
} | } |
return current; |
|
} | } |
| |
static DispSubscriptionItem* _FindSubscriptionItem( |
static void _DispEnumParent__SendLastResponse( |
DispIndicationContext* ctx, |
_In_ DispEnumParent* interaction |
MI_Uint64 subscriptionID) |
) |
{ | { |
DispSubscriptionItem* item = ctx->headSubscriptions; |
PostResultMsg* resp; |
| |
while (item) |
resp = PostResultMsg_NewAndSerialize(&interaction->baseRequest->base, NULL, NULL, MI_RESULT_TYPE_MI, interaction->result); |
|
if( resp ) |
{ | { |
if (item->subscriptionID == subscriptionID) |
Strand_Post( &interaction->strand.strand, &resp->base ); |
break; |
Message_Release(&resp->base); |
|
|
item = item->next; |
|
} |
|
return item; |
|
} | } |
| |
|
Strand_Close( &interaction->strand.strand ); |
|
} |
| |
static void _DestroySubscriptionItem( |
static void _DispEnumParent_Transport_Post( _In_ Strand* self_, _In_ Message* msg) |
DispSubscriptionItem* item) |
|
{ | { |
Batch_Destroy(&item->batch); |
DEBUG_ASSERT( MI_FALSE ); // we dont expect any additional messages at this point |
} | } |
static void _DestroyIndCtx( |
|
DispIndicationContext* ctx) |
|
{ |
|
DispSubscriptionItem* item = ctx->headSubscriptions; |
|
| |
while (item) |
static void _DispEnumParent_Transport_PostControl( _In_ Strand* self, _In_ Message* msg) |
{ | { |
DispSubscriptionItem* next = item->next; |
DEBUG_ASSERT( MI_FALSE ); // not used yet |
|
|
_DestroySubscriptionItem(item); |
|
item = next; |
|
} | } |
Batch_Destroy(&ctx->batch); |
|
} |
|
|
|
| |
static MI_Result _FindCreateIndCtx( |
static void _DispEnumParent_Transport_Cancel( _In_ Strand* self) |
Disp* self, |
|
SubscribeReq* req, |
|
ProvRegEntry const** reg) |
|
{ | { |
/* look for exisiting first */ |
// not used yet |
DispIndicationContext* ctx = _FindIndCtxByNScn( self, req->nameSpace, req->className ); |
} |
| |
if (!ctx) |
static void _DispEnumParent_Finished( _In_ Strand* self_) |
{ | { |
Batch batch = BATCH_INITIALIZER; |
DispEnumParent* self = (DispEnumParent*)StrandMany_FromStrand(self_); |
|
_DispEnumParent_Delete( self ); |
/* Allocate heap space for message */ |
} |
ctx = (DispIndicationContext*) Batch_GetClear(&batch, sizeof(DispIndicationContext) ); |
|
| |
if (!ctx) |
//DISPENUMPARENT_STRANDAUX_ENUMDONE |
return MI_RESULT_FAILED; |
static void _DispEnumParent_EnumDone( _In_ Strand* self_) |
|
{ |
|
DispEnumParent* self = (DispEnumParent*)StrandMany_FromStrand(self_); |
| |
/* Copy batch into context (released by _Destroy method) */ |
trace_DispEnumDone(self, self->strand.numEntries, self->result ); |
memcpy(&ctx->batch, &batch, sizeof(batch)); |
|
| |
ctx->className = Batch_Zdup(&batch, req->className); |
self->done = MI_TRUE; |
ctx->nameSpace = Batch_Zdup(&batch, req->nameSpace); |
|
| |
if (!ctx->className || !ctx->nameSpace) |
if( 0 == self->strand.numEntries ) |
{ | { |
_DestroyIndCtx(ctx); |
_DispEnumParent__SendLastResponse( self ); |
return MI_RESULT_FAILED; |
} |
} | } |
ctx->ctxID = ++self->nextID; |
|
| |
/* Look for provider info */ |
/* |
ctx->provEntry = ProvReg_FindProviderForClass(&self->provreg, |
This object manages a a "Parent" enumeration on the dispatcher level. |
req->nameSpace, req->className); |
Enumerations in this context include also Associations and References. |
|
The dispatcher converts that parent enumertion coming from the client |
|
into several actual child enumerations that can go to the same or different providers |
|
for each of those child enumerations a "EnumEntry" object (see more info below) will be |
|
created and attached to this Parent enumeration using the one-to-many |
|
strand interface (StrandMany). |
|
|
|
Behavior: |
|
- Post and PostControl are not used yet as no secondary messages after |
|
initial request are issued currently |
|
- Cancel is also not implememented as Cancelation e2e is not implemented |
|
- Shutdown: |
|
once all the child enumerations have been issued DISPENUMPARENT_STRANDAUX_ENUMDONE |
|
is scheduled on the parent, what in turn set the done flag to true and sends the last response |
|
(final result) to the transport. That would happen if all the enumerations ran in the same thread |
|
as by that point all of them would have completed. However if one or more enumerations |
|
are run in the own thread (by the provider or out-of-proc) then may not be completed |
|
at that point and then the sending of last response and shutdown will occur once |
|
the last enumeration is closed and deleted and the parent is notified on |
|
_DispEnumParent_Entry_Deleted (implemented below on the internal FT) |
|
|
|
Internal interface and unique features: |
|
- When a message is sent internally (from EnumEntry) it is just sent pass |
|
thru to the transport EXCEPT if it is a PostResultMsg as in that case the result |
|
is just stored internally (if it is not success) as we are only returning one single |
|
result to the parent interaction (managed on _DispEnumParent_Entry_Post below) |
|
*/ |
|
static StrandFT _DispEnumParent_TransportFT = { |
|
_DispEnumParent_Transport_Post, |
|
_DispEnumParent_Transport_PostControl, |
|
NULL, |
|
_DispEnumParent_Transport_Cancel, |
|
NULL, |
|
_DispEnumParent_Finished, |
|
NULL, |
|
_DispEnumParent_EnumDone, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL }; |
|
|
|
static void _DispEnumEntry_Provider_PostControl( _In_ Strand* self, _In_ Message* msg) |
|
{ |
|
DEBUG_ASSERT( MI_FALSE ); // not used yet |
|
} |
| |
if (!ctx->provEntry) |
static void _DispEnumEntry_Provider_Close( _In_ Strand* self ) |
|
{ |
|
if(!self->info.thisClosedOther) |
{ | { |
_DestroyIndCtx(ctx); |
// Just close back |
return MI_RESULT_INVALID_NAMESPACE; |
Strand_Close( self ); |
} | } |
|
|
/* add context to the list */ |
|
List_Append(&self->headIndCtx, &self->tailIndCtx, (ListElem*)ctx); |
|
} | } |
| |
/* Update request with correct IDs */ |
/* |
req->ctxID = ctx->ctxID; |
This object manages the interaction wich each particular provider enumeration |
req->subscriptionID = ++self->nextID; |
that a parent provider is divided into (see more info above on _DispEnumParent_TransportFT) |
|
|
/* Set out parameter */ |
|
*reg = ctx->provEntry; |
|
| |
return MI_RESULT_OK; |
Behavior: |
} |
- PostControl is not used yet |
|
- Posts are just passed pass thru (and acks are managed by StrandMany) |
|
- Shutdown: once the provider side closes the interaction this object closes the |
|
interaction back what will trigger automatically deletion of the object |
|
*/ |
|
static StrandFT _DispEnumEntry_ProviderFT = { |
|
NULL, |
|
_DispEnumEntry_Provider_PostControl, |
|
NULL, |
|
NULL, |
|
_DispEnumEntry_Provider_Close, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL }; |
| |
static MI_Result _UpdateIndicationCtxWithSub( |
static void _DispEnumParent_Entry_Deleted( _In_ StrandMany* self_ ) |
Disp* self, |
|
SubscribeReq* dispReq) |
|
{ | { |
DispIndicationContext* ctx; |
DispEnumParent* self = (DispEnumParent*)self_; |
DispSubscriptionItem* subItem; |
|
|
|
ctx = _FindIndCtxByID( self, dispReq->ctxID ); |
|
| |
/* unlikely, but it can be removed by other operation */ |
DEBUG_ASSERT( NULL != self ); |
if (!ctx) |
|
return MI_RESULT_FAILED; |
|
|
|
/* */ |
|
subItem = _FindSubscriptionItem(ctx, dispReq->subscriptionID); |
|
| |
if (subItem) |
trace_DispEntryDeleted(self, self->strand.numEntries, self->done ); |
return MI_RESULT_ALREADY_EXISTS; |
|
| |
|
if( self->done && 0 == self->strand.numEntries ) |
{ | { |
Batch batch = BATCH_INITIALIZER; |
_DispEnumParent__SendLastResponse( self ); |
|
} |
|
} |
| |
/* Allocate heap space for message */ |
static void _DispEnumParent_Entry_Post( _In_ StrandMany* self_, _In_ Message* msg) |
subItem = (DispSubscriptionItem*) Batch_GetClear(&batch, sizeof(DispSubscriptionItem) ); |
{ |
|
DispEnumParent* self = (DispEnumParent*)self_; |
| |
if (!subItem) |
DEBUG_ASSERT( NULL != self ); |
return MI_RESULT_FAILED; |
|
| |
/* Copy batch into context (released by _Destroy method) */ |
trace_DispPostingMessage( self->strand.strand.info.interaction.other, self_); |
memcpy(&subItem->batch, &batch, sizeof(batch)); |
|
| |
subItem->filter = Batch_Zdup(&batch, dispReq->filter); |
if( PostResultMsgTag == msg->tag ) |
subItem->language = Batch_Zdup(&batch, dispReq->language); |
{ |
|
PostResultMsg* rsp = (PostResultMsg*)msg; |
| |
if (!subItem->filter || !subItem->language) |
if( MI_RESULT_OK != rsp->result && MI_RESULT_OK == self->result ) |
{ | { |
_DestroySubscriptionItem(subItem); |
self->result = rsp->result; |
return MI_RESULT_FAILED; |
|
} | } |
subItem->subscriptionID = dispReq->subscriptionID; |
|
subItem->clientID = dispReq->base.request->clientID; |
|
| |
/* add item to the context */ |
// This is not posted here |
List_Append( |
} |
(ListElem**)&ctx->headSubscriptions, |
else |
(ListElem**)&ctx->tailSubscriptions, |
{ |
(ListElem*)subItem); |
Strand_Post( &self->strand.strand, msg ); |
} | } |
|
|
return MI_RESULT_OK; |
|
} | } |
| |
static void _ProcessSubscribeResponse( |
// used for enums, associators, references and subcriptions |
Disp* self, |
static StrandManyInternalFT _DispEnumParent_InternalFT = { |
PostResultMsg* rsp) |
NULL, |
|
_DispEnumParent_Entry_Deleted, |
|
_DispEnumParent_Entry_Post, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL }; |
|
|
|
static MI_Result _DispatchEnumerateInstancesReq( |
|
_In_ Disp* disp, |
|
_In_ EnumerateInstancesReq* request, |
|
_In_ const ZChar* className, |
|
_In_opt_ EnumEntry* enumEntry, |
|
_In_opt_ InteractionOpenParams* interactionParams ) |
{ | { |
MI_Result r; |
const ProvRegEntry* provEntry; |
SubscribeReq* dispReq = (SubscribeReq*)rsp->base.request; |
MI_Result result; |
|
EnumerateInstancesReq* msg; |
|
AgentMgr_OpenCallbackData openCallbackData; |
/* Find context, create subscription struct */ |
|
Mutex_Lock(&self->mt); |
|
| |
r = _UpdateIndicationCtxWithSub( self, dispReq ); |
DEBUG_ASSERT( NULL != className ); |
| |
Mutex_Unlock(&self->mt); |
/* Attempt to find a provider for this class */ |
|
provEntry = ProvReg_FindProviderForClass(&disp->provreg, |
|
request->nameSpace, className, &result ); |
| |
/* check if error was detected */ |
if (!provEntry) |
if (MI_RESULT_OK != r) |
|
{ | { |
_SendErrorResponse(rsp->base.request->request, r); |
return MI_RESULT_NOT_SUPPORTED; |
} | } |
| |
/* send subscription response */ |
/* Create new request to send to provider */ |
|
msg = EnumerateInstancesReq_New(request->base.base.operationId, request->base.base.flags); |
|
if( NULL == msg ) |
{ | { |
SubscribeRes* resp; |
trace_DispatchEnumerateInstancesReq_OutOfMemory(); |
char s[50]; |
return MI_RESULT_SERVER_LIMITS_EXCEEDED; |
|
|
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); |
|
} | } |
| |
} |
msg->base.options = request->base.options; |
|
AuthInfo_Copy( &msg->base.authInfo, &request->base.authInfo ); |
|
msg->nameSpace = Batch_Tcsdup(msg->base.base.batch, request->nameSpace); |
|
msg->className = Batch_Tcsdup(msg->base.base.batch, className); |
|
msg->base.userAgent = request->base.userAgent; |
| |
static void _ProviderToDispatcherCallback( |
if (!msg->nameSpace || !msg->className) |
Message* msg, |
|
void* callbackData) |
|
{ |
|
switch ( msg->tag ) |
|
{ | { |
case PostResultMsgTag: |
goto OutOfMemory; |
{ |
} |
PostResultMsg* rsp = (PostResultMsg*)msg; |
|
| |
if (msg->request && msg->request->request && msg->request->request->tag == DispResultMsgTag) |
/* Clone the query fields (if any) */ |
|
if (request->queryLanguage) |
{ | { |
DispResultMsg* dispStateMsg = (DispResultMsg*)msg->request->request; |
msg->queryLanguage = Batch_Tcsdup(msg->base.base.batch, request->queryLanguage); |
|
if (!msg->queryLanguage) |
if (rsp->result != MI_RESULT_OK && dispStateMsg->result == MI_RESULT_OK) |
|
{ | { |
dispStateMsg->result = rsp->result; |
goto OutOfMemory; |
} | } |
|
|
if ( AtomicDec(&dispStateMsg->requestCounter) ) |
|
{ /* last result - forward it to the net stack */ |
|
rsp->result = dispStateMsg->result; |
|
} | } |
else /* not the last result - skip it */ |
|
return; |
|
| |
} |
if( request->queryExpression ) |
else if (msg->request && msg->request->tag == SubscribeReqTag) |
|
{ | { |
/* process subscription response */ |
msg->queryExpression = Batch_Tcsdup(msg->base.base.batch,request->queryExpression); |
if (MI_RESULT_OK != rsp->result ) |
if (!msg->queryExpression) |
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); |
goto OutOfMemory; |
return; |
|
} |
|
} |
|
} | } |
break; |
|
|
|
default: |
|
break; |
|
} | } |
| |
/* forward message to the other side */ |
/* Save request's class name to allow provmgr pack back only base properties */ |
if (msg->request && msg->request->request) |
if( request->basePropertiesOnly ) |
{ | { |
/* delegate message to protocol stack */ |
msg->requestClassName = Batch_Tcsdup(msg->base.base.batch, request->className); |
msg->clientID = msg->request->request->clientID; |
if (!msg->requestClassName) |
(*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); |
goto OutOfMemory; |
} | } |
} | } |
| |
static MI_Boolean _DispatchEnumerateInstancesReq( |
openCallbackData.self = &disp->agentmgr; |
Disp* self, |
openCallbackData.proventry = provEntry; |
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 */ |
if( NULL != enumEntry ) |
{ | { |
entry = ProvReg_FindProviderForClass(&self->provreg, |
trace_DispatchEnumDispInteraction(tcs(className)); |
req->nameSpace, className); |
|
| |
if (!entry) |
/* Send the request to provider manager */ |
return MI_FALSE; |
Strand_Open( &enumEntry->strand.strand, AgentMgr_OpenCallback, &openCallbackData, &msg->base.base, MI_TRUE ); |
} | } |
|
else |
|
{ |
|
DEBUG_ASSERT( NULL != interactionParams ); |
| |
/* Create new request to send to provider */ |
// send it directly to AgentMgr |
msg = EnumerateInstancesReq_New(req->base.msgID, req->base.flags); |
interactionParams->callbackData = &openCallbackData; |
msg->base.clientID = req->base.clientID; |
interactionParams->msg = &request->base.base; |
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 */ |
trace_DispatchEnumDirectly(tcs(className)); |
msg->base.callback = _ProviderToDispatcherCallback; |
|
msg->base.callbackData = self; |
|
| |
/* Send the request to provider manager */ |
AgentMgr_OpenCallback( interactionParams ); |
r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, entry); |
} |
| |
/* Release the original message */ | /* Release the original message */ |
EnumerateInstancesReq_Release(msg); | EnumerateInstancesReq_Release(msg); |
| |
/* Log failure */ |
return MI_RESULT_OK; |
if (r != MI_RESULT_OK) |
|
{ |
|
LOGW((T("AgentMgr_HandleRequest() failed: %u: %s"), r, |
|
Result_ToString(r))); |
|
|
|
AtomicDec(&dispStateMsg->requestCounter); |
|
return MI_FALSE; |
|
} |
|
| |
|
OutOfMemory: |
|
trace_DispatchEnumerateInstancesReq_OutOfMemory(); |
|
EnumerateInstancesReq_Release(msg); |
| |
return MI_TRUE; |
return MI_RESULT_SERVER_LIMITS_EXCEEDED; |
} | } |
| |
|
// Also used for References |
static MI_Boolean _DispatchAssocReq( | static MI_Boolean _DispatchAssocReq( |
Disp* self, |
_In_ Disp* disp, |
const MI_Char* className, |
_In_ AssociationsOfReq* req, |
const AssociatorsOfReq* req, |
_In_ EnumEntry* enumEntry, |
DispResultMsg* dispStateMsg) |
MessageTag tag ) |
{ | { |
const ProvRegEntry* entry; | const ProvRegEntry* entry; |
AssociatorsOfReq* msg; |
AssociationsOfReq* msg; |
MI_Result r; |
const ZChar* className = enumEntry->className; |
|
MI_Result result; |
|
AgentMgr_OpenCallbackData openCallbackData; |
| |
/* Attempt to find a provider for this class */ | /* Attempt to find a provider for this class */ |
{ |
entry = ProvReg_FindProviderForClass(&disp->provreg, |
entry = ProvReg_FindProviderForClass(&self->provreg, |
req->nameSpace, className, &result ); |
req->nameSpace, className); |
|
| |
if (!entry) | if (!entry) |
|
{ |
|
trace__DispatchAssocReq_OutOfMemory(); |
return MI_FALSE; | return MI_FALSE; |
} | } |
| |
/* Create new request to send to provider */ | /* Create new request to send to provider */ |
msg = AssociatorsOfReq_New(req->base.msgID, req->base.flags); |
msg = AssociationsOfReq_New(req->base.base.operationId, req->base.base.flags, tag); |
msg->base.clientID = req->base.clientID; |
msg->base.options = req->base.options; |
msg->base.uid = req->base.uid; |
AuthInfo_Copy( &msg->base.authInfo, &req->base.authInfo ); |
msg->base.gid = req->base.gid; |
|
/* original request will be kept for the request duration, so perform shallow copy only */ | /* original request will be kept for the request duration, so perform shallow copy only */ |
/*ATTN! perform full copy*/ |
|
msg->nameSpace = req->nameSpace; | msg->nameSpace = req->nameSpace; |
msg->assocClass = req->assocClass; | msg->assocClass = req->assocClass; |
msg->resultClass = req->resultClass; | msg->resultClass = req->resultClass; |
|
|
msg->instance = req->instance; | msg->instance = req->instance; |
msg->packedInstancePtr = req->packedInstancePtr; | msg->packedInstancePtr = req->packedInstancePtr; |
msg->packedInstanceSize = req->packedInstanceSize; | msg->packedInstanceSize = req->packedInstanceSize; |
|
msg->base.userAgent = req->base.userAgent; |
| |
msg->className = className; |
msg->className = Batch_Tcsdup(msg->base.base.batch, className); |
| |
AtomicInc(&dispStateMsg->requestCounter); |
trace_DispatchAssoc(tcs(className)); |
Message_SetRequest(&msg->base, &dispStateMsg->base); |
|
|
|
/* Setup callback */ |
|
msg->base.callback = _ProviderToDispatcherCallback; |
|
msg->base.callbackData = self; |
|
| |
/* Send the request to provider manager */ | /* Send the request to provider manager */ |
r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, entry); |
openCallbackData.self = &disp->agentmgr; |
|
openCallbackData.proventry = entry; |
|
Strand_Open( &enumEntry->strand.strand, AgentMgr_OpenCallback, &openCallbackData, &msg->base.base, MI_TRUE ); |
| |
/* Release the original message */ | /* Release the original message */ |
AssociatorsOfReq_Release(msg); |
AssociationsOfReq_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; | return MI_TRUE; |
} | } |
| |
static MI_Boolean _DispatchRefReq( |
DispEnumParent* _DispEnumParent_New( |
Disp* self, |
_In_ Disp* disp, |
const MI_Char* className, |
_In_ InteractionOpenParams* interactionParams ) |
const ReferencesOfReq* req, |
|
DispResultMsg* dispStateMsg) |
|
{ | { |
const ProvRegEntry* entry; |
DispEnumParent* self; |
ReferencesOfReq* msg; |
|
MI_Result r; |
|
| |
/* Attempt to find a provider for this class */ |
self = (DispEnumParent*)StrandMany_New( |
|
STRAND_DEBUG( DispEnumParent ) |
|
&_DispEnumParent_TransportFT, |
|
&_DispEnumParent_InternalFT, |
|
sizeof( DispEnumParent ), |
|
STRAND_FLAG_ENTERSTRAND, |
|
interactionParams, |
|
1, |
|
NULL, |
|
NULL, |
|
NULL); |
|
|
|
if(self) |
{ | { |
entry = ProvReg_FindProviderForClass(&self->provreg, |
RequestMsg* req = (RequestMsg*)interactionParams->msg; |
req->nameSpace, className); |
DEBUG_ASSERT( NULL != req ); |
| |
if (!entry) |
Message_AddRef( &req->base ); |
return MI_FALSE; |
self->baseRequest = req; |
} |
|
| |
/* Create new request to send to provider */ |
self->disp = disp; |
msg = ReferencesOfReq_New(req->base.msgID, req->base.flags); |
self->result = MI_RESULT_OK; |
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; |
// As soon as we accept the open we can send the open msg ack |
|
Strand_Ack( &self->strand.strand ); |
|
} |
| |
AtomicInc(&dispStateMsg->requestCounter); |
return self; |
Message_SetRequest(&msg->base, &dispStateMsg->base); |
} |
| |
/* Setup callback */ |
static MI_Result _HandleGetInstanceReq( |
msg->base.callback = _ProviderToDispatcherCallback; |
_In_ Disp* self, |
msg->base.callbackData = self; |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ GetInstanceReq* req) |
|
{ |
|
MI_Result r; |
|
const ProvRegEntry* reg; |
| |
/* Send the request to provider manager */ |
/* Validate input parameters */ |
r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, entry); |
if (!req->instanceName || !req->nameSpace) |
|
return MI_RESULT_INVALID_PARAMETER; |
| |
/* Release the original message */ |
// Find a provider for this class. |
ReferencesOfReq_Release(msg); |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
|
req->instanceName->classDecl->name, &r ); |
| |
/* Log failure */ |
if (!reg) |
if (r != MI_RESULT_OK) |
|
{ | { |
LOGW((T("AgentMgr_HandleRequest() failed: %u: %s"), r, |
trace_NoProviderForClass( |
Result_ToString(r))); |
req->nameSpace, |
|
req->instanceName->classDecl->name); |
AtomicDec(&dispStateMsg->requestCounter); |
goto sendErrorBack; |
return MI_FALSE; |
|
} | } |
| |
return MI_TRUE; |
// Send the request to provider manager. |
} |
r = AgentMgr_HandleRequest(&self->agentmgr, interactionParams, reg); |
| |
static MI_Result _SendErrorResponse( |
if (r != MI_RESULT_OK) |
Message* req, |
|
MI_Result r |
|
) |
|
{ | { |
PostResultMsg* resp; |
trace_AgentMgrHandleRequestForNS( |
|
req->nameSpace); |
resp = PostResultMsg_New( req->msgID ); |
goto sendErrorBack; |
|
} |
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; | return MI_RESULT_OK; |
|
|
|
sendErrorBack: |
|
// Just abort creating any interaction at all |
|
return r; |
} | } |
| |
static MI_Result _HandleEnumerateInstancesReq( |
static MI_Result _HandleGetClassReq( |
Disp* self, |
_In_ Disp* self, |
EnumerateInstancesReq* req) |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ GetClassReq* req) |
{ | { |
ProvRegPosition pos; |
|
MI_Result r; | MI_Result r; |
MI_Boolean sentOk = MI_FALSE; |
const ProvRegEntry* reg; |
DispResultMsg* dispStateMsg; |
ProvRegEntry freg; |
|
ProvRegPosition pos; |
| |
/* Validate input parameters */ | /* Validate input parameters */ |
if (!req->className || !req->nameSpace) | if (!req->className || !req->nameSpace) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
/* create a state message that will keep track of results from providers */ |
// client must specify classname for GetClass request |
dispStateMsg = DispResultMsg_New(req->base.msgID); |
if(Tcscmp(req->className, PAL_T("*")) == 0) |
if (!dispStateMsg) |
return MI_RESULT_INVALID_CLASS; |
return MI_RESULT_FAILED; |
|
| |
/* add one for sending thread so first 'fast' provider will not send its response all the way */ |
memset( &freg, 0, sizeof(freg) ); |
AtomicInc(&dispStateMsg->requestCounter); |
|
| |
dispStateMsg->base.clientID = req->base.clientID; |
// Find a provider for this class. |
/* Setup callback */ |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
dispStateMsg->base.callback = req->base.callback; |
req->className, &r ); |
dispStateMsg->base.callbackData = req->base.callbackData; |
|
| |
/* Precompile the query */ |
if (!reg) |
if (req->queryLanguage || req->queryExpression) |
|
{ | { |
/* Fail if either query language or expression is missing */ |
if(MI_RESULT_INVALID_CLASS == r) |
if (!req->queryLanguage || !req->queryExpression) |
|
{ | { |
LOGW((T("queryLanguage or queryExpression is missing"))); |
/* Checking if the requested class is a base class of an implemented class */ |
r = MI_RESULT_INVALID_QUERY; |
r = ProvReg_BeginClasses(&self->provreg, req->nameSpace, |
goto sendErrorBack; |
req->className, MI_TRUE, &pos, MI_FALSE); |
} |
|
| |
/* Reject non-WQL queries */ |
if(MI_RESULT_INVALID_CLASS == r) |
if (Zcmp(req->queryLanguage, T("WQL")) != 0) |
|
{ | { |
LOGW((T("unknown query language: %s"), req->queryLanguage)); |
/* Checking if the requested class is an extraclass (Class without key property or Class with key property but not part of any |
r = MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED; |
class heirarchy of an implemented class.) |
goto sendErrorBack; |
Class with valid providerFT is called as an implemented class */ |
} |
|
| |
/* Compile the query */ |
/* In extra classes inheritance tree a namespace node is created only if there is at least one extra class in the namespace. |
{ |
So namespace node need not exist in extra classes inheritance tree even for valid namespace */ |
req->wql = WQL_Parse(req->queryExpression, req->base.batch); |
r = ProvReg_BeginClasses(&self->provreg, req->nameSpace, |
|
req->className, MI_TRUE, &pos, MI_TRUE); |
| |
if (!req->wql) |
if(MI_RESULT_INVALID_NAMESPACE == r) |
{ |
r = MI_RESULT_INVALID_CLASS; |
LOGW((T("invalid query expression: %s"), req->queryExpression)); |
|
r = MI_RESULT_INVALID_QUERY; |
|
goto sendErrorBack; |
|
} |
|
} | } |
|
if (MI_RESULT_OK == r) |
/* 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"), |
DEBUG_ASSERT(pos.start != NULL); |
req->className, req->className)); |
MapRegPositionValuesToRegEntry(&freg, &pos); |
r = MI_RESULT_INVALID_QUERY; |
freg.nameSpace = req->nameSpace; |
goto sendErrorBack; |
freg.nameSpaceHash = Hash(req->nameSpace); |
} | } |
} | } |
| |
/* 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) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_BeginClasses() failed: %u: %s"), |
trace_NoProviderForClass( |
r, Result_ToString(r))); |
req->nameSpace, |
|
req->className); |
LOGI((T("unknown class in enumerate request: %s:%s"), |
|
req->nameSpace, req->className)); |
|
|
|
/* send error back to caller */ |
|
goto sendErrorBack; | goto sendErrorBack; |
} | } |
} | } |
|
else |
/* While more classes */ |
|
for (;;) |
|
{ | { |
const MI_Char* derived = NULL; |
freg = *reg; |
MI_Boolean done; |
} |
|
|
r = ProvReg_NextClass(&pos, &derived, &done); |
|
| |
if (done) |
// Send the request to provider manager. |
break; |
r = AgentMgr_HandleRequest(&self->agentmgr, interactionParams, &freg); |
| |
if (MI_RESULT_OK != r) |
if (r != MI_RESULT_OK) |
{ | { |
LOGD((T("ProvReg_NextClass() failed: %u: %s"), |
trace_AgentMgrHandleRequestForNS( |
r, Result_ToString(r))); |
req->nameSpace); |
|
|
LOGI((T("unknown class in enumerate request: %s:%s"), |
|
req->nameSpace, req->className)); |
|
|
|
/* send error back to caller */ |
|
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
if (_DispatchEnumerateInstancesReq(self, derived, req, dispStateMsg)) |
return MI_RESULT_OK; |
sentOk = MI_TRUE; |
|
|
sendErrorBack: |
|
// Just abort creating any interaction at all |
|
return r; |
} | } |
| |
/* Finalize enumeration */ |
static MI_Result _HandleCreateInstanceReq( |
|
_In_ Disp* self, |
|
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ CreateInstanceReq* req) |
{ | { |
r = ProvReg_EndClasses(&pos); |
MI_Result r; |
|
const ProvRegEntry* reg; |
| |
if (MI_RESULT_OK != r) |
/* Validate input parameters */ |
{ |
if (!req->instance || !req->nameSpace) |
LOGD((T("ProvReg_EndClasses() failed: %u: %s"), |
return MI_RESULT_INVALID_PARAMETER; |
r, Result_ToString(r))); |
|
/* send error back to caller */ |
|
goto sendErrorBack; |
|
} |
|
} |
|
} /* if deep*/ |
|
| |
/* Fail if no provider was found for request */ |
// Find a provider for this class. |
if (!sentOk) |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
|
req->instance->classDecl->name, &r ); |
|
|
|
if (!reg) |
{ | { |
LOGD((T("found no providers for class: %s"), MI_GET_SAFE_PRINTF_STRING(req->className))); |
trace_NoProviderForClass( |
r = MI_RESULT_NOT_FOUND; |
req->nameSpace, |
|
req->instance->classDecl->name); |
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
if ( AtomicDec(&dispStateMsg->requestCounter) ) |
// Send the request to provider manager. |
{ /* last result - forward it to the net stack */ |
r = AgentMgr_HandleRequest(&self->agentmgr, interactionParams, reg); |
r = dispStateMsg->result; |
|
|
if (r != MI_RESULT_OK) |
|
{ |
|
trace_AgentMgrHandleRequestForNS( |
|
req->nameSpace); |
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
DispResultMsg_Release(dispStateMsg); |
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
| |
sendErrorBack: | sendErrorBack: |
DispResultMsg_Release(dispStateMsg); |
// Just abort creating any interaction at all |
return _SendErrorResponse(&req->base,r); |
return r; |
} | } |
| |
|
static MI_Result _HandleModifyInstanceReq( |
static MI_Result _HandleGetInstanceReq( |
_In_ Disp* self, |
Disp* self, |
_Inout_ InteractionOpenParams* interactionParams, |
GetInstanceReq* req) |
_In_ ModifyInstanceReq* req) |
{ | { |
MI_Result r; | MI_Result r; |
const ProvRegEntry* reg; | const ProvRegEntry* reg; |
| |
/* Validate input parameters */ | /* Validate input parameters */ |
if (!req->instanceName || !req->nameSpace) |
if (!req->instance || !req->nameSpace) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
// Find a provider for this class. | // Find a provider for this class. |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, | reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
req->instanceName->classDecl->name ); |
req->instance->classDecl->name, &r ); |
| |
if (!reg) | if (!reg) |
{ | { |
r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/ |
trace_NoProviderForClass( |
LOGD((T("cannot find provider for class: %s/%s"), |
req->nameSpace, |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace), |
req->instance->classDecl->name); |
MI_GET_SAFE_PRINTF_STRING(req->instanceName->classDecl->name))); |
|
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
// Send the request to provider manager. | // Send the request to provider manager. |
r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg); |
r = AgentMgr_HandleRequest(&self->agentmgr, interactionParams, reg); |
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
{ | { |
LOGD((T("AgentMgr_HandleRequest for namespace: %s"), |
trace_AgentMgrHandleRequestForNS( |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace))); |
req->nameSpace); |
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
| |
sendErrorBack: | sendErrorBack: |
return _SendErrorResponse(&req->base,r); |
// Just abort creating any interaction at all |
|
return r; |
} | } |
| |
static MI_Result _HandleCreateInstanceReq( |
static MI_Result _HandleDeleteInstanceReq( |
Disp* self, |
_In_ Disp* self, |
CreateInstanceReq* req) |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ DeleteInstanceReq* req) |
{ | { |
MI_Result r; | MI_Result r; |
const ProvRegEntry* reg; | const ProvRegEntry* reg; |
| |
/* Validate input parameters */ | /* Validate input parameters */ |
if (!req->instance || !req->nameSpace) |
if (!req->instanceName || !req->nameSpace) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
// Find a provider for this class. | // Find a provider for this class. |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, | reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
req->instance->classDecl->name ); |
req->instanceName->classDecl->name, &r); |
| |
if (!reg) | if (!reg) |
{ | { |
r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/ |
trace_NoProviderForClass( |
LOGD((T("cannot find provider for class: %s/%s"), |
req->nameSpace, |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace), |
req->instanceName->classDecl->name); |
MI_GET_SAFE_PRINTF_STRING(req->instance->classDecl->name))); |
|
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
// Send the request to provider manager. | // Send the request to provider manager. |
r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg); |
r = AgentMgr_HandleRequest(&self->agentmgr, interactionParams, reg); |
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
{ | { |
LOGD((T("AgentMgr_HandleRequest for namespace: %s"), |
trace_AgentMgrHandleRequestForNS( |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace))); |
req->nameSpace); |
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
| |
sendErrorBack: | sendErrorBack: |
return _SendErrorResponse(&req->base,r); |
// Just abort creating any interaction at all |
|
return r; |
} | } |
| |
static MI_Result _HandleModifyInstanceReq( |
static MI_Result _HandleInvokeReq( |
Disp* self, |
_In_ Disp* self, |
ModifyInstanceReq* req) |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ InvokeReq* req) |
{ | { |
MI_Result r; | MI_Result r; |
const ProvRegEntry* reg; | 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; |
|
trace_ClassNameIsExpectedForInvoke(); |
|
goto sendErrorBack; |
|
} |
| |
/* Validate input parameters */ |
|
if (!req->instance || !req->nameSpace) |
|
return MI_RESULT_INVALID_PARAMETER; |
|
| |
// Find a provider for this class. | // Find a provider for this class. |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, cn, &r); |
req->instance->classDecl->name ); |
|
| |
if (!reg) | if (!reg) |
{ | { |
r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/ |
trace_FoundNoProvider( |
LOGD((T("cannot find provider for class: %s/%s"), |
cn); |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace), |
|
MI_GET_SAFE_PRINTF_STRING(req->instance->classDecl->name))); |
|
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
// Send the request to provider manager. | // Send the request to provider manager. |
r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg); |
r = AgentMgr_HandleRequest(&self->agentmgr, interactionParams, reg); |
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
{ | { |
LOGD((T("AgentMgr_HandleRequest for namespace: %s"), |
trace_AgentMgrHandleRequestForNS( |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace))); |
req->nameSpace); |
goto sendErrorBack; | goto sendErrorBack; |
} | } |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
| |
sendErrorBack: | sendErrorBack: |
return _SendErrorResponse(&req->base,r); |
// Just abort creating any interaction at all |
|
return r; |
} | } |
| |
static MI_Result _HandleDeleteInstanceReq( |
static MI_Result _HandleEnumerateInstancesReq( |
Disp* self, |
_In_ Disp* self, |
DeleteInstanceReq* req) |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ EnumerateInstancesReq* req) |
{ | { |
MI_Result r; |
MI_Result r = MI_RESULT_FAILED; |
const ProvRegEntry* reg; |
MI_Boolean sentOk = MI_FALSE; |
|
WQL_Dialect dialect; |
|
DispEnumParent* enumInteraction; |
|
EnumEntry* enumEntry; |
|
EnumEntry* enumEntryHead = NULL; |
| |
/* Validate input parameters */ | /* Validate input parameters */ |
if (!req->instanceName || !req->nameSpace) |
if (!req->nameSpace) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
// Find a provider for this class. |
/* Precompile the query */ |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, |
if (req->queryLanguage || req->queryExpression) |
req->instanceName->classDecl->name); |
{ |
|
/* Fail if either query language or expression is missing */ |
|
if (!req->queryLanguage || !req->queryExpression) |
|
{ |
|
trace_QueryLanguageOrExpressionMissing(); |
|
return MI_RESULT_INVALID_QUERY; |
|
} |
| |
if (!reg) |
/* Reject non-WQL queries */ |
|
if (Tcscasecmp(req->queryLanguage, MI_QUERY_DIALECT_WQL) == 0) |
{ | { |
r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/ |
dialect = WQL_DIALECT_WQL; |
LOGD((T("cannot find provider for class: %s/%s"), |
} |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace), |
else if (Tcscasecmp(req->queryLanguage, MI_QUERY_DIALECT_CQL) == 0) |
MI_GET_SAFE_PRINTF_STRING(req->instanceName->classDecl->name))); |
{ |
goto sendErrorBack; |
dialect = WQL_DIALECT_CQL; |
|
} |
|
else |
|
{ |
|
trace_UnsupportedQueryLanguage(tcs(req->queryLanguage)); |
|
return MI_RESULT_QUERY_LANGUAGE_NOT_SUPPORTED; |
} | } |
| |
// Send the request to provider manager. |
/* Compile the query */ |
r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg); |
{ |
|
req->wql = WQL_Parse(req->queryExpression, req->base.base.batch, |
|
dialect); |
| |
if (r != MI_RESULT_OK) |
if (!req->wql) |
{ | { |
LOGD((T("AgentMgr_HandleRequest for namespace: %s"), |
trace_InvalidQueryExpression(tcs(req->queryExpression)); |
MI_GET_SAFE_PRINTF_STRING(req->nameSpace))); |
return MI_RESULT_INVALID_QUERY; |
goto sendErrorBack; |
} |
} | } |
| |
return MI_RESULT_OK; |
/* WQL queries from WinRM pass '*' as the class name */ |
| |
sendErrorBack: |
if (!req->className || (Tcscmp(req->className, PAL_T("*")) == 0)) |
return _SendErrorResponse(&req->base,r); |
{ |
|
req->className = req->wql->className; |
} | } |
| |
static MI_Result _HandleSubscribeReq( |
/* Verify that the query classname matches the enumeration classname */ |
Disp* self, |
if (Tcscmp(req->wql->className, req->className) != 0) |
SubscribeReq* req) |
|
{ | { |
MI_Result r; |
trace_QueryEnumClassnameMismatch( |
const ProvRegEntry* reg = 0; |
tcs(req->wql->className), tcs(req->className)); |
SubscribeReq* msg = 0; |
return MI_RESULT_INVALID_QUERY; |
|
} |
/* Validate input parameters */ |
} |
if (!req->className || !req->nameSpace || !req->language || !req->filter) |
else if (!req->className) |
|
{ |
|
trace_EnumHasNoClassname(); |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
|
} |
| |
// Duplicate incoming request to substitute callback pointer |
if (req->deepInheritance) |
msg = SubscribeReq_New(req->base.msgID, req->base.flags); |
{ |
|
ProvRegPosition pos; |
msg->base.uid = req->base.uid; |
EnumEntry* enumEntryPrev; |
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; |
/* create the interaction that will keep track of results from providers */ |
|
enumInteraction = _DispEnumParent_New( |
|
self, |
|
interactionParams); |
|
if (!enumInteraction) |
|
{ |
|
trace_Disp_ErrorInteractionAlloc(); |
|
return MI_RESULT_FAILED; |
|
} |
| |
Message_SetRequest(&msg->base, &req->base); |
/* Send to direct name */ |
|
/* Start by sending to direct name */ |
|
enumEntry = (EnumEntry*)StrandEntry_New( STRAND_DEBUG( DispEnumEntry ) |
|
&enumInteraction->strand, |
|
&_DispEnumEntry_ProviderFT, |
|
sizeof(EnumEntry), |
|
STRAND_FLAG_ENTERSTRAND, |
|
NULL); |
|
if( NULL == enumEntry ) |
|
{ |
|
trace_Disp_ErrorEnumEntryAlloc(); |
|
goto sendErrorBack_Opened; |
|
} |
|
r = StrandMany_AddEntry( &enumEntry->strand ); |
|
if( MI_RESULT_OK != r ) |
|
{ |
|
StrandEntry_DeleteNoAdded( &enumEntry->strand ); |
|
goto sendErrorBack_Opened; |
|
} |
|
enumEntry->className = req->className; |
|
enumEntryHead = enumEntry; |
|
enumEntryPrev = enumEntry; |
| |
/* Setup callback */ |
/* Begin enumeration of classes for this request */ |
msg->base.callback = _ProviderToDispatcherCallback; |
{ |
msg->base.callbackData = self; |
r = ProvReg_BeginClasses(&self->provreg, req->nameSpace, |
|
req->className, MI_TRUE, &pos, MI_FALSE); |
| |
// Find a indication context by ns/cn |
if (MI_RESULT_OK != r) |
Mutex_Lock(&self->mt); |
{ |
|
{ |
|
/* Checking if the class is in extra classes to return appropriate error */ |
|
MI_Result result; |
|
result = ProvReg_BeginClasses(&self->provreg, req->nameSpace, |
|
req->className, MI_TRUE, &pos, MI_TRUE); |
|
if(MI_RESULT_OK == result) |
|
{ |
|
ProvReg_EndClasses(&pos); |
|
r = MI_RESULT_NOT_SUPPORTED; |
|
goto sendErrorBack_Opened; |
|
} |
|
} |
|
trace_ProvReg_BeginClasses_Failed( |
|
r, tcs(Result_ToString(r))); |
| |
r = _FindCreateIndCtx( self, msg, ® ); |
trace_DispEnum_UnknownClass( |
|
tcs(req->nameSpace), tcs(req->className)); |
| |
Mutex_Unlock(&self->mt); |
/* send error back to caller */ |
|
goto sendErrorBack_Opened; |
|
} |
|
} |
| |
/* check if error was detected */ |
/* While more classes */ |
if (MI_RESULT_OK != r) |
for (;;) |
goto sendErrorBack; |
{ |
|
const ZChar* derived = NULL; |
|
MI_Boolean done; |
| |
/* empty reg with OK means context is being initialized; |
r = ProvReg_NextClass(&pos, &derived, &done); |
sub command will be processed later, once EnableIndicaitons is processed */ |
|
if (!reg) |
|
return MI_RESULT_OK; |
|
| |
// Send the request to provider manager. |
if (done) |
r = AgentMgr_HandleRequest(&self->agentmgr, &msg->base, reg); |
break; |
| |
if (r != MI_RESULT_OK) |
if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("AgentMgr_HandleRequest for namespace: %s"), MI_GET_SAFE_PRINTF_STRING(req->nameSpace))); |
trace_ProvReg_NextClass_Failed( |
goto sendErrorBack; |
r, tcs(Result_ToString(r))); |
} |
|
|
|
if (msg) |
|
SubscribeReq_Release(msg); |
|
| |
return MI_RESULT_OK; |
trace_DispEnum_UnknownClass( |
|
tcs(req->nameSpace), tcs(req->className)); |
| |
sendErrorBack: |
/* send error back to caller */ |
if (msg) |
goto sendErrorBack_Opened; |
SubscribeReq_Release(msg); |
} |
| |
return _SendErrorResponse(&req->base,r); |
enumEntry = (EnumEntry*)StrandEntry_New( STRAND_DEBUG( DispEnumEntry ) |
|
&enumInteraction->strand, |
|
&_DispEnumEntry_ProviderFT, |
|
sizeof(EnumEntry), |
|
STRAND_FLAG_ENTERSTRAND, |
|
NULL); |
|
if( NULL == enumEntry ) |
|
{ |
|
trace_Disp_ErrorEnumEntryAlloc(); |
|
goto sendErrorBack_Opened; |
} | } |
| |
static MI_Result _HandleInvokeReq( |
r = StrandMany_AddEntry( &enumEntry->strand ); |
Disp* self, |
if( MI_RESULT_OK != r ) |
InvokeReq* req) |
|
{ | { |
MI_Result r; |
trace_Disp_ErrorAddEntry(); |
const ProvRegEntry* reg; |
StrandEntry_DeleteNoAdded( &enumEntry->strand ); |
MI_ConstString cn = 0; |
goto sendErrorBack_Opened; |
|
} |
| |
/* Validate input parameters */ |
// Use the original message batch, it will not be deleted until enumInteraction (who holds a ref to the message) is deleted |
if (!req->nameSpace) |
enumEntry->className = Batch_Tcsdup(req->base.base.batch, derived); |
return MI_RESULT_INVALID_PARAMETER; |
enumEntry->next = NULL; |
|
enumEntryPrev->next = enumEntry; |
|
enumEntryPrev = enumEntry; |
|
} |
| |
if (req->className) |
/* Finalize enumeration */ |
cn = req->className; |
{ |
else if (req->instance) |
r = ProvReg_EndClasses(&pos); |
cn = req->instance->classDecl->name; |
|
| |
if (!cn) |
if (MI_RESULT_OK != r) |
{ | { |
r = MI_RESULT_INVALID_CLASS; |
trace_ProvReg_EndClasses_Failed( |
LOGD((T("class name is expected for invoke\n"))); |
r, tcs(Result_ToString(r))); |
goto sendErrorBack; |
/* send error back to caller */ |
|
goto sendErrorBack_Opened; |
|
} |
} | } |
| |
|
Strand_Leave( &enumInteraction->strand.strand ); |
| |
// Find a provider for this class. |
// Now go thru the added entries and dispatch the interactions |
reg = ProvReg_FindProviderForClass(&self->provreg, req->nameSpace, cn); |
enumEntry = enumEntryHead; |
|
while( NULL != enumEntry ) |
|
{ |
|
// Move to the next one before the object can be deleted by itself or by delete below |
|
enumEntryPrev = enumEntry; |
|
enumEntry = enumEntry->next; |
|
if( _DispatchEnumerateInstancesReq(self, req, enumEntryPrev->className, enumEntryPrev, NULL) == MI_RESULT_OK) |
|
{ |
|
sentOk = MI_TRUE; |
|
} |
|
else |
|
{ |
|
StrandEntry_Delete( &enumEntryPrev->strand ); |
|
} |
|
} |
|
enumEntryHead = NULL; |
| |
if (!reg) |
/* Fail if no provider was found for request */ |
|
if (!sentOk) |
{ | { |
r = MI_RESULT_INVALID_NAMESPACE; /*ATTN! or class?*/ |
trace_FoundNoProvider( |
LOGD((T("cannot find provider for class: %s"), MI_GET_SAFE_PRINTF_STRING(cn))); |
req->className); |
goto sendErrorBack; |
r = MI_RESULT_NOT_SUPPORTED; |
|
goto sendErrorBack_Opened; |
} | } |
| |
// Send the request to provider manager. |
StrandMany_ScheduleAux(&enumInteraction->strand,DISPENUMPARENT_STRANDAUX_ENUMDONE); |
r = AgentMgr_HandleRequest(&self->agentmgr, &req->base, reg); |
} /* if deep*/ |
|
else |
|
{ |
|
/* Checking to see if the requested className is valid */ |
|
ProvRegPosition pos; |
|
r = ProvReg_BeginClasses(&self->provreg, req->nameSpace, |
|
req->className, MI_TRUE, &pos, MI_FALSE); |
| |
if (r != MI_RESULT_OK) |
if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("AgentMgr_HandleRequest for namespace: %s"), MI_GET_SAFE_PRINTF_STRING(req->nameSpace))); |
/* Checking if the class is in extra classes to return appropriate error */ |
goto sendErrorBack; |
MI_Result result; |
|
result = ProvReg_BeginClasses(&self->provreg, req->nameSpace, |
|
req->className, MI_TRUE, &pos, MI_TRUE); |
|
if(MI_RESULT_OK == result) |
|
{ |
|
r = MI_RESULT_NOT_SUPPORTED; |
|
ProvReg_EndClasses(&pos); |
|
} |
|
return r; |
|
} |
|
else |
|
{ |
|
ProvReg_EndClasses(&pos); |
|
} |
|
|
|
// no need to create new interaction |
|
return _DispatchEnumerateInstancesReq(self, req, req->className, NULL, interactionParams); |
} | } |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
| |
sendErrorBack: |
sendErrorBack_Opened: |
return _SendErrorResponse(&req->base,r); |
// Delete not dispatched entries |
|
enumEntry = enumEntryHead; |
|
while( NULL != enumEntry ) |
|
{ |
|
StrandEntry_Delete( &enumEntry->strand ); |
|
enumEntry = enumEntry->next; |
} | } |
| |
|
// send error back to caller |
|
_SendErrorResponse_Opened(interactionParams, enumInteraction, r, MI_FALSE ); |
|
return MI_RESULT_OK; |
|
} |
| |
static MI_Result _HandleAssociatorsOfReq( | static MI_Result _HandleAssociatorsOfReq( |
Disp* self, |
_In_ Disp* self, |
AssociatorsOfReq* req) |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ AssociationsOfReq* req) |
{ | { |
MI_Result r; |
int res; |
|
MI_Result r = MI_RESULT_FAILED; |
MI_ConstString cn = 0; | MI_ConstString cn = 0; |
DispResultMsg* dispStateMsg; |
|
ProvRegAssocPosition pos; | ProvRegAssocPosition pos; |
MI_Boolean sentOk = MI_FALSE; | MI_Boolean sentOk = MI_FALSE; |
HashTable classNames; |
HashMap classNames; |
|
DispEnumParent* enumInteraction; |
|
EnumEntry* enumEntry; |
|
EnumEntry* enumEntryHead = NULL; |
|
EnumEntry* enumEntryPrev = NULL; |
| |
/* Create a hash table of class names */ | /* Create a hash table of class names */ |
| |
r = HashTable_Init( |
res = HashMap_Init( |
&classNames, | &classNames, |
64, | 64, |
ClassNameHash, | ClassNameHash, |
ClassNameEqual, | ClassNameEqual, |
ClassNameRelease); | ClassNameRelease); |
| |
if (r != 0) |
if (res != 0) |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
| |
/* Validate input parameters */ | /* Validate input parameters */ |
if (!req->instance || !req->nameSpace) | if (!req->instance || !req->nameSpace) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
/* create a state message that will keep track of results from providers */ |
/* create the interaction that will keep track of results from providers */ |
dispStateMsg = DispResultMsg_New(req->base.msgID); |
enumInteraction = _DispEnumParent_New( |
if (!dispStateMsg) |
self, |
|
interactionParams); |
|
if (!enumInteraction) |
|
{ |
|
trace_Disp_ErrorInteractionAlloc(); |
|
HashMap_Destroy(&classNames); |
return MI_RESULT_FAILED; | 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, | r = ProvReg_BeginAssocClasses(&self->provreg, req->nameSpace, |
req->instance->classDecl->name, | req->instance->classDecl->name, |
|
|
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_BeginAssocClasses() failed: %u: %s"), |
trace_ProvReg_BeginAssocClasses_Failed(r, tcs(Result_ToString(r))); |
r, Result_ToString(r))); |
|
| |
/* send error back to caller */ | /* send error back to caller */ |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
| |
/* ATTN: there is a bug in the provider registration tree causing | /* ATTN: there is a bug in the provider registration tree causing |
|
|
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_NextAssocClass() failed: %u: %s"), |
trace_ProvReg_NextAssocClass_Failed(r, tcs(Result_ToString(r))); |
r, Result_ToString(r))); |
|
/* send error back to caller */ | /* send error back to caller */ |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
| |
/* Check whether this class has been dispatched */ | /* Check whether this class has been dispatched */ |
{ | { |
ClassNameBucket bucket; | ClassNameBucket bucket; |
bucket.key = (char*)cn; |
bucket.key = (ZChar*)cn; |
| |
if (!HashTable_Find(&classNames, (const HashBucket*)&bucket)) |
if (!HashMap_Find(&classNames, (const HashBucket*)&bucket)) |
{ | { |
if (_DispatchAssocReq(self, cn, req, dispStateMsg)) |
enumEntry = (EnumEntry*)StrandEntry_New( STRAND_DEBUG( DispEnumEntry ) |
sentOk = MI_TRUE; |
&enumInteraction->strand, |
|
&_DispEnumEntry_ProviderFT, |
|
sizeof(EnumEntry), |
|
STRAND_FLAG_ENTERSTRAND, |
|
NULL); |
|
if( NULL == enumEntry ) |
|
{ |
|
trace_Disp_ErrorEnumEntryAlloc(); |
|
goto sendErrorBack_Opened; |
|
} |
|
|
|
r = StrandMany_AddEntry( &enumEntry->strand ); |
|
if( MI_RESULT_OK != r ) |
|
{ |
|
trace_Disp_ErrorAddEntry(); |
|
StrandEntry_DeleteNoAdded( &enumEntry->strand ); |
|
goto sendErrorBack_Opened; |
|
} |
|
|
|
// Use the original message batch, it will not be deleted until enumInteraction (who holds a ref to the message) is deleted |
|
enumEntry->className = Batch_Tcsdup(req->base.base.batch, cn); |
|
enumEntry->next = NULL; |
|
if( NULL == enumEntryHead ) |
|
{ |
|
enumEntryHead = enumEntry; |
|
} |
|
else |
|
{ |
|
enumEntryPrev->next = enumEntry; |
|
} |
|
enumEntryPrev = enumEntry; |
| |
{ | { |
ClassNameBucket* bucket = (ClassNameBucket*)calloc( |
ClassNameBucket* bucket = (ClassNameBucket*)PAL_Calloc( |
1, sizeof(ClassNameBucket)); | 1, sizeof(ClassNameBucket)); |
| |
if (!bucket) | if (!bucket) |
{ | { |
r = MI_RESULT_FAILED; | r = MI_RESULT_FAILED; |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
| |
bucket->key = strdup(cn); |
bucket->key = PAL_Tcsdup(cn); |
| |
if (HashTable_Insert(&classNames, (HashBucket*)bucket) != 0) |
if (HashMap_Insert(&classNames, (HashBucket*)bucket) != 0) |
{ | { |
r = MI_RESULT_FAILED; | r = MI_RESULT_FAILED; |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
} | } |
} | } |
|
|
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_EndAssocClasses() failed: %u: %s"), |
trace_ProvReg_EndAssocClasses_Failed(r, tcs(Result_ToString(r))); |
r, Result_ToString(r))); |
|
/* send error back to caller */ | /* send error back to caller */ |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
} | } |
| |
|
Strand_Leave( &enumInteraction->strand.strand ); |
|
|
|
// Now go thru the added entries and dispatch the interactions |
|
enumEntry = enumEntryHead; |
|
while( NULL != enumEntry ) |
|
{ |
|
// Move to the next one before the object can be deleted by itself or by delete below |
|
enumEntryPrev = enumEntry; |
|
enumEntry = enumEntry->next; |
|
if (_DispatchAssocReq(self, req, enumEntryPrev, AssociatorsOfReqTag)) |
|
{ |
|
sentOk = MI_TRUE; |
|
} |
|
else |
|
{ |
|
StrandEntry_Delete( &enumEntryPrev->strand ); |
|
} |
|
} |
|
enumEntryHead = NULL; |
|
|
|
HashMap_Destroy(&classNames); |
|
|
/* Fail if no provider was found for request */ | /* Fail if no provider was found for request */ |
if (!sentOk) | if (!sentOk) |
{ | { |
LOGD((T("found no providers for class: %s"), req->instance->classDecl->name)); |
trace_FoundNoProvider( |
r = MI_RESULT_NOT_FOUND; |
tcs(req->instance->classDecl->name)); |
goto sendErrorBack; |
_SendErrorResponse_Opened(interactionParams, enumInteraction, MI_RESULT_NOT_SUPPORTED, MI_TRUE ); |
|
return MI_RESULT_OK; |
} | } |
| |
if ( AtomicDec(&dispStateMsg->requestCounter) ) |
StrandMany_ScheduleAux(&enumInteraction->strand,DISPENUMPARENT_STRANDAUX_ENUMDONE); |
{ /* last result - forward it to the net stack */ |
return MI_RESULT_OK; |
r = dispStateMsg->result; |
|
goto sendErrorBack; |
sendErrorBack_Opened: |
|
HashMap_Destroy(&classNames); |
|
// Delete not dispatched entries |
|
enumEntry = enumEntryHead; |
|
while( NULL != enumEntry ) |
|
{ |
|
StrandEntry_Delete( &enumEntry->strand ); |
|
enumEntry = enumEntry->next; |
} | } |
| |
HashTable_Destroy(&classNames); |
// send error back to caller |
DispResultMsg_Release(dispStateMsg); |
_SendErrorResponse_Opened(interactionParams, enumInteraction, r, MI_FALSE ); |
return MI_RESULT_OK; | return MI_RESULT_OK; |
|
|
sendErrorBack: |
|
DispResultMsg_Release(dispStateMsg); |
|
HashTable_Destroy(&classNames); |
|
return _SendErrorResponse(&req->base,r); |
|
} | } |
| |
static MI_Result _HandleReferencesOfReq( | static MI_Result _HandleReferencesOfReq( |
Disp* self, |
_In_ Disp* self, |
ReferencesOfReq* req) |
_Inout_ InteractionOpenParams* interactionParams, |
|
_In_ AssociationsOfReq* req) |
{ | { |
MI_Result r; |
MI_Result r = MI_RESULT_FAILED; |
MI_ConstString cn = 0; | MI_ConstString cn = 0; |
DispResultMsg* dispStateMsg; |
|
ProvRegAssocPosition pos; | ProvRegAssocPosition pos; |
MI_Boolean sentOk = MI_FALSE; | MI_Boolean sentOk = MI_FALSE; |
|
DispEnumParent* enumInteraction; |
|
EnumEntry* enumEntry; |
|
EnumEntry* enumEntryHead = NULL; |
|
EnumEntry* enumEntryPrev = NULL; |
| |
/* Validate input parameters */ | /* Validate input parameters */ |
if (!req->instance || !req->nameSpace) | if (!req->instance || !req->nameSpace) |
return MI_RESULT_INVALID_PARAMETER; | return MI_RESULT_INVALID_PARAMETER; |
| |
/* create a state message that will keep track of results from providers */ |
/* create the interaction that will keep track of results from providers */ |
dispStateMsg = DispResultMsg_New(req->base.msgID); |
enumInteraction = _DispEnumParent_New( |
if (!dispStateMsg) |
self, |
|
interactionParams); |
|
if (!enumInteraction) |
|
{ |
|
trace_Disp_ErrorInteractionAlloc(); |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
|
} |
| |
/* add one for sending thread so first 'fast' provider will not send its response all the way */ |
/* resultClass parameter of ReferencesOf operation contains association class name. |
AtomicInc(&dispStateMsg->requestCounter); |
Here using req->resultClass for passing assocClassName to ProvReg_BeginAssocClasses function */ |
|
|
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, | r = ProvReg_BeginAssocClasses(&self->provreg, req->nameSpace, |
req->instance->classDecl->name, | req->instance->classDecl->name, |
req->assocClass, 0, &pos); |
req->resultClass, 0, &pos); |
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_BeginAssocClasses() failed: %u: %s"), |
trace_ProvReg_BeginAssocClasses_Failed(r, tcs(Result_ToString(r))); |
r, Result_ToString(r))); |
|
| |
/* send error back to caller */ | /* send error back to caller */ |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
| |
/* While more classes */ | /* While more classes */ |
|
|
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_NextAssocClass() failed: %u: %s"), |
trace_ProvReg_NextAssocClass_Failed(r, tcs(Result_ToString(r))); |
r, Result_ToString(r))); |
|
/* send error back to caller */ | /* send error back to caller */ |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
} | } |
| |
if (_DispatchRefReq(self, cn, req, dispStateMsg)) |
enumEntry = (EnumEntry*)StrandEntry_New( STRAND_DEBUG( DispEnumEntry ) |
sentOk = MI_TRUE; |
&enumInteraction->strand, |
|
&_DispEnumEntry_ProviderFT, |
|
sizeof(EnumEntry), |
|
STRAND_FLAG_ENTERSTRAND, |
|
NULL); |
|
if( NULL == enumEntry ) |
|
{ |
|
trace_Disp_ErrorEnumEntryAlloc(); |
|
goto sendErrorBack_Opened; |
|
} |
|
|
|
r = StrandMany_AddEntry( &enumEntry->strand ); |
|
if( MI_RESULT_OK != r ) |
|
{ |
|
trace_Disp_ErrorAddEntry(); |
|
StrandEntry_DeleteNoAdded( &enumEntry->strand ); |
|
goto sendErrorBack_Opened; |
|
} |
|
|
|
// Use the original message batch, it will not be deleted until enumInteraction (who holds a ref to the message) is deleted |
|
enumEntry->className = Batch_Tcsdup(req->base.base.batch, cn); |
|
enumEntry->next = NULL; |
|
if( NULL == enumEntryHead ) |
|
{ |
|
enumEntryHead = enumEntry; |
|
} |
|
else |
|
{ |
|
enumEntryPrev->next = enumEntry; |
|
} |
|
enumEntryPrev = enumEntry; |
} | } |
| |
/* Finalize enumeration */ | /* Finalize enumeration */ |
|
|
| |
if (MI_RESULT_OK != r) | if (MI_RESULT_OK != r) |
{ | { |
LOGD((T("ProvReg_EndAssocClasses() failed: %u: %s"), |
trace_ProvReg_EndAssocClasses_Failed(r, tcs(Result_ToString(r))); |
r, Result_ToString(r))); |
|
/* send error back to caller */ | /* send error back to caller */ |
goto sendErrorBack; |
goto sendErrorBack_Opened; |
|
} |
|
} |
|
|
|
Strand_Leave( &enumInteraction->strand.strand ); |
|
|
|
// Now go thru the added entries and dispatch the interactions |
|
enumEntry = enumEntryHead; |
|
while( NULL != enumEntry ) |
|
{ |
|
// Move to the next one before the object can be deleted by itself or by delete below |
|
enumEntryPrev = enumEntry; |
|
enumEntry = enumEntry->next; |
|
if (_DispatchAssocReq(self, req, enumEntryPrev, ReferencesOfReqTag)) |
|
{ |
|
sentOk = MI_TRUE; |
|
} |
|
else |
|
{ |
|
StrandEntry_Delete( &enumEntryPrev->strand ); |
} | } |
} | } |
|
enumEntryHead = NULL; |
| |
/* Fail if no provider was found for request */ | /* Fail if no provider was found for request */ |
if (!sentOk) | if (!sentOk) |
{ | { |
LOGD((T("found no providers for class: %s"), req->instance->classDecl->name)); |
trace_FoundNoProvider( |
r = MI_RESULT_NOT_FOUND; |
tcs(req->instance->classDecl->name)); |
goto sendErrorBack; |
_SendErrorResponse_Opened(interactionParams, enumInteraction, MI_RESULT_NOT_SUPPORTED, MI_TRUE ); |
|
return MI_RESULT_OK; |
} | } |
| |
if ( AtomicDec(&dispStateMsg->requestCounter) ) |
StrandMany_ScheduleAux(&enumInteraction->strand,DISPENUMPARENT_STRANDAUX_ENUMDONE); |
{ /* last result - forward it to the net stack */ |
return MI_RESULT_OK; |
r = dispStateMsg->result; |
|
goto sendErrorBack; |
sendErrorBack_Opened: |
|
// Delete not dispatched entries |
|
enumEntry = enumEntryHead; |
|
while( NULL != enumEntry ) |
|
{ |
|
StrandEntry_Delete( &enumEntry->strand ); |
|
enumEntry = enumEntry->next; |
} | } |
| |
DispResultMsg_Release(dispStateMsg); |
// send error back to caller |
|
_SendErrorResponse_Opened(interactionParams, enumInteraction, r, FALSE ); |
return MI_RESULT_OK; | return MI_RESULT_OK; |
|
} |
| |
sendErrorBack: |
#ifndef DISABLE_INDICATION |
DispResultMsg_Release(dispStateMsg); |
static MI_Result _HandleSubscribeReq( |
return _SendErrorResponse(&req->base,r); |
_In_ Disp* self, |
|
_Inout_ InteractionOpenParams* params ) |
|
{ |
|
params->callbackData = self->indmgr; |
|
IndiMgr_HandleSubscribeReq(params); |
|
return MI_RESULT_OK; |
} | } |
|
#endif /* ifndef DISABLE_INDICATION */ |
| |
/* | /* |
**============================================================================== | **============================================================================== |
|
|
| |
#if 0 | #if 0 |
/* Initialize the provider registry */ | /* Initialize the provider registry */ |
MI_RETURN_ERR(ProvReg_Init(&self->provreg, GetPath(ID_REGISTERFILE))); |
MI_RETURN_ERR(ProvReg_Init(&self->provreg, OMI_GetPath(ID_REGISTERFILE))); |
#else | #else |
MI_RETURN_ERR(ProvReg_Init2(&self->provreg)); | MI_RETURN_ERR(ProvReg_Init2(&self->provreg)); |
#endif | #endif |
|
|
/* Initialize the provider manager */ | /* Initialize the provider manager */ |
MI_RETURN_ERR(AgentMgr_Init(&self->agentmgr, selector)); | MI_RETURN_ERR(AgentMgr_Init(&self->agentmgr, selector)); |
| |
/* Initialize indications part */ |
#ifndef DISABLE_INDICATION |
MI_RETURN_ERR(Mutex_Init(&self->mt)); |
/* Initialize indication manager */ |
|
self->indmgr = IndiMgr_NewFromDisp(self); |
|
if (NULL == self->indmgr) |
|
MI_RETURN_ERR(MI_RESULT_FAILED); |
|
#endif /* ifndef DISABLE_INDICATION */ |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
|
|
MI_RETURN_ERR(AgentMgr_Destroy(&self->agentmgr)); | MI_RETURN_ERR(AgentMgr_Destroy(&self->agentmgr)); |
ProvReg_Destroy(&self->provreg); | ProvReg_Destroy(&self->provreg); |
| |
|
#ifndef DISABLE_INDICATION |
|
/* Shutdown indication manager */ |
|
IndiMgr_Shutdown(self->indmgr); |
|
#endif /* ifndef DISABLE_INDICATION */ |
|
|
/*ATTN! remove indication contexts! */ | /*ATTN! remove indication contexts! */ |
Mutex_Destroy(&self->mt); |
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
MI_Result Disp_HandleRequest( |
MI_Result Disp_HandleInteractionRequest( |
Disp* self, |
_In_ Disp* self, |
Message* msg) |
_Inout_ InteractionOpenParams* params ) |
{ |
{ |
|
Message* msg = params->msg; |
|
|
|
trace_DispHandleInteractionRequest(self, |
|
params->interaction, |
|
msg, |
|
msg->tag, |
|
MessageName(msg->tag), |
|
msg->operationId); |
|
|
|
DEBUG_ASSERT( NULL != self ); |
|
DEBUG_ASSERT( NULL != params ); |
|
DEBUG_ASSERT( NULL != params->interaction ); |
|
DEBUG_ASSERT( NULL != params->msg ); |
|
|
switch (msg->tag) | switch (msg->tag) |
{ | { |
case EnumerateInstancesReqTag: |
case GetInstanceReqTag: |
{ | { |
EnumerateInstancesReq* req = (EnumerateInstancesReq*)msg; |
GetInstanceReq* req = (GetInstanceReq*)msg; |
return _HandleEnumerateInstancesReq(self, req); |
return _HandleGetInstanceReq(self, params, req); |
} | } |
| |
case GetInstanceReqTag: |
case GetClassReqTag: |
{ | { |
GetInstanceReq* req = (GetInstanceReq*)msg; |
GetClassReq* req = (GetClassReq*)msg; |
return _HandleGetInstanceReq(self, req); |
return _HandleGetClassReq(self, params, req); |
} | } |
| |
|
|
case CreateInstanceReqTag: | case CreateInstanceReqTag: |
{ | { |
CreateInstanceReq* req = (CreateInstanceReq*)msg; | CreateInstanceReq* req = (CreateInstanceReq*)msg; |
return _HandleCreateInstanceReq(self, req); |
return _HandleCreateInstanceReq(self, params, req); |
} | } |
| |
case ModifyInstanceReqTag: | case ModifyInstanceReqTag: |
{ | { |
ModifyInstanceReq* req = (ModifyInstanceReq*)msg; | ModifyInstanceReq* req = (ModifyInstanceReq*)msg; |
return _HandleModifyInstanceReq(self, req); |
return _HandleModifyInstanceReq(self, params, req); |
} | } |
| |
case DeleteInstanceReqTag: | case DeleteInstanceReqTag: |
{ | { |
DeleteInstanceReq* req = (DeleteInstanceReq*)msg; | DeleteInstanceReq* req = (DeleteInstanceReq*)msg; |
return _HandleDeleteInstanceReq(self, req); |
return _HandleDeleteInstanceReq(self, params, req); |
} | } |
| |
case InvokeReqTag: | case InvokeReqTag: |
{ | { |
InvokeReq* req = (InvokeReq*)msg; | InvokeReq* req = (InvokeReq*)msg; |
return _HandleInvokeReq(self, req); |
return _HandleInvokeReq(self, params, req); |
|
} |
|
|
|
case EnumerateInstancesReqTag: |
|
{ |
|
EnumerateInstancesReq* req = (EnumerateInstancesReq*)msg; |
|
return _HandleEnumerateInstancesReq(self, params, req); |
} | } |
| |
case AssociatorsOfReqTag: | case AssociatorsOfReqTag: |
{ | { |
AssociatorsOfReq* req = (AssociatorsOfReq*)msg; |
AssociationsOfReq* req = (AssociationsOfReq*)msg; |
return _HandleAssociatorsOfReq(self, req); |
return _HandleAssociatorsOfReq(self, params, req); |
} | } |
| |
case ReferencesOfReqTag: | case ReferencesOfReqTag: |
{ | { |
ReferencesOfReq* req = (ReferencesOfReq*)msg; |
AssociationsOfReq* req = (AssociationsOfReq*)msg; |
return _HandleReferencesOfReq(self, req); |
return _HandleReferencesOfReq(self, params, req); |
} | } |
| |
|
#ifndef DISABLE_INDICATION |
|
|
case SubscribeReqTag: | case SubscribeReqTag: |
{ | { |
SubscribeReq* req = (SubscribeReq*)msg; |
return _HandleSubscribeReq(self, params); |
return _HandleSubscribeReq(self, req); |
|
} | } |
| |
|
#endif /* ifndef DISABLE_INDICATION */ |
|
|
default: | default: |
{ | { |
/* Unsupported mesage type */ | /* Unsupported mesage type */ |
return _SendErrorResponse(msg,MI_RESULT_NOT_SUPPORTED); |
trace_DispUnsupportedMessage( self, |
|
params->interaction, |
|
msg, |
|
msg->tag, |
|
MessageName(msg->tag), |
|
msg->operationId ); |
|
return MI_RESULT_NOT_SUPPORTED; |
} | } |
} | } |
} | } |