/*
**==============================================================================
**
** 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 "context.h"
#include <protocol/wsmanbuffer.h>
#include <wql/wql.h>
static const MI_Uint32 _MAGIC = 0x35eb3d3b;
static MI_Result _ProcessResult(
MI_Context* self_,
MI_Result result,
const MI_Char* message,
const MI_Instance* error)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC)
return MI_RESULT_INVALID_PARAMETER;
LOGD_CHAR(("post result from provider, %d", (int)result));
/* If no instances matched during GetInstance over EnumerateInstance */
if (self->instanceName && !self->matchedInstanceName)
{
if (result == MI_RESULT_OK)
result = MI_RESULT_NOT_FOUND;
}
message = message;
error = error;
if (self->request && !self->cancelled)
{
PostResultMsg* resp = PostResultMsg_New( self->request ? self->request->msgID : 0 );
if (!resp)
return MI_RESULT_FAILED;
resp->result = result;
Message_SetRequest(&resp->base,self->request);
(*self->request->callback)(&resp->base, self->request->callbackData);
PostResultMsg_Release(resp);
}
if (self->result)
*self->result = result;
/* destory context */
Context_Destroy(self);
return MI_RESULT_OK;
}
static MI_Boolean _FilterProperty(const MI_Char* name, void *data)
{
WQL* wql = (WQL*)data;
if (WQL_ContainsProperty(wql, name))
return MI_FALSE;
else
return MI_TRUE;
}
static MI_Result _PostInstanceToCallback(
Context* self,
const MI_Instance* instance)
{
PostInstanceMsg* resp = PostInstanceMsg_New(self->request->msgID);
if (!resp)
return MI_RESULT_FAILED;
if (self->request->flags & WSMANFlag)
{
const MI_ClassDecl* castToClassDecl = 0;
/* Enumerate response with 'base-properties-only' option
may require instance conversion */
if (EnumerateInstancesReqTag == self->request->tag)
{
EnumerateInstancesReq* req = (EnumerateInstancesReq*)self->request;
if (req->requestClassName)
{
castToClassDecl = instance->classDecl;
while (castToClassDecl &&
Zcasecmp(req->requestClassName, castToClassDecl->name) != 0)
{
castToClassDecl = castToClassDecl->superClassDecl;
}
}
}
{
EnumerateInstancesReq* req = NULL;
if (EnumerateInstancesReqTag == self->request->tag)
req = (EnumerateInstancesReq*)self->request;
if (req && req->wql)
{
WSBuf_InstanceToBuf(
instance,
_FilterProperty,
req->wql,
castToClassDecl,
resp->base.batch,
self->request->flags,
&resp->packedInstancePtr,
&resp->packedInstanceSize);
}
else
{
WSBuf_InstanceToBuf(
instance,
NULL, /* filterProperty */
NULL, /* filterPropertyData */
castToClassDecl,
resp->base.batch,
self->request->flags,
&resp->packedInstancePtr,
&resp->packedInstanceSize);
}
}
resp->base.flags |= self->request->flags;
}
else
{
EnumerateInstancesReq* req = NULL;
if (EnumerateInstancesReqTag == self->request->tag)
req = (EnumerateInstancesReq*)self->request;
if (req && req->wql)
{
InstanceToBatch(instance, _FilterProperty, req->wql,
resp->base.batch, &resp->packedInstancePtr,
&resp->packedInstanceSize);
}
else
{
InstanceToBatch(instance, NULL, NULL, resp->base.batch,
&resp->packedInstancePtr, &resp->packedInstanceSize);
}
resp->base.flags |= BinaryProtocolFlag;
}
/* count message in for back-pressure feature (only Instances) */
if (self->provider)
Provider_NewInstanceCreated(self->provider, &resp->base);
Message_SetRequest(&resp->base,self->request);
(*self->request->callback)(&resp->base, self->request->callbackData);
PostInstanceMsg_Release(resp);
return MI_RESULT_OK;
}
/* successfully received instance from 'gi' - call invoke with this instance now */
static void _CallInvoke(
Context* self,
const MI_Instance* instance)
{
Context* ctx = (Context*)Batch_GetClear(self->request->batch, sizeof(Context));;
Context_Init(ctx, self->provider);
ctx->request = self->request;
/* message will be freed in context release*/
Message_AddRef(ctx->request);
/* disregard all other messages for this context */
self->cancelled = MI_TRUE;
/* ATTN! clone instance, since invoke can overlive instance (if it's async)!!! */
(*self->md->function)(self->prov_self, &ctx->base,
__nameSpace, __className, __methodName, instance, self->instParams);
}
static MI_Result MI_CALL _PostResult(
MI_Context* self_,
MI_Result result)
{
return _ProcessResult(self_, result, 0, 0);
}
static MI_Result MI_CALL _PostResultWithMessage(
MI_Context* self_,
MI_Result result,
const MI_Char* message)
{
return _ProcessResult(self_, result, message, 0);
}
static MI_Result MI_CALL _PostResultWithError(
_In_ MI_Context* self_,
MI_Result result,
_In_ const MI_Instance* error)
{
return _ProcessResult(self_, result, 0, error);
}
static MI_Result MI_CALL _PostInstance(
MI_Context* self_,
const MI_Instance* instance)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !instance)
return MI_RESULT_INVALID_PARAMETER;
if (self->request && !self->cancelled)
{
if (self->instanceName == NULL)
{
if (CTX_TYPE_INVOKE_WITH_INSTANCE == self->chainType)
{
_CallInvoke(self, instance);
return MI_RESULT_OK;
}
else if (EnumerateInstancesReqTag == self->request->tag)
{
EnumerateInstancesReq* req =
(EnumerateInstancesReq*)self->request;
if (req->wql)
{
int r;
r = WQL_Eval(req->wql, WQL_LookupInstanceProperty,
(void*)instance);
if (r == 0)
{
/* Instance matched the query */
return _PostInstanceToCallback(self, instance);
}
else
{
/* Mismatch or failure */
return MI_RESULT_OK;
}
}
}
return _PostInstanceToCallback(self, instance);
}
else if (Instance_MatchKeys(instance, self->instanceName))
{
/* Handle GetInstance through EnumerateInstances */
if (!self->matchedInstanceName)
{
self->matchedInstanceName = MI_TRUE;
return _PostInstanceToCallback(self, instance);
}
}
}
return MI_RESULT_OK;
}
static MI_Result MI_CALL _ConstructInstance(
MI_Context* self_,
const MI_ClassDecl* classDecl,
MI_Instance* instance)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !instance || !classDecl)
return MI_RESULT_INVALID_PARAMETER;
return Instance_Construct(instance, classDecl, self->request->batch);
}
static MI_Result MI_CALL _ConstructParameters(
MI_Context* self_,
const MI_MethodDecl* methodDecl,
MI_Instance* instance)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !instance || !methodDecl)
return MI_RESULT_INVALID_PARAMETER;
return Parameters_Init(instance, methodDecl, self->request->batch);
}
static MI_Result MI_CALL _NewInstance(
MI_Context* self_,
const MI_ClassDecl* classDecl,
MI_Instance** instance)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !classDecl || !instance)
return MI_RESULT_INVALID_PARAMETER;
return Instance_New(instance, classDecl, self->request->batch);
}
static MI_Result MI_CALL _NewDynamicInstance(
MI_Context* self_,
const MI_Char* className,
MI_Uint32 flags,
MI_Instance** instance)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !className || !instance)
return MI_RESULT_INVALID_PARAMETER;
return Instance_NewDynamic(instance, className, flags,
self->request->batch);
}
static MI_Result MI_CALL _NewParameters(
MI_Context* self_,
const MI_MethodDecl* methodDecl,
MI_Instance** instance)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !methodDecl || !instance)
return MI_RESULT_INVALID_PARAMETER;
return Parameters_New(instance, methodDecl, self->request->batch);
}
static MI_Result MI_CALL _Canceled(
const MI_Context* self_,
MI_Boolean* flag)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !flag)
return MI_RESULT_INVALID_PARAMETER;
*flag = self->cancelled;
return MI_RESULT_OK;
}
static MI_Result MI_CALL _PostIndication(
MI_Context* context,
const MI_Instance* indication,
MI_Uint32 subscriptionIDCount,
const MI_Char* bookmark)
{
/* ATTN: just use _PostInstance() for now */
MI_UNUSED(subscriptionIDCount);
MI_UNUSED(bookmark);
return _PostInstance(context, indication);
}
static MI_Result MI_CALL _GetLocale(
const MI_Context* context,
MI_LocaleType localeType,
MI_Char locale[MI_MAX_LOCALE_SIZE])
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result MI_CALL _RegisterCancel(
MI_Context* context,
MI_CancelCallback callback,
void* callbackData)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result MI_CALL _RequestUnload(
MI_Context* self_)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !self->provider)
return MI_RESULT_INVALID_PARAMETER;
Provider_SetRefuseUnloadFlag(self->provider, MI_FALSE);
return MI_RESULT_OK;
}
static MI_Result MI_CALL _RefuseUnload(
MI_Context* self_)
{
Context* self = (Context*)self_;
if (!self || self->magic != _MAGIC || !self->provider)
return MI_RESULT_INVALID_PARAMETER;
Provider_SetRefuseUnloadFlag(self->provider, MI_TRUE);
return MI_RESULT_OK;
}
static MI_Result _GetLocalSession(
_In_ const MI_Context* context,
_Out_ MI_Session* session)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _SetStringOption(
_In_ MI_Context* context,
_In_z_ const MI_Char* name,
_In_z_ const MI_Char* value)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _GetStringOption(
_In_ MI_Context* context,
_In_z_ const MI_Char* name,
_Outptr_result_z_ const MI_Char** value)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _GetNumberOption(
_In_ MI_Context* context,
_In_z_ const MI_Char *name,
_Out_opt_ MI_Uint32* value)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _GetCustomOption(
_In_ MI_Context* context,
_In_z_ const MI_Char* name,
_Out_opt_ MI_Type* valueType,
_Out_opt_ MI_Value* value)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _GetCustomOptionCount(
_In_ MI_Context* context,
_Out_opt_ MI_Uint32* count)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _GetCustomOptionAt(
_In_ MI_Context* context,
_In_ MI_Uint32 index,
_Outptr_opt_result_maybenull_z_ const MI_Char** name,
_Out_opt_ MI_Type* valueType,
_Out_opt_ MI_Value* value)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _WriteMessage(
_In_ MI_Context* context,
MI_Uint32 channel,
_In_z_ const MI_Char* message)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _WriteProgress(
_In_ MI_Context* context,
_In_z_ const MI_Char* activity,
_In_z_ const MI_Char* currentOperation,
_In_z_ const MI_Char* statusDescription,
MI_Uint32 percentComplete,
MI_Uint32 secondsRemaining)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _WriteStreamParameter(
_In_ MI_Context* context,
_In_z_ const MI_Char* name,
_In_ const MI_Value* value,
_In_ MI_Type type,
_In_ MI_Uint32 flags)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _WriteCimError(
_In_ MI_Context* context,
_In_ const MI_Instance *error,
_Out_ MI_Boolean *flag)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _PromptUser(
_In_ MI_Context* context,
_In_z_ const MI_Char* message,
MI_PromptType promptType,
_Out_ MI_Boolean* result)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _ShouldProcess(
_In_ MI_Context* context,
_In_z_ const MI_Char* target,
_In_z_ const MI_Char* action,
_Out_ MI_Boolean* result)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _ShouldContinue(
_In_ MI_Context* context,
_In_z_ const MI_Char* message,
_Out_ MI_Boolean* result)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _PostError(
_In_ MI_Context* context,
MI_Uint32 resultCode,
_In_z_ const MI_Char* resultType,
_In_z_ const MI_Char* errorMessage)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _PostCimError(
_In_ MI_Context* context,
_In_ const MI_Instance *error)
{
return MI_RESULT_NOT_SUPPORTED;
}
static MI_Result _WriteError(
_In_ MI_Context* context,
MI_Uint32 resultCode,
_In_z_ const MI_Char* resultType,
_In_z_ const MI_Char* errorMessage,
_Out_ MI_Boolean *flag)
{
return MI_RESULT_NOT_SUPPORTED;
}
MI_ContextFT __mi_contextFT =
{
_PostResult,
_PostResultWithMessage,
_PostResultWithError,
_PostInstance,
_PostIndication,
_ConstructInstance,
_ConstructParameters,
_NewInstance,
_NewDynamicInstance,
_NewParameters,
_Canceled,
_GetLocale,
_RegisterCancel,
_RequestUnload,
_RefuseUnload,
_GetLocalSession,
_SetStringOption,
_GetStringOption,
_GetNumberOption,
_GetCustomOption,
_GetCustomOptionCount,
_GetCustomOptionAt,
_WriteMessage,
_WriteProgress,
_WriteStreamParameter,
_WriteCimError,
_PromptUser,
_ShouldProcess,
_ShouldContinue,
_PostError,
_PostCimError,
_WriteError,
};
void Context_Init(
Context* self,
Provider* provider)
{
memset(self, 0, sizeof(Context));
self->base.ft = &__mi_contextFT;
self->magic = _MAGIC;
self->provider = provider;
Provider_Addref(self->provider);
}
void Context_Destroy(
Context* self)
{
Message* req = self ? self->request : 0;
if (self)
Provider_Release(self->provider);
memset(self, -1, sizeof(Context));
/* Context typ[ically allocated from message's batch
so it may be freed right inside 'Release' call */
if (req)
Message_Release(req);
}