File: [OMI] / omi / protocol / Attic / 3
(download)
Revision: 1.1,
Wed May 30 21:47:49 2012 UTC (12 years, 1 month ago) by mike
Branch: MAIN
Initial revision
|
/*
**==============================================================================
**
** Open Management Infrastructure (OMI)
**
** Copyright (c) Microsoft Corporation
**
** Licensed under the Apache License, Version 2.0 (the "License"); you may not
** use this file except in compliance with the License. You may obtain a copy
** of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABLITY OR NON-INFRINGEMENT.
**
** See the Apache 2 License for the specific language governing permissions
** and limitations under the License.
**
**==============================================================================
*/
#include <assert.h>
#include "wsman.h"
#include "wsmanbuffer.h"
#include "wsmanparser.h"
#include "http.h"
#include <base/time.h>
#include <xml/xml.h>
#include <base/log.h>
#include <base/result.h>
#include <base/strings.h>
#include <base/user.h>
#include <base/io.h>
#include <base/base.h>
#include "wstags.h"
#define T MI_T
/*
**==============================================================================
**
** Local definitions:
**
**==============================================================================
*/
/* Maximum wsman envelope size */
#define WSMAN_MAX_ENVELOPE_SIZE (128 * 1024)
/* aproximate repsonse header size */
#define WSMAN_APROX_ENUM_RESP_HEADER_SIZE 1024
static const MI_Uint32 _MAGIC = 0x1CF2BCB7;
/************************************************************************\
* Local definitions
\************************************************************************/
typedef struct _WSMAN_ConnectionData WSMAN_ConnectionData;
typedef struct _WSMAN_EnumerateContext WSMAN_EnumerateContext;
/* These tags are used as magic numbers as well as to distinguish connection data strucutre from enumeration context */
#define DATA_TAG_CONNECTION_DATA 0x17CDDC11
#define DATA_TAG_ENUMERATION_CONTEXT 0xAB70900D
/* Maximum number of enumeration contexts stored at the same time
effectively limits number of concurent enumerations */
#define WSMAN_MAX_ENUM_CONTEXTS 64
struct _WSMAN
{
MI_Uint32 magic;
WSMANCallback callback;
void* callbackData;
Http* http;
Selector* selector;
/* configurable options */
WSMAN_Options options;
/* Array of enumeration contexts:
each 'pull' will look for corresponding context
*/
WSMAN_EnumerateContext* enumerateContexts[WSMAN_MAX_ENUM_CONTEXTS];
/* Cached xml parser with all namespaces registered */
XML xml;
};
/* Represents state of connection including buffers, unsent packets, states etc */
struct _WSMAN_ConnectionData
{
/* Since message's data can point to either ConnectionData or EnumerationContext,
both strucutres need some generic base property - tag;
in addition, tag used as magic number */
MI_Uint32 tag;
/* Link to http layer */
void* httpConnectionHandle;
/* Requestor information */
uid_t uid;
gid_t gid;
/* Attributes of the request */
WSMAN_WSHeader wsheader;
union
{
/* Actual type is defined by wsheader.rqtAction field */
WSMAN_WSEnumeratePullBody wsenumpullbody;
}
u;
/* Request page (buffer for most pointers inside header/body structures) */
Page* page;
/* for single-instance repsonses, we keep mesage until result received to avoid
conflicts with keep-alive enabled */
PostInstanceMsg* single_message;
/* Number of consumers of this structure:
connected client, outstanding request to the provider and timer */
MI_Uint32 refcounter;
/* response data */
/* only valid for enumerate/pull requests */
MI_Uint32 enumerateContextID;
/* flag indicates that response was not sent yet to the client */
MI_Boolean outstandingRequest;
};
/* Enumeration context:
'derived' from socket Handler, so it can subscribe for timeouts */
struct _WSMAN_EnumerateContext
{
/* Since message's data can point to either ConnectionData or EnumerationContext,
both strucutres need some generic base property - tag;
in addition, tag used as magic number */
MI_Uint32 tag;
/* based member - can be added to 'selector' for timeout support */
Handler base;
/* response data */
/* Linked list of messages to send */
PostInstanceMsg* head;
PostInstanceMsg* tail;
/* Total size of all instances in response queue */
MI_Uint32 totalResponseSize;
/* NUmber of messages in repsonse queue */
MI_Uint32 totalResponses;
/* Number of consumers of this structure:
reference from enum-context-list in WSMAN, outstanding request to the provider and timer */
MI_Uint32 refcounter;
/* lower 16 bits is aninxed in self->enumerateContexts, upper 16 bits are random data (for validation) */
MI_Uint32 enumerationContextID;
MI_Result finalResult;
/* indicates that 'Result' recevied form provider and stored in finalResult */
MI_Boolean enumerationCompleted;
/* Indicates that context has expired (either by timer or by Release request)
and all repsonses form the provider has to be ignored */
MI_Boolean expired;
/* pointer to current active connection - either Enumerate or Pull request */
WSMAN_ConnectionData* activeConnection;
};
/* forward declarations */
static void _CD_Release(
WSMAN_ConnectionData* selfConnectionData);
static void _SendEnumPullResponse(
WSMAN* self,
WSMAN_EnumerateContext* selfEC);
static MI_Boolean _ProcessEnumResponse(
WSMAN* self,
WSMAN_EnumerateContext* selfEC,
MI_Boolean attachingPullRequest);
static void _WSMAN_ReleaseEnumerateContext(
WSMAN* self,
MI_Uint32 enumerationContextID);
/************************************************************************\
* Helper funcitons
\************************************************************************/
/* Converts Enumeration mode into "Message" struct flag */
MI_INLINE MI_Uint32 _convertWSMANtoMsgEnumerationMode(
MI_Uint32 enumerationMode )
{
if (WSMANTAG_ENUM_MODE_EPR == enumerationMode)
return WSMAN_EPRFlag;
if (WSMANTAG_ENUM_MODE_OBJECT_AND_EPR == enumerationMode)
return WSMAN_ObjectAndEPRFlag;
return WSMAN_ObjectFlag;
}
/************************************************************************\
* Enumeration Context operations
\************************************************************************/
static void _EC_ReleaseAllMessages(
WSMAN_EnumerateContext* self)
{
/* Delete all queued messages*/
while (self->head)
{
PostInstanceMsg* msg = self->head;
List_Remove(
(ListElem**)&self->head,
(ListElem**)&self->tail,
(ListElem*)msg);
PostInstanceMsg_Release(msg);
}
self->totalResponses = 0;
self->totalResponseSize = 0;
}
static void _EC_SetActiveConnection(
WSMAN_EnumerateContext* self,
WSMAN_ConnectionData* selfCD)
{
if (self->activeConnection)
_CD_Release(self->activeConnection);
self->activeConnection = selfCD;
if (self->activeConnection)
{
self->activeConnection->refcounter++;
self->activeConnection->enumerateContextID = self->enumerationContextID;
}
}
static void _EC_Release(
WSMAN_EnumerateContext* self,
MI_Boolean freeAllMessages)
{
if (--self->refcounter == 0)
{
/* Delete all queued messages*/
_EC_ReleaseAllMessages(self);
/* release active connection (if exist) */
_EC_SetActiveConnection(self, 0);
#ifdef CONFIG_ENABLE_DEBUG
/* invalidate struct */
memset(self, 0xcd, sizeof(*self));
#endif
free(self);
}
else if (freeAllMessages)
{
/* Delete all queued messages*/
_EC_ReleaseAllMessages(self);
}
}
static MI_Boolean _EC_TimeoutCallback(
Selector* sel,
Handler* handler,
MI_Uint32 mask,
MI_Uint64 currentTimeUsec)
{
/* since 'base' is not the first member in EC struct,
adjust pointer as appropriate */
WSMAN_EnumerateContext* self = (WSMAN_EnumerateContext*)
(((char*)handler) - offsetof(WSMAN_EnumerateContext, base));
MI_UNUSED(sel);
MI_UNUSED(currentTimeUsec);
if (mask & SELECTOR_TIMEOUT)
{
/* remove context only from wsman list; selector will remove it automatically,
once 'false' returned */
_WSMAN_ReleaseEnumerateContext(
(WSMAN*)self->base.data, self->enumerationContextID);
/* once 'false' returned, selector will remove handler,
so actual handling happens in next 'if' */
return MI_FALSE;
}
if (mask & (SELECTOR_REMOVE | SELECTOR_DESTROY))
{
_EC_Release(self, MI_TRUE);
}
return MI_TRUE;
}
/************************************************************************\
* WSman operations
\************************************************************************/
static WSMAN_EnumerateContext* _WSMAN_AllocateEnumContext(
WSMAN* self)
{
MI_Uint32 enumerationContextID;
WSMAN_EnumerateContext* enumContext;
/* Find empty slot */
for (enumerationContextID = 0; enumerationContextID < MI_COUNT(self->enumerateContexts); enumerationContextID++)
{
if (!self->enumerateContexts[enumerationContextID])
break;
}
if (MI_COUNT(self->enumerateContexts) == enumerationContextID)
{
LOGW((T("Cannot allocate new enumerate context - too many concurrent enumerations") ));
return 0; /* no more slots available */
}
enumContext = (WSMAN_EnumerateContext*)calloc(1, sizeof(WSMAN_EnumerateContext));
if (!enumContext)
return 0;
/* Store reference to a new context */
self->enumerateContexts[enumerationContextID] = enumContext;
/* set tag/magic */
enumContext->tag = DATA_TAG_ENUMERATION_CONTEXT;
/* Add random data to the context-id */
enumerationContextID |= (rand() & 0xFFFF) << 16;
enumContext->enumerationContextID = enumerationContextID;
/* set ref-counter to 1, since it's referred by enumerateContexts array now */
enumContext->refcounter = 1;
return enumContext;
}
static WSMAN_EnumerateContext* _WSMAN_FindEnumContext(
WSMAN* self,
MI_Uint32 enumerationContextID)
{
MI_Uint32 index = enumerationContextID & 0xFFFF;
/* ATTN: add logging here! */
/* verify that context exist and has the same id as required */
if (index < MI_COUNT(self->enumerateContexts) &&
self->enumerateContexts[index] &&
self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
return self->enumerateContexts[index];
return 0;
}
static void _WSMAN_ReleaseEnumerateContext(
WSMAN* self,
MI_Uint32 enumerationContextID)
{
MI_Uint32 index = enumerationContextID & 0xFFFF;
if (index < MI_COUNT(self->enumerateContexts) &&
self->enumerateContexts[index] &&
self->enumerateContexts[index]->enumerationContextID == enumerationContextID)
{
/* mark handler for removing:
we cannot remove it directly since we are inside selector's callback;
settign time to current will trigger timeout/context removal */
MI_Uint64 currentTimeUsec = 0;
Time_Now(¤tTimeUsec);
self->enumerateContexts[index]->base.fireTimeoutAt = currentTimeUsec;
self->enumerateContexts[index]->expired = MI_TRUE;
/* dec-ref context: note: it can still be alive if porvider has outstanding request */
_EC_Release(self->enumerateContexts[index], MI_FALSE);
self->enumerateContexts[index] = 0;
}
}
static void _WSMAN_ReleaseAllEnumerateContexts(
WSMAN* self)
{
MI_Uint32 index;
for (index = 0; index < MI_COUNT(self->enumerateContexts); index++ )
{
if (self->enumerateContexts[index])
{
/* delete timer if was set */
Selector_RemoveHandler(self->selector, &self->enumerateContexts[index]->base);
/* dec-ref context: note: it can still be alive if porvider has outstanding request */
_EC_Release(self->enumerateContexts[index], MI_FALSE);
self->enumerateContexts[index] = 0;
}
}
}
static void _WSMAN_SetUpdateTimer(
WSMAN* self,
WSMAN_EnumerateContext* selfEC)
{
/* check if timer was already added */
if (!selfEC->base.fireTimeoutAt)
{
/* add timer - first time called */
selfEC->base.sock = INVALID_SOCK;
selfEC->base.data = self;
selfEC->base.callback = _EC_TimeoutCallback;
/* increment counter - will be decremented in callback/remove */
if (MI_RESULT_OK == Selector_AddHandler(self->selector, &selfEC->base))
selfEC->refcounter++;
}
/* extend time */
{
MI_Uint64 currentTimeUsec = 0;
if (MI_RESULT_OK == Time_Now(¤tTimeUsec))
{
selfEC->base.fireTimeoutAt =
currentTimeUsec + self->options.timeoutEnumContextUsec;
}
}
}
/************************************************************************\
* connection data operations
\************************************************************************/
MI_INLINE void _CD_SetPage(
WSMAN_ConnectionData* selfConnectionData,
Page* page)
{
if (selfConnectionData->page)
free(selfConnectionData->page);
selfConnectionData->page = page;
}
MI_INLINE void _CD_SetSingleMessage(
WSMAN_ConnectionData* selfConnectionData,
PostInstanceMsg* single_message)
{
if (selfConnectionData->single_message)
PostInstanceMsg_Release(selfConnectionData->single_message);
selfConnectionData->single_message = single_message;
if (selfConnectionData->single_message)
Message_AddRef(&selfConnectionData->single_message->base);
}
static void _CD_Cleanup(
WSMAN_ConnectionData* selfConnectionData)
{
_CD_SetPage(selfConnectionData, 0);
_CD_SetSingleMessage(selfConnectionData, 0);
/* free allocated instance/batch */
if (selfConnectionData->wsheader.instanceBatch)
{
/* destroying batch takes care of instance and instanceBatch members */
Batch_Destroy(selfConnectionData->wsheader.instanceBatch);
selfConnectionData->wsheader.instanceBatch = 0;
selfConnectionData->wsheader.instance = 0;
}
memset(&selfConnectionData->wsheader, 0, sizeof(selfConnectionData->wsheader));
}
static void _CD_Release(
WSMAN_ConnectionData* selfConnectionData)
{
if (--selfConnectionData->refcounter == 0)
{
_CD_Cleanup(selfConnectionData);
free(selfConnectionData);
}
}
static void _SendFaultResponse(
Http* http,
WSMAN_ConnectionData* selfCD,
WSBUF_FAULT_CODE faultCode,
const MI_Char* descriptionText)
{
Page* responsePage = WSBuf_CreateFaultResponsePage(
faultCode,
selfCD->wsheader.unknownMandatoryTag,
selfCD->wsheader.rqtMessageID,
descriptionText);
//printf("\n\n%s\n\n", (char*)(responsePage+1));
Http_SendResponse(http, selfCD->httpConnectionHandle,
HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR,
&responsePage);
selfCD->outstandingRequest = MI_FALSE;
if (responsePage)
free(responsePage);
}
static void _SendReleaseResponse(
WSMAN* self,
WSMAN_ConnectionData* selfCD)
{
Page* responsePage = WSBuf_CreateReleaseResponsePage(
selfCD->wsheader.rqtMessageID);
//printf("\n\n%s\n\n", (char*)(responsePage+1));
Http_SendResponse(self->http, selfCD->httpConnectionHandle,
HTTP_ERROR_CODE_OK,
&responsePage);
selfCD->outstandingRequest = MI_FALSE;
if (responsePage)
free(responsePage);
}
static int _ValidateHeader(
Http* http,
WSMAN_ConnectionData* selfCD)
{
if (selfCD->wsheader.unknownMandatoryTag)
{
_SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_UNDERSTOOD, 0);
return -1;
}
//DSP0226
//1756 R6.2-4: Services should reject any MaxEnvelopeSize value less than 8192 octets. This number
//1757 is the safe minimum in which faults can be reliably encoded for all character sets. If the requested
//1758 size is less than this, the service should return a wsman:EncodingLimit fault with the following
//1759 detail code:
//1760 http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/MinimumEnvelopeLimit
if (selfCD->wsheader.maxEnvelopeSize != 0 &&
selfCD->wsheader.maxEnvelopeSize < 8192)
{
LOGW_CHAR(("wsman: requested envelope size (%d) is too small; "
"expected at least 8K", (int)selfCD->wsheader.maxEnvelopeSize));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, 0);
return -1;
}
/* Limit envelope size to server's max */
if (selfCD->wsheader.maxEnvelopeSize == 0 ||
selfCD->wsheader.maxEnvelopeSize > WSMAN_MAX_ENVELOPE_SIZE)
{
selfCD->wsheader.maxEnvelopeSize = WSMAN_MAX_ENVELOPE_SIZE;
}
/* verify action for invoke */
if (
0 == selfCD->wsheader.rqtAction &&
(!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtMethod))
{
LOGW_CHAR(("wsman: unknown custom action"));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_SUPPORTED,
T("unknown custom action"));
return -1;
}
return 0;
}
static int _ValidateEnumerateRequest(
Http* http,
WSMAN_ConnectionData* selfCD)
{
/* If it has reference params, it must be an association request */
MI_Instance* referenceParameters =
selfCD->u.wsenumpullbody.associationFilter.referenceParameters;
if (referenceParameters)
{
selfCD->wsheader.rqtNamespace = referenceParameters->nameSpace;
selfCD->wsheader.rqtClassname = referenceParameters->classDecl->name;
}
else if (!selfCD->wsheader.rqtClassname || !selfCD->wsheader.rqtNamespace)
{
LOGW_CHAR(("wsman: mandatory parameters (className, namespace) "
"are missing for enumerate request"));
_SendFaultResponse(
http,
selfCD,
WSBUF_FAULT_INTERNAL_ERROR,
T("mandatory parameters (className, namespace) "
"are missing for enumerate request"));
return -1;
}
//R8.2.3; DSP226
//wsmen:Enumerate/wsman:MaxElements
//(optional) indicates the maximum number of items the consumer is willing to accept in the
//EnumerateResponse
//It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
//implied value is 1.
if (!selfCD->u.wsenumpullbody.maxElements)
selfCD->u.wsenumpullbody.maxElements = 1;
// if enumeration mode is not specified, use 'Objects'
if (selfCD->u.wsenumpullbody.enumerationMode == 0)
selfCD->u.wsenumpullbody.enumerationMode = WSMANTAG_ENUM_MODE_OBJECT;
return 0;
}
static int _ValidatePullRequest(
Http* http,
WSMAN_ConnectionData* selfCD)
{
MI_UNUSED(http);
//R8.2.3; DSP226
//wsmen:Enumerate/wsman:MaxElements
//(optional) indicates the maximum number of items the consumer is willing to accept in the
//EnumerateResponse
//It plays the same role as wsmen:Pull/wsmen:MaxElements. When this element is absent, its
//implied value is 1.
if (!selfCD->u.wsenumpullbody.maxElements)
selfCD->u.wsenumpullbody.maxElements = 1;
return 0;
}
static void _ProcessEnumerateRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD)
{
EnumerateInstancesReq* msg;
WSMAN_EnumerateContext* enumContext;
/* create EnumerateContext */
enumContext = _WSMAN_AllocateEnumContext(self);
if (!enumContext)
{
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* link new context to current EnumRequest */
_EC_SetActiveConnection(enumContext, selfCD);
// Create new request.
msg = EnumerateInstancesReq_New(/*_NextMsgID()*/ 1,
WSMANFlag | _convertWSMANtoMsgEnumerationMode(selfCD->u.wsenumpullbody.enumerationMode));
if (!msg)
{
_WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
selfCD->enumerateContextID = 0;
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* In case when client does not support optimized enumeration,
send empty Enum-response with correct enumerate context */
if (!selfCD->u.wsenumpullbody.allowOptimization)
{
_SendEnumPullResponse(self, enumContext);
_EC_SetActiveConnection(enumContext, 0);
_WSMAN_SetUpdateTimer(self, enumContext);
}
msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
msg->className = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtClassname);
msg->deepInheritance = (selfCD->u.wsenumpullbody.polymorphismMode != WSMANTAG_ENUM_POLYMORPHISM_MODE_NONE);
msg->basePropertiesOnly = (selfCD->u.wsenumpullbody.polymorphismMode == WSMANTAG_ENUM_POLYMORPHISM_MODE_EXCLUDE_PROPS);
/* Set the query related fields */
{
if (selfCD->u.wsenumpullbody.dialect)
msg->queryLanguage = Batch_Strdup2(msg->base.batch, selfCD->u.wsenumpullbody.dialect);
if (selfCD->u.wsenumpullbody.filter)
msg->queryExpression = Batch_Strdup2(msg->base.batch, selfCD->u.wsenumpullbody.filter);
}
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* attach client id */
msg->base.clientID = PtrToUint64(enumContext);
/* increment counter to keep it alive until provider replies */
enumContext->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
EnumerateInstancesReq_Release(msg);
}
static void _ProcessAssociatorsRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD)
{
AssociatorsOfReq* msg;
WSMAN_EnumerateContext* enumContext;
MI_Uint32 enumerationMode;
/* create EnumerateContext */
enumContext = _WSMAN_AllocateEnumContext(self);
if (!enumContext)
{
Http_SendErrorResponse(
http,
httpConnectionHandle,
HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* link new context to current EnumRequest */
_EC_SetActiveConnection(enumContext, selfCD);
/* Extract teh enumeration mode */
enumerationMode = _convertWSMANtoMsgEnumerationMode(
selfCD->u.wsenumpullbody.enumerationMode);
/* Create new request. */
msg = AssociatorsOfReq_New(
/*_NextMsgID()*/ 1,
WSMANFlag | enumerationMode);
if (!msg)
{
_WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
selfCD->enumerateContextID = 0;
Http_SendErrorResponse(
http,
httpConnectionHandle,
HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* In case when client does not support optimized enumeration,
* send empty Enum-response with correct enumerate context
*/
if (!selfCD->u.wsenumpullbody.allowOptimization)
{
_SendEnumPullResponse(self, enumContext);
_EC_SetActiveConnection(enumContext, 0);
_WSMAN_SetUpdateTimer(self, enumContext);
}
msg->nameSpace = Batch_Strdup2(
msg->base.batch,
selfCD->wsheader.rqtNamespace);
msg->className = Batch_Strdup2(
msg->base.batch,
selfCD->wsheader.rqtClassname);
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* Set messages fileds from association filter */
{
WSMAN_AssociationFilter* filter =
&selfCD->u.wsenumpullbody.associationFilter;
msg->instance = filter->referenceParameters;
msg->assocClass = filter->associationClassName;
msg->resultClass = filter->resultClassName;
msg->role = filter->role;
msg->resultRole = filter->resultRole;
}
/* attach client id */
msg->base.clientID = PtrToUint64(enumContext);
/* increment counter to keep it alive until provider replies */
enumContext->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
AssociatorsOfReq_Release(msg);
}
static void _ProcessPullRequest(
Http* http,
WSMAN* self,
WSMAN_ConnectionData* selfCD)
{
WSMAN_EnumerateContext* enumContext;
/* find EnumerateContext */
enumContext = _WSMAN_FindEnumContext(self, selfCD->u.wsenumpullbody.enumerationContextID);
if (!enumContext)
{
_SendFaultResponse(http, selfCD, WSBUF_FAULT_DESTINATION_UNREACHABLE, T("Enumeration context not found"));
return;
}
/* link new context to the request */
_EC_SetActiveConnection(enumContext, selfCD);
_ProcessEnumResponse(self, enumContext, MI_TRUE);
}
static void _ProcessReleaseRequest(
Http* http,
WSMAN* self,
WSMAN_ConnectionData* selfCD)
{
WSMAN_EnumerateContext* enumContext;
/* find EnumerateContext */
enumContext = _WSMAN_FindEnumContext(self, selfCD->u.wsenumpullbody.enumerationContextID);
if (!enumContext)
{
_SendFaultResponse(http, selfCD, WSBUF_FAULT_DESTINATION_UNREACHABLE, T("Enumeration context not found"));
return;
}
/* Remove context from the list */
_WSMAN_ReleaseEnumerateContext(self, enumContext->enumerationContextID);
_SendReleaseResponse(self, selfCD);
}
static void _ParseValidateProcessEnumerateRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
/* ATTN: only used if enumeration contains an association filter. Find
* some way to prevent creation in that case.
*/
if (!selfCD->wsheader.instanceBatch)
{
selfCD->wsheader.instanceBatch = Batch_New(BATCH_MAX_PAGES);
}
/* Parse enumerate request/body */
if (WS_ParseEnumerateBody(
xml,
&selfCD->wsheader.instanceBatch,
&selfCD->u.wsenumpullbody) != 0)
{
LOGW_CHAR(("wsman: unable to parse incoming xml/ enumerate request body"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* Validate enumerate request body */
if (_ValidateEnumerateRequest(http, selfCD) != 0)
{
/* appropriate error code was already sent to the client */
return;
}
/* Process reqest */
if (selfCD->u.wsenumpullbody.foundAssociationFilter)
{
_ProcessAssociatorsRequest(http,httpConnectionHandle,self,selfCD);
}
else
{
_ProcessEnumerateRequest(http,httpConnectionHandle,self,selfCD);
}
}
static void _ParseValidateProcessInvokeRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
InvokeReq* msg = 0;
/* if instance was created from batch, re-use exisintg batch to allocate message */
if (selfCD->wsheader.instanceBatch)
{
/* Allocate heap space for message */
msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(InvokeReq));
if (!msg)
goto failed;
/* Set the tag */
msg->base.tag = InvokeReqTag;
/* Set the message id and flags */
msg->base.msgID = 1;
msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
/* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
msg->base.refCounter = 1;
/* Copy batch onto message (released by delete method) */
msg->base.batch = selfCD->wsheader.instanceBatch;
msg->instance = selfCD->wsheader.instance;
selfCD->wsheader.instanceBatch = 0;
selfCD->wsheader.instance = 0;
}
else
msg = InvokeReq_New(1, WSMANFlag | WSMAN_ObjectFlag);
if (!msg)
goto failed;
/* Parse invoke request/body */
if (WS_ParseInvokeBody(xml, msg->base.batch, &msg->instanceParams) != 0)
goto failed;
/* Extract/set relevant parameters */
if (selfCD->wsheader.rqtNamespace)
msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
msg->className = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtClassname);
msg->function = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtMethod);
/* attach client id */
msg->base.clientID = PtrToUint64(selfCD);
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* increment counter to keep it alive until provider replies */
selfCD->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
InvokeReq_Release(msg);
return;
failed:
LOGW_CHAR(("wsman: unable to process invoke request"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
if (msg)
InvokeReq_Release(msg);
}
static void _ParseValidateProcessGetRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
GetInstanceReq* msg = 0;
MI_UNUSED(xml);
/* Check if instance name parameter was specified */
if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
{
LOGW_CHAR(("wsman: get-instance: instance name parameter is missing"));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("get-instance: instance name parameter is missing"));
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* if instance was created from batch, re-use exisintg batch to allocate message */
/* Allocate heap space for message */
msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(GetInstanceReq));
if (!msg)
goto failed;
/* Set the tag */
msg->base.tag = GetInstanceReqTag;
/* Set the message id and flags */
msg->base.msgID = 1;
msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
/* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
msg->base.refCounter = 1;
/* Copy batch into message (released by delete method) */
msg->base.batch = selfCD->wsheader.instanceBatch;
msg->instanceName = selfCD->wsheader.instance;
/* clear batch/instance fields in header structure */
selfCD->wsheader.instanceBatch = 0;
selfCD->wsheader.instance = 0;
/* Skip parsing get-request/body - assumed to be empty */
/* Extract/set relevant parameters */
if (selfCD->wsheader.rqtNamespace)
msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
/* attach client id */
msg->base.clientID = PtrToUint64(selfCD);
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* increment counter to keep it alive until provider replies */
selfCD->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
GetInstanceReq_Release(msg);
return;
failed:
LOGW_CHAR(("wsman: unable to process get-instance request"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
if (msg)
GetInstanceReq_Release(msg);
}
static void _ParseValidateProcessPutRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
ModifyInstanceReq* msg = 0;
MI_UNUSED(xml);
/* Check if instance name parameter was specified */
if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
{
LOGW_CHAR(("wsman: Put-instance: instance name parameter is missing"));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("Put-instance: instance name parameter is missing"));
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* if instance was created from batch, re-use exisintg batch to allocate message */
/* Allocate heap space for message */
msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(ModifyInstanceReq));
if (!msg)
goto failed;
/* Set the tag */
msg->base.tag = ModifyInstanceReqTag;
/* Set the message id and flags */
msg->base.msgID = 1;
msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
/* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
msg->base.refCounter = 1;
/* Copy batch into message (released by delete method) */
msg->base.batch = selfCD->wsheader.instanceBatch;
msg->instance = selfCD->wsheader.instance;
/* clear batch/instance fields in header structure */
selfCD->wsheader.instanceBatch = 0;
selfCD->wsheader.instance = 0;
/* re-use 'create' parser to parse 'Modify' request/body */
if (WS_ParseCreateBody(xml, msg->base.batch, &msg->instance) != 0)
goto failed;
/* Extract/set relevant parameters */
if (selfCD->wsheader.rqtNamespace)
msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
/* attach client id */
msg->base.clientID = PtrToUint64(selfCD);
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* increment counter to keep it alive until provider replies */
selfCD->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
ModifyInstanceReq_Release(msg);
return;
failed:
LOGW_CHAR(("wsman: unable to process Put-instance request"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
if (msg)
ModifyInstanceReq_Release(msg);
}
static void _ParseValidateProcessDeleteRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
DeleteInstanceReq* msg = 0;
MI_UNUSED(xml);
/* Check if instance name parameter was specified */
if (!selfCD->wsheader.instance || !selfCD->wsheader.instanceBatch)
{
LOGW_CHAR(("wsman: delete-instance: instance name parameter is missing"));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_INTERNAL_ERROR, T("delete-instance: instance name parameter is missing"));
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* if instance was created from batch, re-use exisintg batch to allocate message */
/* Allocate heap space for message */
msg = Batch_GetClear(selfCD->wsheader.instanceBatch, sizeof(DeleteInstanceReq));
if (!msg)
goto failed;
/* Set the tag */
msg->base.tag = DeleteInstanceReqTag;
/* Set the message id and flags */
msg->base.msgID = 1;
msg->base.flags = WSMANFlag | WSMAN_ObjectFlag;
/* ref-counter is set to 1, to balance NewMessage/Release Message pair*/
msg->base.refCounter = 1;
/* Copy batch into message (released by delete method) */
msg->base.batch = selfCD->wsheader.instanceBatch;
msg->instanceName = selfCD->wsheader.instance;
/* clear batch/instance fields in header structure */
selfCD->wsheader.instanceBatch = 0;
selfCD->wsheader.instance = 0;
/* Skip parsing Delete-request/body - assumed to be empty */
/* Extract/set relevant parameters */
if (selfCD->wsheader.rqtNamespace)
msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
/* attach client id */
msg->base.clientID = PtrToUint64(selfCD);
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* increment counter to keep it alive until provider replies */
selfCD->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
DeleteInstanceReq_Release(msg);
return;
failed:
LOGW_CHAR(("wsman: unable to process delete-instance request"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
if (msg)
DeleteInstanceReq_Release(msg);
}
static void _ParseValidateProcessCreateRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
CreateInstanceReq* msg = 0;
msg = CreateInstanceReq_New(1, WSMANFlag | WSMAN_CreatedEPRFlag);
if (!msg)
goto failed;
/* Parse create request/body */
if (WS_ParseCreateBody(xml, msg->base.batch, &msg->instance) != 0)
goto failed;
/* Extract/set relevant parameters */
if (selfCD->wsheader.rqtNamespace)
msg->nameSpace = Batch_Strdup2(msg->base.batch, selfCD->wsheader.rqtNamespace);
/* attach client id */
msg->base.clientID = PtrToUint64(selfCD);
msg->base.uid = selfCD->uid;
msg->base.gid = selfCD->gid;
/* increment counter to keep it alive until provider replies */
selfCD->refcounter++;
(*self->callback)(self, &msg->base, self->callbackData);
CreateInstanceReq_Release(msg);
return;
failed:
LOGW_CHAR(("wsman: unable to process Create request"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
if (msg)
CreateInstanceReq_Release(msg);
}
static void _ParseValidateProcessPullRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
/* Parse pull request/body */
if (WS_ParsePullBody(xml, &selfCD->u.wsenumpullbody) != 0)
{
LOGW_CHAR(("wsman: unable to parse incoming xml/ Pull request body"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* Validate enumerate request body */
if (_ValidatePullRequest(http, selfCD) != 0)
{
/* appropriate error code was already sent to the client */
return;
}
/* Process reqest */
_ProcessPullRequest(http,self,selfCD);
}
static void _ParseValidateProcessReleaseRequest(
Http* http,
void* httpConnectionHandle,
WSMAN* self,
WSMAN_ConnectionData* selfCD,
XML* xml)
{
/* Parse pull request/body */
if (WS_ParseReleaseBody(xml, &selfCD->u.wsenumpullbody) != 0)
{
LOGW_CHAR(("wsman: unable to parse incoming xml/ Release request body"));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
return;
}
/* Validate enumerate request body */
/* no validation needed */
/* Process reqest */
_ProcessReleaseRequest(http,self,selfCD);
}
/************************************************************************\
* Dispatcher calls processing
\************************************************************************/
static void _EC_GetMessageSubset(
WSMAN_EnumerateContext* selfEC,
WSMAN_ConnectionData* selfCD,
PostInstanceMsg** subsetEnd,
MI_Uint32* totalSize)
{
MI_Uint32 count = 0;
*totalSize = 0;
*subsetEnd = selfEC->head;
while (*subsetEnd)
{
if (count + 1 > selfCD->u.wsenumpullbody.maxElements ||
(*totalSize) + (*subsetEnd)->packedInstanceSize + WSMAN_APROX_ENUM_RESP_HEADER_SIZE > selfCD->wsheader.maxEnvelopeSize)
break;
(*totalSize) += (*subsetEnd)->packedInstanceSize;
count++;
(*subsetEnd) = (PostInstanceMsg*)(*subsetEnd)->base.next;
}
}
/* Sends as many instances as posisble (based on envelope-size and instance counter) */
static void _SendEnumPullResponse(
WSMAN* self,
WSMAN_EnumerateContext* selfEC)
{
WS_Buffer outBufHeader, outBufTrailer;
Page* responsePageCombined = 0;
Page* responsePageHeader = 0;
Page* responsePageTrailer = 0;
MI_Uint32 totalSize, messagesSize = 0;
WSMAN_ConnectionData* selfCD = selfEC->activeConnection;
PostInstanceMsg* subsetEnd = 0;
MI_Boolean endOfSequence = selfEC->enumerationCompleted;
/* Get message subset based on envelope size/ maxElements */
_EC_GetMessageSubset(selfEC, selfCD, &subsetEnd, &messagesSize);
/* validate if all mesages can be sent */
if (endOfSequence && subsetEnd)
{
endOfSequence = MI_FALSE;
}
/* check if we can put at least one message in response */
if (NULL != selfEC->head &&
subsetEnd == selfEC->head)
{
LOGW_CHAR(("wsman: max-envelope is too small even for one message; message size %d",
(int)subsetEnd->packedInstanceSize ));
_SendFaultResponse(self->http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, T("insufficient envelope size for instance transferring"));
/* Note: leaving context 'as is' so advanced client can increase packet size and re-try */
return;
}
/* Create EnumResponse */
if (WSBuf_Init(&outBufHeader, WSMAN_APROX_ENUM_RESP_HEADER_SIZE) != MI_RESULT_OK)
{
outBufTrailer.page = 0;
goto failed;
}
if (WSBuf_Init(&outBufTrailer, 256) != MI_RESULT_OK)
goto failed;
/* prepare response header */
if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
{
if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
LIT(T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse")), selfCD->wsheader.rqtMessageID))
goto failed;
}
else
{
if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBufHeader,
LIT(T("http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse")), selfCD->wsheader.rqtMessageID))
goto failed;
}
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("</SOAP-ENV:Header>")
T("<SOAP-ENV:Body>"))))
goto failed;
if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("<wsen:EnumerateResponse>"))))
goto failed;
}
else
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("<wsen:PullResponse>"))))
goto failed;
}
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("<wsen:EnumerationContext>"))))
goto failed;
if (MI_RESULT_OK != WSBuf_AddUint32(&outBufHeader,selfEC->enumerationContextID))
goto failed;
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("</wsen:EnumerationContext>"))))
goto failed;
if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("<wsman:Items>"))))
goto failed;
}
else
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufHeader,
LIT(T("<wsen:Items>"))))
goto failed;
}
/* trailer */
if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("</wsman:Items>"))))
goto failed;
}
else
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("</wsen:Items>"))))
goto failed;
}
if (endOfSequence)
{
if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("<wsman:EndOfSequence/>"))))
goto failed;
}
else
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("<wsen:EndOfSequence/>"))))
goto failed;
}
}
if (selfCD->wsheader.rqtAction == WSMANTAG_ACTION_ENUMERATE)
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("</wsen:EnumerateResponse>"))))
goto failed;
}
else
{
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("</wsen:PullResponse>"))))
goto failed;
}
if (MI_RESULT_OK != WSBuf_AddLit(&outBufTrailer,
LIT(T("</SOAP-ENV:Body>")
T("</SOAP-ENV:Envelope>"))))
goto failed;
/* all together */
responsePageHeader = WSBuf_StealPage(&outBufHeader);
responsePageTrailer = WSBuf_StealPage(&outBufTrailer);
if (!responsePageTrailer || !responsePageHeader)
goto failed;
/* calculate size */
totalSize = (MI_Uint32)(responsePageHeader->u.s.size + responsePageTrailer->u.s.size) + messagesSize;
responsePageCombined = (Page*)malloc(sizeof(Page) + totalSize + 1);
if (!responsePageCombined)
goto failed;
{
char* data = (char*) (responsePageCombined + 1);
data[totalSize] = 0;
memcpy(data, responsePageHeader+1, responsePageHeader->u.s.size);
data += responsePageHeader->u.s.size;
{
PostInstanceMsg* msg = selfEC->head;
while (msg != subsetEnd)
{
PostInstanceMsg* next = (PostInstanceMsg*)msg->base.next;
memcpy(data, msg->packedInstancePtr, msg->packedInstanceSize);
data += msg->packedInstanceSize;
/* remove message from the list */
selfEC->totalResponses--;
selfEC->totalResponseSize -= msg->packedInstanceSize;
List_Remove(
(ListElem**)&selfEC->head,
(ListElem**)&selfEC->tail,
(ListElem*)msg);
PostInstanceMsg_Release(msg);
msg = next;
}
}
memcpy(data, responsePageTrailer+1, responsePageTrailer->u.s.size);
data += responsePageTrailer->u.s.size;
responsePageCombined->u.s.size = totalSize;
responsePageCombined->u.s.next = 0;
}
free(responsePageHeader); responsePageHeader = 0;
free(responsePageTrailer); responsePageTrailer = 0;
/* Trace the response XML */
if (self->options.enableTracing)
{
printf("%s\n\n", (char*)(responsePageCombined+1));
}
/*{
FILE* f = Fopen("out_test.xml", "a");
fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
fclose(f);
}*/
Http_SendResponse(
self->http,
selfCD->httpConnectionHandle,
HTTP_ERROR_CODE_OK,
&responsePageCombined);
selfCD->outstandingRequest = MI_FALSE;
if (responsePageCombined)
free(responsePageCombined);
return;
failed:
WSBuf_Destroy(&outBufHeader);
WSBuf_Destroy(&outBufTrailer);
if (responsePageCombined) free(responsePageCombined);
if (responsePageHeader) free(responsePageHeader);
if (responsePageTrailer) free(responsePageTrailer);
_EC_ReleaseAllMessages(selfEC);
Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
selfCD->outstandingRequest = MI_FALSE;
}
static void _SendInvokeResponse(
WSMAN* self,
WSMAN_ConnectionData* selfCD,
PostInstanceMsg* message)
{
WS_Buffer outBuf;
Page* responsePage = 0;
MI_Char* action = 0;
MI_Uint32 actionLen;
/* create action */
actionLen = (MI_Uint32)(7 /* http:// */ +
27 /* "/wbem/wscim/1/cim-schema/2/" */ +
1 /* / between cn/meth */ +
1 /* \0 at the end */ +
strlen(selfCD->wsheader.rqtServer) +
strlen(selfCD->wsheader.rqtClassname) +
strlen(selfCD->wsheader.rqtMethod));
action = (MI_Char*)malloc(actionLen * sizeof(MI_Char));
if (!action)
goto failed;
#if (MI_CHAR_TYPE == 1)
//Snprintf(action, actionLen, T("http://%s/wbem/wscim/1/cim-schema/2/%s/%s"),
// selfCD->wsheader.rqtServer, selfCD->wsheader.rqtClassname, selfCD->wsheader.rqtMethod);
{
MI_Uint32 size;
action[0] = 0;
size = Strlcat(action, "http://", actionLen);
size += Strlcat(action + size, selfCD->wsheader.rqtServer, actionLen - size);
size += Strlcat(action + size, "/wbem/wscim/1/cim-schema/2/", actionLen - size);
size += Strlcat(action + size, selfCD->wsheader.rqtClassname, actionLen - size);
size += Strlcat(action + size, "/", actionLen - size);
size += Strlcat(action + size, selfCD->wsheader.rqtMethod, actionLen - size);
assert(size == (actionLen-1));
}
#else
Szprintf(action, actionLen, T("http://%S/wbem/wscim/1/cim-schema/2/%S/%S"),
selfCD->wsheader.rqtServer, selfCD->wsheader.rqtClassname, selfCD->wsheader.rqtMethod);
#endif
actionLen--;
/* Create EnumResponse */
if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
goto failed;
/* prepare response header */
if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
action, actionLen, selfCD->wsheader.rqtMessageID))
goto failed;
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
LIT(T("</SOAP-ENV:Header>")
T("<SOAP-ENV:Body>")
T("<n1:ExecuteCommand_OUTPUT xmlns:n1=\"")
)))
goto failed;
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
action, actionLen))
goto failed;
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
LIT(T("\">"))))
goto failed;
if (MI_RESULT_OK != WSBuf_AddCharLit(&outBuf,
message->packedInstancePtr, message->packedInstanceSize))
goto failed;
/* trailer */
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
LIT(
T("</n1:ExecuteCommand_OUTPUT>")
T("</SOAP-ENV:Body>")
T("</SOAP-ENV:Envelope>"))))
goto failed;
/* all together */
responsePage = WSBuf_StealPage(&outBuf);
if (!responsePage)
goto failed;
/* Trace the response XML */
if (self->options.enableTracing)
{
printf("%s\n\n", (char*)(responsePage+1));
}
/*{
FILE* f = Fopen("out_test.xml", "a");
fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
fclose(f);
}*/
Http_SendResponse(
self->http,
selfCD->httpConnectionHandle,
HTTP_ERROR_CODE_OK,
&responsePage);
/* indicate that response was sent */
selfCD->outstandingRequest = MI_FALSE;
if (responsePage)
free(responsePage);
if (action)
free(action);
return;
failed:
WSBuf_Destroy(&outBuf);
if (responsePage) free(responsePage);
if (action) free(action);
Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
/* indicate that response was sent */
selfCD->outstandingRequest = MI_FALSE;
}
static void _SendSingleInstanceResponse(
WSMAN* self,
WSMAN_ConnectionData* selfCD,
PostInstanceMsg* message,
const MI_Char* action,
MI_Uint32 actionSize)
{
WS_Buffer outBuf;
Page* responsePage = 0;
if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE + message->packedInstanceSize) != MI_RESULT_OK)
goto failed;
if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
action, actionSize, selfCD->wsheader.rqtMessageID))
goto failed;
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
LIT(T("</SOAP-ENV:Header>")
T("<SOAP-ENV:Body>")
)))
goto failed;
if (MI_RESULT_OK != WSBuf_AddCharLit(&outBuf,
message->packedInstancePtr, message->packedInstanceSize))
goto failed;
/* trailer */
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
LIT(
T("</SOAP-ENV:Body>")
T("</SOAP-ENV:Envelope>"))))
goto failed;
/* all together */
responsePage = WSBuf_StealPage(&outBuf);
if (!responsePage)
goto failed;
/* Trace the response XML */
if (self->options.enableTracing)
{
printf("%s\n\n", (char*)(responsePage+1));
}
/* {
FILE* f = Fopen("out_test.xml", "a");
fwrite((char*)(responsePage+1), 1, (size_t)responsePage->u.s.size, f);
fclose(f);
} */
Http_SendResponse(
self->http,
selfCD->httpConnectionHandle,
HTTP_ERROR_CODE_OK,
&responsePage);
/* indicate that response was sent */
selfCD->outstandingRequest = MI_FALSE;
if (responsePage)
free(responsePage);
return;
failed:
WSBuf_Destroy(&outBuf);
if (responsePage) free(responsePage);
Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
/* indicate that response was sent */
selfCD->outstandingRequest = MI_FALSE;
}
static void _SendDeleteInstanceResponse(
WSMAN* self,
WSMAN_ConnectionData* selfCD)
{
WS_Buffer outBuf;
Page* responsePage = 0;
if (WSBuf_Init(&outBuf, WSMAN_APROX_ENUM_RESP_HEADER_SIZE) != MI_RESULT_OK)
goto failed;
if (MI_RESULT_OK != WSBuf_CreateSoapResponseHeader(&outBuf,
LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/DeleteResponse")), selfCD->wsheader.rqtMessageID))
goto failed;
if (MI_RESULT_OK != WSBuf_AddLit(&outBuf,
LIT(T("</SOAP-ENV:Header>")
T("<SOAP-ENV:Body/>")
T("</SOAP-ENV:Envelope>")
)))
goto failed;
/* all together */
responsePage = WSBuf_StealPage(&outBuf);
if (!responsePage)
goto failed;
/* Trace the response XML */
if (self->options.enableTracing)
{
printf("%s\n\n", (char*)(responsePage+1));
}
/*{
FILE* f = Fopen("out_test.xml", "a");
fwrite((char*)(responsePageCombined+1), 1, (size_t)responsePageCombined->u.s.size, f);
fclose(f);
}*/
Http_SendResponse(
self->http,
selfCD->httpConnectionHandle,
HTTP_ERROR_CODE_OK,
&responsePage);
/* indicate that response was sent */
selfCD->outstandingRequest = MI_FALSE;
if (responsePage)
free(responsePage);
return;
failed:
WSBuf_Destroy(&outBuf);
if (responsePage) free(responsePage);
Http_SendErrorResponse(self->http, selfCD->httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
/* indicate that response was sent */
selfCD->outstandingRequest = MI_FALSE;
}
static void _SendErrorResponse(
WSMAN* self,
WSMAN_ConnectionData* selfCD,
MI_Result result)
{
WSBUF_FAULT_CODE faultCode;
const MI_Char* description = 0;
faultCode = WSBuf_CIMErrorToWSFault(result, &description);
/* ATTN! consume text from cim_error if supplied */
_SendFaultResponse(self->http, selfCD, faultCode, description);
}
/* Function processes backlog in enumeration context;
returns true if message was sent to active connection;
once last repsonse is sent, it deletes context */
static MI_Boolean _ProcessEnumResponse(
WSMAN* self,
WSMAN_EnumerateContext* selfEC,
MI_Boolean attachingPullRequest)
{
/* do we have connected cleint to send response to? */
if (!selfEC->activeConnection)
return MI_FALSE;
if (selfEC->enumerationCompleted && selfEC->finalResult != MI_RESULT_OK)
{
_SendErrorResponse(self, selfEC->activeConnection, selfEC->finalResult);
/* release context */
_EC_SetActiveConnection(selfEC, 0);
_WSMAN_ReleaseEnumerateContext(self, selfEC->enumerationContextID);
selfEC = 0;
return MI_TRUE;
}
/* Check if partial response has to be sent (or enumeration is completed) */
/* Update: send anything that is available once client re-connects with pull */
/* Send resposne now if:
- enumeration is complete
- queue has enough instances to fill entire packet (by size or number)
- pull request arrives. Normally, network is lsower than providers,
so once client returns with next pull request, lets send all messages
we have in queue
- server is stressed (too many instances)
*/
if (selfEC->enumerationCompleted ||
WSMAN_APROX_ENUM_RESP_HEADER_SIZE + selfEC->totalResponseSize > selfEC->activeConnection->wsheader.maxEnvelopeSize ||
selfEC->totalResponses >= selfEC->activeConnection->u.wsenumpullbody.maxElements ||
(attachingPullRequest && selfEC->head) ||
(Selector_IsStressed(self->selector) && selfEC->head)
)
//if (selfEC->enumerationCompleted || selfEC->head)
{
//LOGW_CHAR(("processing responses %d", selfEC->totalResponses));
_SendEnumPullResponse(self, selfEC);
_EC_SetActiveConnection(selfEC, 0);
}
/* release context if last message was sent */
if (selfEC->enumerationCompleted && !selfEC->head)
{
_EC_SetActiveConnection(selfEC, 0);
_WSMAN_ReleaseEnumerateContext(self, selfEC->enumerationContextID);
selfEC = 0;
}
else
{
/* set/update timer */
_WSMAN_SetUpdateTimer(self, selfEC);
}
return MI_TRUE;
}
static void _ProcessResultEnumerationContext(
WSMAN* self,
WSMAN_EnumerateContext* selfEC,
PostResultMsg* message )
{
/* mark context as 'completed' */
selfEC->enumerationCompleted = MI_TRUE;
selfEC->finalResult = message->result;
//ATTN!: process error text/messages
_ProcessEnumResponse(self, selfEC, MI_FALSE);
/* release context */
_EC_Release(selfEC, MI_FALSE);
}
static void _ProcessInstanceResponse(
WSMAN* self,
WSMAN_ConnectionData* selfCD,
PostInstanceMsg* message)
{
/* send appropriate response */
switch (selfCD->wsheader.rqtAction)
{
case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
_SendInvokeResponse(self, selfCD, message);
break;
case WSMANTAG_ACTION_GET:
_SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")));
break;
case WSMANTAG_ACTION_PUT:
_SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse")));
break;
case WSMANTAG_ACTION_CREATE:
_SendSingleInstanceResponse(self, selfCD, message, LIT(T("http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse")));
break;
default:
/* unexpected */
_SendFaultResponse(
self->http,
selfCD,
WSBUF_FAULT_INTERNAL_ERROR,
T("unexpected internal state"));
break;
}
selfCD->outstandingRequest = MI_FALSE;
}
static void _ProcessResultConnectionData(
WSMAN* self,
WSMAN_ConnectionData* selfCD,
PostResultMsg* message )
{
/* if response was not sent yet, send it now (error probably) */
if (selfCD->outstandingRequest)
{
if (selfCD->single_message)
{
_ProcessInstanceResponse(self, selfCD, selfCD->single_message);
}
else if (MI_RESULT_OK == message->result &&
WSMANTAG_ACTION_DELETE == selfCD->wsheader.rqtAction)
{
_SendDeleteInstanceResponse(self, selfCD);
}
else
{
_SendErrorResponse(self, selfCD, message->result);
}
selfCD->outstandingRequest = MI_FALSE;
}
/* release connection data */
_CD_Release(selfCD);
}
static void _ProcessInstanceConnectionData(
WSMAN* self,
WSMAN_ConnectionData* selfCD,
PostInstanceMsg* message)
{
MI_UNUSED(self);
/* Ignore expired contexts */
if (!selfCD->outstandingRequest)
return;
_CD_SetSingleMessage(selfCD, message);
}
static void _ProcessInstanceEnumerationContext(
WSMAN* self,
WSMAN_EnumerateContext* selfEC,
PostInstanceMsg* message )
{
/* Ignore expired contexts */
if (selfEC->expired)
return;
/* add-ref message to keep it alive */
Message_AddRef( &message->base);
/* Add it to the list to process when result is posted */
List_Append(
(ListElem**)&selfEC->head,
(ListElem**)&selfEC->tail,
(ListElem*)message);
/* Increment total instance size */
selfEC->totalResponseSize += message->packedInstanceSize;
/* Increment total number of responses */
selfEC->totalResponses++;
/* Check if we need to send response to the client */
_ProcessEnumResponse(self, selfEC, MI_FALSE);
}
/* HTTP callbacks */
static void _HttpCallbackOnNewConnection(
Http* http,
void* callbackData,
void* httpConnectionHandle,
void** connectionData)
{
WSMAN_ConnectionData* selfConnectionData;
MI_UNUSED(http);
MI_UNUSED(callbackData);
selfConnectionData = (WSMAN_ConnectionData*)calloc(1, sizeof(WSMAN_ConnectionData));
if (!selfConnectionData)
return /*MI_RESULT_FAILED*/;
selfConnectionData->httpConnectionHandle = httpConnectionHandle;
selfConnectionData->refcounter = 1;
selfConnectionData->tag = DATA_TAG_CONNECTION_DATA;
*connectionData = selfConnectionData;
}
static void _HttpCallbackOnCloseConnection(
Http* http,
void* callbackData,
void* connectionData)
{
MI_UNUSED(http);
MI_UNUSED(callbackData);
if (connectionData)
{
WSMAN_ConnectionData* selfConnectionData = (WSMAN_ConnectionData*)connectionData;
selfConnectionData->httpConnectionHandle = 0;
selfConnectionData->outstandingRequest = MI_FALSE;
_CD_Release(selfConnectionData);
}
}
static void _HttpCallbackOnRequest(
Http* http,
void* callbackData,
void* connectionData,
void* httpConnectionHandle,
const HttpHeaders* headers,
Page** page)
{
WSMAN_ConnectionData* selfCD = (WSMAN_ConnectionData*)connectionData;
WSMAN* self = (WSMAN*)callbackData;
XML xml = self->xml;
/* Trace the request XML */
if (self->options.enableTracing)
{
printf("TRACE:%u\n", __LINE__);
printf("%s\n\n", (const char*)((*page)+1));
}
/* Cleanup connection data, since it may still store allocated pointers
from previous operation */
_CD_Cleanup(selfCD);
/* Verify content type */
if ( !headers->contentType ||
(Strcasecmp(headers->contentType,"application/soap+xml") != 0 &&
Strcasecmp(headers->contentType,"text/xml") != 0))
{
LOGW_CHAR(("wsman: invalid/missing content type in request [%s]", (const char*)((*page)+1) ));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_BAD_REQUEST);
printf("TRACE:%u\n", __LINE__);
return;
}
if (headers->charset &&
Strcasecmp(headers->charset,"utf-8") != 0)
{
LOGW_CHAR(("wsman: charset is not supported [%s]", MI_GET_SAFE_PRINTF_STRING(headers->charset) ));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_ENCODING_LIMIT, T("only utf 8 is supported"));
printf("TRACE:%u\n", __LINE__);
return;
}
if (!headers->username || !headers->password ||
0 != AuthenticateUser(headers->username, headers->password))
{
LOGW_CHAR(("wsman: authentication failed for user [%s]", MI_GET_SAFE_PRINTF_STRING(headers->username) ));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_UNAUTHORIZED);
printf("TRACE:%u\n", __LINE__);
return;
}
if (0 != LookupUser(headers->username, &selfCD->uid, &selfCD->gid))
{
LOGW_CHAR(("wsman: get user [%s] uid/gid", MI_GET_SAFE_PRINTF_STRING(headers->username) ));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
printf("TRACE:%u\n", __LINE__);
return;
}
XML_SetText(&xml, (char*)((*page)+1) );
/* Parse header */
if (WS_ParseSoapEnvelope(&xml) != 0 ||
WS_ParseWSHeader(&xml, &selfCD->wsheader) != 0 ||
xml.status)
{
LOGW_CHAR(("wsman: unable to parse incoming xml [%s] ", (const char*)((*page)+1) ));
Http_SendErrorResponse(http, httpConnectionHandle, HTTP_ERROR_CODE_INTERNAL_SERVER_ERROR);
printf("TRACE:%u\n", __LINE__);
return;
}
/* Validate header */
if (_ValidateHeader(http, selfCD) != 0)
{
/*
ATTN:MEB
*/
printf("TRACE:%u\n", __LINE__);
return;
}
/* keep reference to the page to keep xml object/ cached strings like msgID valid */
_CD_SetPage(selfCD, *page);
*page = 0;
selfCD->outstandingRequest = MI_TRUE;
printf("TRACE:%u\n", __LINE__);
/* Parse body and send request to the dispatcher */
switch (selfCD->wsheader.rqtAction)
{
case WSMANTAG_ACTION_ENUMERATE:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessEnumerateRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case WSMANTAG_ACTION_PULL:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessPullRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case WSMANTAG_ACTION_RELEASE:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessReleaseRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case WSMANTAG_ACTION_GET:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessGetRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case WSMANTAG_ACTION_PUT:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessPutRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case WSMANTAG_ACTION_DELETE:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessDeleteRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case WSMANTAG_ACTION_CREATE:
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessCreateRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
case 0: /* since invoke does not have strict URI, we got it as 'undefined' */
printf("TRACE:%u\n", __LINE__);
_ParseValidateProcessInvokeRequest(http, httpConnectionHandle, self, selfCD, &xml);
break;
default:
printf("TRACE:%u\n", __LINE__);
/* unsupported action */
LOGW_CHAR(("wsman: unsupported action [%d] ", selfCD->wsheader.rqtAction ));
_SendFaultResponse(http, selfCD, WSBUF_FAULT_NOT_SUPPORTED, 0);
selfCD->outstandingRequest = MI_FALSE;
break;
}
}
/*
**==============================================================================
**
** Public definitions:
**
**==============================================================================
*/
MI_Result WSMAN_New_Listener(
WSMAN** selfOut,
Selector* selector, /*optional, maybe NULL*/
unsigned short http_port, /* 0 to disable */
unsigned short https_port, /* 0 to disable */
WSMANCallback callback,
void* callbackData)
{
WSMAN* self;
MI_Result r;
/* Check parameters */
if (!selfOut)
return MI_RESULT_INVALID_PARAMETER;
/* Clear output parameter */
*selfOut = NULL;
/* Allocate structure */
{
self = (WSMAN*)calloc(1, sizeof(WSMAN));
if (!self)
return MI_RESULT_FAILED;
}
/* Save the callback and callbackData */
self->callback = callback;
self->callbackData = callbackData;
/*ATTN! slector can be null!*/
self->selector = selector;
/* options */
{
WSMAN_Options options = DEFAULT_WSMAN_OPTIONS;
self->options = options;
}
/* Set the magic number */
self->magic = _MAGIC;
/* create a server */
r = Http_New_Server(
&self->http, selector, http_port, https_port,
_HttpCallbackOnNewConnection,
_HttpCallbackOnCloseConnection,
_HttpCallbackOnRequest, self);
if (MI_RESULT_OK != r)
{
WSMAN_Delete(self);
return r;
}
/* Initialize xml parser */
XML_Init(&self->xml);
XML_RegisterNameSpace(&self->xml, 's',
"http://www.w3.org/2003/05/soap-envelope");
XML_RegisterNameSpace(&self->xml, 'a',
"http://schemas.xmlsoap.org/ws/2004/08/addressing");
XML_RegisterNameSpace(&self->xml, 'w',
"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd");
XML_RegisterNameSpace(&self->xml, 'n',
"http://schemas.xmlsoap.org/ws/2004/09/enumeration");
XML_RegisterNameSpace(&self->xml, 'b',
"http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd");
XML_RegisterNameSpace(&self->xml, 'p',
"http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd");
XML_RegisterNameSpace(&self->xml, 'i',
"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd");
*selfOut = self;
return MI_RESULT_OK;
}
MI_Result WSMAN_Delete(
WSMAN* self)
{
/* Check parameters */
if (!self)
return MI_RESULT_INVALID_PARAMETER;
/* Check magic number */
if (self->magic != _MAGIC)
return MI_RESULT_INVALID_PARAMETER;
Http_Delete(self->http);
/* clear all outstanding contexts */
_WSMAN_ReleaseAllEnumerateContexts(self);
/* Clear magic number */
self->magic = 0xDDDDDDDD;
/* Free self pointer */
free(self);
return MI_RESULT_OK;
}
MI_Result WSMAN_Run(
WSMAN* self,
MI_Uint64 timeoutUsec)
{
/* Run the selector */
return Http_Run(self->http, timeoutUsec);
}
static MI_Result _SendIN_IO_thread(
void* self_,
Message* message)
{
WSMAN* self = (WSMAN*)self_;
WSMAN_ConnectionData* selfCD = 0;
WSMAN_EnumerateContext* selfEC = 0;
/* check params */
if (!self || !message )
return MI_RESULT_INVALID_PARAMETER;
if (self->magic != _MAGIC)
{
LOGW((T("_SendIN_IO_thread: invalid magic!") ));
return MI_RESULT_INVALID_PARAMETER;
}
/* find where to send it */
selfCD = (WSMAN_ConnectionData*)Uint64ToPtr(message->clientID);
selfEC = (WSMAN_EnumerateContext*)Uint64ToPtr(message->clientID);
if (selfCD && selfCD->tag != DATA_TAG_CONNECTION_DATA)
{
selfCD = 0;
}
if (selfEC && selfEC->tag != DATA_TAG_ENUMERATION_CONTEXT)
{
selfEC = 0;
}
if (!selfCD && !selfEC)
{
LOGW((T("_SendIN_IO_thread: clientID!") ));
return MI_RESULT_INVALID_PARAMETER;
}
/* ATTN! validate handler */
/* Process response message */
switch (message->tag)
{
case PostResultMsgTag:
if (selfCD)
_ProcessResultConnectionData(self, selfCD, (PostResultMsg*)message );
else
_ProcessResultEnumerationContext(self, selfEC, (PostResultMsg*)message );
break;
case PostInstanceMsgTag:
if (selfCD)
_ProcessInstanceConnectionData(self, selfCD, (PostInstanceMsg*)message );
else
_ProcessInstanceEnumerationContext(self, selfEC, (PostInstanceMsg*)message );
break;
default:
LOGW((T("wsman: _SendIN_IO_thread: unexpected message tag %d"), message->tag ));
return MI_RESULT_INVALID_PARAMETER;
}
return MI_RESULT_OK;
}
/* Signature must not have return type so we created this wrapper */
static void _SendIN_IO_thread_wrapper(void* self, Message* message)
{
MI_Result r;
r = _SendIN_IO_thread(self, message);
/* ATTN: log failed result? */
}
MI_Result WSMAN_Send(
WSMAN* self,
Message* message)
{
return Selector_CallInIOThread(
self->selector, _SendIN_IO_thread_wrapper, self, message );
}
MI_Result WSMAN_SetOptions(
WSMAN* self,
const WSMAN_Options* options)
{
/* check params */
if (!self || !options)
return MI_RESULT_INVALID_PARAMETER;
/* Check magic number */
if (self->magic != _MAGIC)
{
LOGW((T("invalid magic!") ));
return MI_RESULT_INVALID_PARAMETER;
}
self->options = *options;
return MI_RESULT_OK;
}