blob: 706989268a8f3a71e0780c479fc4639d28c57738 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2004-2007 Intel Corp. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of Intel Corp. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/**
* @author Liang Hou
*/
#include "wsman-faults.h"
#include "wsman-soap.h"
#include "wsman-names.h"
#include "wsman-soap-message.h"
#include "wsman-soap-envelope.h"
#include "wsman-xml-api.h"
#include "wsman-xml.h"
#include "wsman-event-pool.h"
#include "wsman-cimindication-processor.h"
static int isvalidCIMIndicationExport(WsXmlDocH doc){
if(doc == NULL) return 0;
WsXmlNodeH node = ws_xml_get_doc_root(doc);
WsXmlNodeH temp = NULL;
node = ws_xml_get_child(node, 0, NULL, CIMXML_MESSAGE);
temp = ws_xml_get_child(node, 0, NULL, CIMXML_SIMPLEEXPREQ);
if(temp == NULL) {
temp = ws_xml_get_child(node, 0, NULL, CIMXML_MULTIEXPREQ);
if(temp == NULL) return 0;
}
return 1;
}
static void cimxml_build_response_msg(WsXmlDocH indoc, WsXmlDocH *outdoc) {
WsXmlDocH doc = NULL;
WsXmlNodeH outnode = NULL;
WsXmlNodeH innode = NULL;
WsXmlNodeH temp = NULL;
WsXmlNodeH temp2 = NULL;
doc = ws_xml_create_doc(NULL, CIMXML_CIM);
outnode = ws_xml_get_doc_root(doc);
innode = ws_xml_get_doc_root(indoc);
// char *value = ws_xml_get_node_attr(WsXmlNodeH node, int index)
ws_xml_add_node_attr(outnode, NULL, CIMXML_CIMVERSION, "2.0");
ws_xml_add_node_attr(outnode, NULL, CIMXML_DTDVERSION, "2.0");
outnode = ws_xml_add_child(outnode, NULL, CIMXML_MESSAGE, NULL);
innode = ws_xml_get_child(innode, 0, NULL, CIMXML_MESSAGE);
int n = ws_xml_get_node_attr_count(innode);
int i = 0;
while(i < n) {
WsXmlAttrH attr = ws_xml_get_node_attr(innode, i);
char *name = ws_xml_get_attr_name(attr);
char *value = ws_xml_get_attr_value(attr);
ws_xml_add_node_attr(outnode, NULL, name, value);
i++;
}
temp = ws_xml_get_child(innode, 0, NULL, CIMXML_SIMPLEEXPREQ);
if(temp) {
outnode = ws_xml_add_child(outnode, NULL, CIMXML_SIMPLEEXPRSP, NULL);
outnode = ws_xml_add_child(outnode, NULL, CIMXML_EXPMETHODRESPONSE, NULL);
ws_xml_add_node_attr(outnode, NULL, CIMXML_NAME, "ExportIndication");
ws_xml_add_child(outnode, NULL, CIMXML_IRETURNVALUE, NULL);
}
else {
temp = ws_xml_get_child(innode, 0, NULL, CIMXML_MULTIEXPREQ);
outnode = ws_xml_add_child(outnode, NULL, CIMXML_MULTIEXPRSQ, NULL);
n = ws_xml_get_child_count(temp);
i = 0;
while(i < n) {
innode = ws_xml_get_child(temp, i, NULL, CIMXML_SIMPLEEXPREQ);
temp2 = ws_xml_add_child(outnode, NULL, CIMXML_EXPMETHODRESPONSE, NULL);
ws_xml_add_node_attr(temp2, NULL, CIMXML_NAME, "ExportIndication");
ws_xml_add_child(temp2, NULL, CIMXML_IRETURNVALUE, NULL);
i++;
}
}
*outdoc = doc;
}
static
char * get_cim_indication_namespace(WsSubscribeInfo *subsInfo, char *classname) {
hscan_t hs;
hnode_t *hn;
char *sub;
if (strstr(subsInfo->uri, XML_NS_CIM_CLASS) != NULL) {
return u_strdup(subsInfo->uri);
}
hash_t *namespaces = subsInfo->vendor_namespaces;
if (namespaces) {
hash_scan_begin(&hs, namespaces);
while ((hn = hash_scan_next(&hs))) {
debug("namespace=%s", (char *) hnode_get(hn));
if ((sub = strstr(classname, (char *) hnode_getkey(hn)))) {
return u_strdup((char *)hnode_get(hn));
}
}
}
return NULL;
}
static WsNotificationInfoH
create_notification_entity(WsSubscribeInfo *subsInfo, WsXmlNodeH node)
{
char *classname = NULL;
char *class_namespace = NULL;
WsXmlNodeH indicationnode = NULL;
WsNotificationInfoH notificationinfo = NULL;
notificationinfo = u_zalloc(sizeof(*notificationinfo));
if (notificationinfo == NULL) {
return NULL;
}
WsXmlNodeH instance = ws_xml_get_child(node, 0, NULL, CIMXML_EXPMETHODCALL);
if (instance == NULL) {
u_free(notificationinfo);
return NULL;
}
instance = ws_xml_get_child(instance, 0, NULL, CIMXML_EXPPARAMVALUE);
if (instance == NULL) {
u_free(notificationinfo);
return NULL;
}
instance = ws_xml_get_child(instance, 0, NULL, CIMXML_INSTANCE);
if (instance == NULL) {
u_free(notificationinfo);
return NULL;
}
WsXmlAttrH attr = ws_xml_find_node_attr(instance, NULL, CIMXML_CLASSNAME);
if (attr) {
classname = ws_xml_get_attr_value(attr);
class_namespace = get_cim_indication_namespace(subsInfo, classname);
notificationinfo->EventAction = u_strdup_printf("%s/%s", class_namespace, classname);
}
notificationinfo->EventContent = ws_xml_create_doc(notificationinfo->EventAction, classname);
indicationnode = ws_xml_get_doc_root(notificationinfo->EventContent);
//Parse "PROPERTY"
int n = 0;
while ( (node = ws_xml_get_child(instance, n++, NULL, CIMXML_PROPERTY)) ) {
attr = ws_xml_find_node_attr(node, NULL, CIMXML_NAME);
char *property = NULL;
char *value = NULL;
if ( attr ) {
property = ws_xml_get_attr_value(attr);
}
value = ws_xml_get_node_text(node);
ws_xml_add_child(indicationnode, notificationinfo->EventAction, property, value);
}
//Parse "PROPERTY.ARRAY"
n = 0;
while ( (node = ws_xml_get_child(instance, n++, NULL, CIMXML_PROPERTYARRAY)) ) {
attr = ws_xml_find_node_attr(node, NULL, CIMXML_NAME);
char *property = NULL;
if ( attr ) {
property = ws_xml_get_attr_value(attr);
WsXmlNodeH valarraynode = ws_xml_get_child(node, 0, NULL, CIMXML_VALUEARRAY);
if ( valarraynode ) {
int m = 0;
WsXmlNodeH valnode = NULL;
while ( (valnode = ws_xml_get_child(valarraynode, m++, NULL, CIMXML_VALUE)) ) {
char *value = ws_xml_get_node_text(valnode);
ws_xml_add_child(indicationnode, notificationinfo->EventAction, property, value);
}
}
}
}
if (class_namespace)
u_free(class_namespace);
return notificationinfo;
}
static
void create_indication_event(WsXmlDocH indoc, WsSubscribeInfo *subsInfo, EventPoolOpSetH opset) {
int count, i;
int retval;
WsNotificationInfoH notificationinfo = NULL;
WsXmlNodeH node = ws_xml_get_doc_root(indoc);
node = ws_xml_get_child(node, 0, NULL, CIMXML_MESSAGE);
WsXmlNodeH tmp = ws_xml_get_child(node, 0, NULL, CIMXML_MULTIEXPREQ);
if(tmp) {
count = ws_xml_get_child_count(tmp);
i = 0;
while(i < count) {
node = ws_xml_get_child(tmp, i, NULL, CIMXML_SIMPLEEXPREQ);
notificationinfo = create_notification_entity(subsInfo, node);
if(notificationinfo == NULL) {
i++;
continue;
}
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PULL)
retval = opset->addpull(subsInfo->subsId, notificationinfo);
else
retval = opset->add(subsInfo->subsId, notificationinfo);
if(retval) {
u_free(notificationinfo->EventAction);
ws_xml_destroy_doc(notificationinfo->EventContent);
u_free(notificationinfo);
}
i++;
}
}
else {
tmp = ws_xml_get_child(node, 0, NULL, CIMXML_SIMPLEEXPREQ);
notificationinfo = create_notification_entity(subsInfo, tmp);
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PULL)
retval = opset->addpull(subsInfo->subsId, notificationinfo);
else
retval = opset->add(subsInfo->subsId, notificationinfo);
if(retval) {
u_free(notificationinfo->EventAction);
ws_xml_destroy_doc(notificationinfo->EventContent);
u_free(notificationinfo);
}
}
}
CimxmlMessage *cimxml_message_new() {
CimxmlMessage *cimxml_msg = u_zalloc(sizeof(CimxmlMessage));
u_buf_create(&cimxml_msg->request);
u_buf_create(&cimxml_msg->response);
cimxml_msg->status.code = CIMXML_STATUS_OK;
return cimxml_msg;
}
void cimxml_message_destroy(CimxmlMessage *msg) {
u_buf_free(msg->request);
u_buf_free(msg->response);
u_free(msg->charset);
u_free(msg);
}
static
void cimxml_set_fault(CimxmlMessage *message, CIMXMLKnownStatusCode status) {
struct cimxml_code_map {
int code;
char *reason_phrase;
};
struct cimxml_code_map maps[] = {
{CIMXML_STATUS_UNSUPPORTED_PROTOCOL_VERSIOIN, "unsupported-protocol-version"},
{CIMXML_STATUS_MULTIPLE_REQUESTS_UNSUPPORTED, "multiple-requests-unsupported"},
{CIMXML_STATUS_UNSUPPORTED_CIM_VERSION, "unsupported-cim-version"},
{CIMXML_STATUS_UNSUPPORTED_DTD_VERSION, "unsupported-dtd-version"},
{CIMXML_STATUS_REQUEST_NOT_VALID, "request-not-valid"},
{CIMXML_STATUS_REQUEST_NOT_WELL_FORMED, "request-not-well-formed"},
{CIMXML_STATUS_REQUEST_NOT_LOOSELY_VALID, "request-not-loosely-valid"},
{CIMXML_STATUS_HEADER_MISMATCH, "header-mismatch"},
{CIMXML_STATUS_UNSUPPORTED_OPERATION, "unsupported-operatioin"},
{0, NULL}
};
int i = 0;
if(message == NULL) return;
while(maps[i].code) {
if(maps[i].code == status) {
message->status.code = status;
message->status.fault_msg = maps[i].reason_phrase;
break;
}
i++;
}
}
void CIM_Indication_call(cimxml_context *cntx, CimxmlMessage *message, void *opaqueData) {
char *response = NULL;
int len;
WsXmlDocH indicationRequest = NULL;
WsXmlDocH indicationResponse = NULL;
SoapH soap = cntx->soap;
char *uuid = cntx->uuid;
WsContextH soapCntx = ws_get_soap_context(soap);
debug("**********in CIM_Indication_call:: %s", u_buf_ptr(message->request));
indicationRequest = ws_xml_read_memory(u_buf_ptr(message->request), u_buf_len(message->request),
message->charset, 0);
if(indicationRequest == NULL) {
debug("error, request cannot be parsed !");
message->http_code = WSMAN_STATUS_BAD_REQUEST;
cimxml_set_fault(message, CIMXML_STATUS_REQUEST_NOT_VALID);
goto DONE;
}
if(!isvalidCIMIndicationExport(indicationRequest)) {
debug("error, invalid cim indication");
message->http_code = WSMAN_STATUS_FORBIDDEN;
cimxml_set_fault(message, CIMXML_STATUS_UNSUPPORTED_OPERATION);
goto DONE;
}
//to do here: put indication in event pool
WsSubscribeInfo *subsInfo = NULL;
list_t *subslist = soapCntx->subscriptionMemList;
lnode_t *node = list_first(subslist);
while(node) {
subsInfo = (WsSubscribeInfo *)node->list_data;
if(!strcmp(subsInfo->subsId, uuid)) break;
node = list_next(subslist, node);
}
if(node == NULL) {
message->http_code = WSMAN_STATUS_NOT_FOUND;
cimxml_set_fault(message, CIMXML_STATUS_REQUEST_NOT_VALID);
debug("error. uuid:%s not registered!", uuid);
goto DONE;
}
EventPoolOpSetH opset = soap->eventpoolOpSet;
create_indication_event(indicationRequest, subsInfo, opset);
cimxml_build_response_msg(indicationRequest, &indicationResponse);
ws_xml_dump_memory_enc(indicationResponse, &response, &len, "utf-8");
u_buf_construct(message->response, response, len, len);
DONE:
u_free(cntx);
ws_xml_destroy_doc(indicationRequest);
ws_xml_destroy_doc(indicationResponse);
}