blob: da610350ad76a5bf916b6bd8526c5e203f401184 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2004-2006 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 Anas Nashif
* @author Eugene Yarmosh
* @author Liang Hou
*/
#ifdef HAVE_CONFIG_H
#include <wsman_config.h>
#endif
#define _GNU_SOURCE
#include "u/libu.h"
#include "wsman-xml-api.h"
#include "wsman-soap.h"
#include "wsman-xml.h"
#include "wsman-dispatcher.h"
#include "wsman-xml-serializer.h"
#include "wsman-xml-serialize.h"
#include "wsman-soap-envelope.h"
#include "wsman-faults.h"
#include "wsman-soap-message.h"
#include "wsman-client-api.h"
#include "wsman-client-transport.h"
/* ENUMERATION */
#define ENUM_EXPIRED(enuminfo, mytime) \
((enumInfo->expires > 0) && \
(enumInfo->expires > mytime))
/**
* Calculate needed space for interface array with Endpoints
* @param interfaces List of interfaces
* @return Needed size of WsManDispatcherInfo
*/
static int
calculate_map_count(list_t * interfaces)
{
int count = 0;
int j;
lnode_t *node = list_first(interfaces);
while (node) {
WsDispatchInterfaceInfo *ifc =
(WsDispatchInterfaceInfo *) node->list_data;
for (j = 0; ifc->endPoints[j].serviceEndPoint != NULL; j++)
count++;
node = list_next(interfaces, node);
}
return (list_count(interfaces) * sizeof(WsManDispatcherInfo))
+ (count * sizeof(DispatchToEpMap));
}
/**
* Register Dispatcher
* @param cntx Context
* @param proc Dispatcher Callback
* @param data Callback data
*/
static void
ws_register_dispatcher(WsContextH cntx, DispatcherCallback proc, void *data)
{
SoapH soap = ws_context_get_runtime(cntx);
if (soap) {
soap->dispatcherProc = proc;
soap->dispatcherData = data;
}
return;
}
static int
set_context_val(WsContextH cntx,
char *name,
void *val,
int size,
int no_dup,
unsigned long type)
{
int retVal = 1;
debug("Setting context value: %s", name);
if (cntx && name) {
void *ptr = val;
if (!no_dup) {
if (val && (ptr = u_malloc(size))) {
memcpy(ptr, val, size);
}
}
if (ptr || val == NULL) {
u_lock(cntx->soap);
ws_remove_context_val(cntx, name);
if (create_context_entry(cntx->entries, name, ptr)) {
retVal = 0;
}
u_unlock(cntx->soap);
}
} else {
error("error setting context value.");
}
return retVal;
}
static void
free_hentry_func(hnode_t * n, void *arg)
{
u_free((void*)hnode_getkey(n));
u_free(n);
}
static void
remove_locked_enuminfo(WsContextH cntx,
WsEnumerateInfo * enumInfo)
{
u_lock(cntx->soap);
if (!(enumInfo->flags & WSMAN_ENUMINFO_INWORK_FLAG)) {
error("locked enuminfo unlocked");
u_unlock(cntx->soap);
return;
}
hash_delete_free(cntx->enuminfos,
hash_lookup(cntx->enuminfos, enumInfo->enumId));
u_unlock(cntx->soap);
}
#ifdef ENABLE_EVENTING_SUPPORT
static void wsman_expiretime2xmldatetime(unsigned long expire, char *str)
{
time_t t = expire;
struct tm tm;
localtime_r(&t, &tm);
snprintf(str, 30, "%u-%u%u-%u%uT%u%u:%u%u:%u%u+%u%u:%u%u",
tm.tm_year + 1900, (tm.tm_mon + 1)/10, (tm.tm_mon + 1)%10,
tm.tm_mday/10, tm.tm_mday%10, tm.tm_hour/10, tm.tm_hour%10,
tm.tm_min/10, tm.tm_min%10, tm.tm_sec/10, tm.tm_sec%10,
0, 0, 0,0);
}
static void delete_notification_info(WsNotificationInfoH notificationInfo) {
if(notificationInfo) {
ws_xml_destroy_doc(notificationInfo->EventContent);
ws_xml_destroy_doc(notificationInfo->headerOpaqueData);
u_free(notificationInfo->EventAction);
u_free(notificationInfo);
}
}
#endif
static WsSubscribeInfo*
search_pull_subs_info(SoapH soap, WsXmlDocH indoc)
{
WsSubscribeInfo *subsInfo = NULL;
char *uuid = NULL;
lnode_t *lnode;
WsContextH soapCntx = ws_get_soap_context(soap);
WsXmlNodeH node = ws_xml_get_soap_body(indoc);
node = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_PULL);
if(node) {
node = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT);
uuid = ws_xml_get_node_text(node);
}
if(uuid == NULL) return subsInfo;
pthread_mutex_lock(&soap->lockSubs);
lnode = list_first(soapCntx->subscriptionMemList);
while(lnode) {
subsInfo = (WsSubscribeInfo *)lnode->list_data;
if(!strcmp(subsInfo->subsId, uuid+5)) break;
lnode = list_next(soapCntx->subscriptionMemList, lnode);
}
pthread_mutex_unlock(&soap->lockSubs);
if(lnode == NULL) return NULL;
return subsInfo;
}
static WsXmlDocH
create_enum_info(SoapOpH op,
WsContextH epcntx,
WsXmlDocH indoc,
WsEnumerateInfo **eInfo)
{
WsXmlNodeH node = ws_xml_get_soap_body(indoc);
WsXmlNodeH header = ws_xml_get_soap_header(indoc);
WsXmlDocH outdoc = NULL;
WsXmlNodeH enumnode = NULL;
WsEnumerateInfo *enumInfo;
WsmanMessage *msg = wsman_get_msg_from_op(op);
WsmanFaultCodeType fault_code = WSMAN_RC_OK;
WsmanFaultDetailType fault_detail_code = WSMAN_DETAIL_OK;
char *uri, *to;
enumInfo = (WsEnumerateInfo *)u_zalloc(sizeof (WsEnumerateInfo));
if (enumInfo == NULL) {
error("No memory");
fault_code = WSMAN_INTERNAL_ERROR;
goto DONE;
}
enumInfo->encoding = u_strdup(msg->charset);
enumInfo->maxsize = wsman_get_maxsize_from_op(op);
if(enumInfo->maxsize == 0) {
enumnode = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_ENUMERATE);
enumInfo->maxsize = ws_deserialize_uint32(NULL, enumnode,
0, XML_NS_ENUMERATION,
WSENUM_MAX_CHARACTERS);
}
enumInfo->releaseproc = wsman_get_release_endpoint(epcntx, indoc);
to = ws_xml_get_node_text(
ws_xml_get_child(header, 0, XML_NS_ADDRESSING, WSA_TO));
uri = ws_xml_get_node_text(
ws_xml_get_child(header, 0, XML_NS_WS_MAN, WSM_RESOURCE_URI));
enumInfo->epr_to = u_strdup(to);
enumInfo->epr_uri = u_strdup(uri);
node = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_ENUMERATE);
node = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_EXPIRES);
if (node == NULL) {
debug("No wsen:Expires");
enumInfo->expires = 0;
} else {
wsman_set_expiretime(node, &(enumInfo->expires), &fault_code);
if (fault_code != WSMAN_RC_OK) {
fault_detail_code = WSMAN_DETAIL_EXPIRATION_TIME;
goto DONE;
}
}
if (msg->auth_data.username != NULL) {
enumInfo->auth_data.username =
u_strdup(msg->auth_data.username);
enumInfo->auth_data.password =
u_strdup(msg->auth_data.password);
} else {
enumInfo->auth_data.username = NULL;
enumInfo->auth_data.password = NULL;
}
generate_uuid(enumInfo->enumId, EUIDLEN, 1);
DONE:
if (fault_code != WSMAN_RC_OK) {
outdoc = wsman_generate_fault(indoc, fault_code, fault_detail_code, NULL);
u_free(enumInfo);
} else {
*eInfo = enumInfo;
}
return outdoc;
}
static void
destroy_enuminfo(WsEnumerateInfo * enumInfo)
{
debug("destroy enuminfo");
u_free(enumInfo->auth_data.username);
u_free(enumInfo->auth_data.password);
u_free(enumInfo->epr_to);
u_free(enumInfo->epr_uri);
u_free(enumInfo->encoding);
if (enumInfo->filter)
filter_destroy(enumInfo->filter);
u_free(enumInfo);
}
static int
wsman_verify_enum_info(SoapOpH op,
WsEnumerateInfo * enumInfo,
WsXmlDocH doc,
WsmanStatus * status)
{
WsmanMessage *msg = wsman_get_msg_from_op(op);
WsXmlNodeH header = ws_xml_get_soap_header(doc);
char *to = ws_xml_get_node_text(ws_xml_get_child(header, 0,
XML_NS_ADDRESSING, WSA_TO));
char *uri= ws_xml_get_node_text(ws_xml_get_child(header, 0,
XML_NS_WS_MAN, WSM_RESOURCE_URI));
if (strcmp(enumInfo->epr_to, to) != 0 ||
strcmp(enumInfo->epr_uri, uri) != 0 ) {
status->fault_code = WSA_MESSAGE_INFORMATION_HEADER_REQUIRED;
status->fault_detail_code = 0;
debug("verifying enumeration context: ACTUAL uri: %s, to: %s", uri, to);
debug("verifying enumeration context: SHOULD uri: %s, to: %s",
enumInfo->epr_uri, enumInfo->epr_to);
return 0;
}
if (msg->auth_data.username && msg->auth_data.password) {
if (strcmp(msg->auth_data.username,
enumInfo->auth_data.username) != 0 &&
strcmp(msg->auth_data.password,
enumInfo->auth_data.password) != 0) {
status->fault_code = WSMAN_ACCESS_DENIED;
status->fault_detail_code = 0;
return 0;
}
}
return 1;
}
static int
insert_enum_info(WsContextH cntx,
WsEnumerateInfo *enumInfo)
{
struct timeval tv;
int retVal = 1;
u_lock(cntx->soap);
gettimeofday(&tv, NULL);
enumInfo->timeStamp = tv.tv_sec;
if (create_context_entry(cntx->enuminfos, enumInfo->enumId, enumInfo)) {
retVal = 0;
}
u_unlock(cntx->soap);
return retVal;
}
static WsEnumerateInfo *
get_locked_enuminfo(WsContextH cntx,
WsXmlDocH doc,
SoapOpH op,
char *action,
WsmanStatus *status)
{
hnode_t *hn;
WsEnumerateInfo *eInfo = NULL;
char *enumId = NULL;
WsXmlNodeH node = ws_xml_get_soap_body(doc);
if (node && (node = ws_xml_get_child(node,
0, XML_NS_ENUMERATION, action))) {
node = ws_xml_get_child(node, 0,
XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT);
if (node) {
enumId = ws_xml_get_node_text(node);
}
}
debug("enum context: %s", enumId);
if (enumId == NULL) {
status->fault_code = WSEN_INVALID_ENUMERATION_CONTEXT;
return NULL;
}
u_lock(cntx->soap);
hn = hash_lookup(cntx->enuminfos, enumId);
if (hn) {
eInfo = (WsEnumerateInfo *)hnode_get(hn);
if (strcmp(eInfo->enumId, enumId)) {
error("enum context mismatch: %s == %s",
eInfo->enumId, enumId);
status->fault_code = WSMAN_INTERNAL_ERROR;
} else if (wsman_verify_enum_info(op, eInfo, doc,status)) {
if (eInfo->flags & WSMAN_ENUMINFO_INWORK_FLAG) {
status->fault_code = WSMAN_CONCURRENCY;
} else {
eInfo->flags |= WSMAN_ENUMINFO_INWORK_FLAG;
}
}
} else {
status->fault_code = WSEN_INVALID_ENUMERATION_CONTEXT;
}
if (status->fault_code != WSMAN_RC_OK) {
eInfo = NULL;
}
u_unlock(cntx->soap);
return eInfo;
}
static void
unlock_enuminfo(WsContextH cntx, WsEnumerateInfo *enumInfo)
{
struct timeval tv;
gettimeofday(&tv, NULL);
u_lock(cntx->soap);
if (!(enumInfo->flags & WSMAN_ENUMINFO_INWORK_FLAG)) {
error("locked enuminfo unlocked");
u_unlock(cntx->soap);
return;
}
enumInfo->flags &= ~WSMAN_ENUMINFO_INWORK_FLAG;
enumInfo->timeStamp = tv.tv_sec;
u_unlock(cntx->soap);
}
static void
ws_clear_context_entries(WsContextH hCntx)
{
hash_t *h;
if (!hCntx) {
return;
}
h = hCntx->entries;
hash_free(h);
}
static void
ws_clear_context_enuminfos(WsContextH hCntx)
{
hash_t *h;
if (!hCntx) {
return;
}
h = hCntx->enuminfos;
hash_free(h);
}
callback_t *
make_callback_entry(SoapServiceCallback proc,
void *data,
list_t * list_to_add)
{
callback_t *entry = (callback_t *) u_malloc(sizeof(callback_t));
debug("make new callback entry");
if (entry) {
lnode_init(&entry->node, data);
entry->proc = proc;
if (list_to_add == NULL) {
list_to_add = list_create(LISTCOUNT_T_MAX);
}
list_append(list_to_add, &entry->node);
} else {
return NULL;
}
return entry;
}
void
ws_initialize_context(WsContextH cntx, SoapH soap)
{
cntx->entries = hash_create(HASHCOUNT_T_MAX, NULL, NULL);
hash_set_allocator(cntx->entries, NULL, free_hentry_func, NULL);
cntx->enuminfos = hash_create(HASHCOUNT_T_MAX, NULL, NULL);
cntx->subscriptionMemList = list_create(LISTCOUNT_T_MAX);
hash_set_allocator(cntx->enuminfos, NULL, free_hentry_func, NULL);
cntx->owner = 1;
cntx->soap = soap;
cntx->serializercntx = ws_serializer_init();
}
WsContextH
ws_create_context(SoapH soap)
{
WsContextH cntx = (WsContextH) u_zalloc(sizeof (*cntx));
if (cntx) {
ws_initialize_context(cntx, soap);
}
return cntx;
}
SoapH
ws_soap_initialize()
{
SoapH soap = (SoapH) u_zalloc(sizeof(*soap));
if (soap == NULL) {
error("Could not alloc memory");
return NULL;
}
soap->cntx = ws_create_context(soap);
soap->inboundFilterList = NULL;
soap->outboundFilterList = NULL;
soap->dispatchList = NULL;
soap->processedMsgIdList = NULL;
u_init_lock(soap);
u_init_lock(&soap->lockSubs);
ws_xml_parser_initialize();
soap_add_filter(soap, outbound_addressing_filter, NULL, 0);
soap_add_filter(soap, outbound_control_header_filter, NULL, 0);
return soap;
}
void
ws_set_context_enumIdleTimeout(WsContextH cntx,
unsigned long timeout)
{
cntx->enumIdleTimeout = timeout;
}
WsContextH
ws_create_runtime(list_t * interfaces)
{
SoapH soap = ws_soap_initialize();
WsManDispatcherInfo *dispInfo;
int size;
lnode_t *node;
if (soap == NULL) {
error("Could not initialize soap");
return NULL;
}
if (interfaces == NULL) {
return soap->cntx;
}
size = calculate_map_count(interfaces);
dispInfo = (WsManDispatcherInfo *) u_zalloc(size);
if (dispInfo == NULL) {
error("Could not allocate memory");
u_free(soap);
return NULL;
}
debug("Registering %d plugins", (int) list_count(interfaces));
dispInfo->interfaceCount = list_count(interfaces);
dispInfo->interfaces = interfaces;
node = list_first(interfaces);
while (node != NULL) {
WsDispatchInterfaceInfo *wdii = (WsDispatchInterfaceInfo *) node->list_data;
if (wsman_register_interface(soap->cntx, wdii, dispInfo) != 0) {
error("Interface registration failed for %s", wdii->displayName);
u_free(dispInfo);
soap_destroy(soap);
return NULL;
}
node = list_next(interfaces, node);
}
ws_register_dispatcher(soap->cntx, wsman_dispatcher, dispInfo);
return soap->cntx;
}
/**
* Register Dispatcher Interfaces
* @param cntx WS-Man Context
* @param wsInterface Interface
* @param dispinfo Dispatcher
*/
int
wsman_register_interface(WsContextH cntx,
WsDispatchInterfaceInfo * wsInterface,
WsManDispatcherInfo * dispInfo)
{
int i, retVal = 0;
WsDispatchEndPointInfo *ep = wsInterface->endPoints;
for (i = 0; ep[i].serviceEndPoint != NULL; i++) {
if ((retVal = wsman_register_endpoint(cntx, wsInterface,
&ep[i], dispInfo)) != 0) {
break;
}
}
return retVal;
}
/*
* Register Endpoint
* @param cntx Context
* @param wsInterface Interface
* @param ep Endpoint
* @param dispInfo Dispatcher information
*/
int
wsman_register_endpoint(WsContextH cntx,
WsDispatchInterfaceInfo *wsInterface,
WsDispatchEndPointInfo *ep,
WsManDispatcherInfo *dispInfo)
{
SoapDispatchH disp = NULL;
unsigned long flags = SOAP_CUSTOM_DISPATCHER;
SoapServiceCallback callbackProc = NULL;
SoapH soap = ws_context_get_runtime(cntx);
char *action = NULL;
debug("Registering Endpoint: %s", ep->inAction ? ep->inAction : "<null>");
switch (ep->flags & WS_DISP_TYPE_MASK) {
case WS_DISP_TYPE_IDENTIFY:
debug("Registering endpoint for Identify");
action = ep->inAction;
callbackProc = wsman_identify_stub;
break;
case WS_DISP_TYPE_ENUMERATE:
debug("Registering endpoint for Enumerate");
action = ep->inAction;
callbackProc = wsenum_enumerate_stub;
break;
case WS_DISP_TYPE_RELEASE:
debug("Registering endpoint for Release");
action = ep->inAction;
callbackProc = wsenum_release_stub;
break;
case WS_DISP_TYPE_DELETE:
debug("Registering endpoint for Delete");
action = ep->inAction;
callbackProc = ws_transfer_delete_stub;
break;
case WS_DISP_TYPE_PULL:
debug("Registering endpoint for Pull");
action = ep->inAction;
callbackProc = wsenum_pull_stub;
break;
case WS_DISP_TYPE_DIRECT_PULL:
debug("Registering endpoint for direct Pull");
action = ep->inAction;
callbackProc = wsenum_pull_direct_stub;
break;
case WS_DISP_TYPE_GET:
debug("Registering endpoint for Get");
action = ep->inAction;
callbackProc = ws_transfer_get_stub;
break;
case WS_DISP_TYPE_DIRECT_GET:
debug("Registering endpoint for direct Get");
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
case WS_DISP_TYPE_DIRECT_DELETE:
debug("Registering endpoint for Delete");
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
case WS_DISP_TYPE_DIRECT_PUT:
debug("Registering endpoint for direct Put");
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
case WS_DISP_TYPE_DIRECT_CREATE:
debug("Registering endpoint for direct Create");
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
case WS_DISP_TYPE_PUT:
debug("Registering endpoint for Put");
action = ep->inAction;
callbackProc = ws_transfer_put_stub;
break;
#ifdef ENABLE_EVENTING_SUPPORT
case WS_DISP_TYPE_SUBSCRIBE:
debug("Registering endpoint for Subscribe");
action = ep->inAction;
callbackProc = wse_subscribe_stub;
break;
case WS_DISP_TYPE_UNSUBSCRIBE:
debug("Registering endpoint for Unsubscribe");
action = ep->inAction;
callbackProc = wse_unsubscribe_stub;
break;
case WS_DISP_TYPE_RENEW:
action = ep->inAction;
callbackProc = wse_renew_stub;
break;
#endif
case WS_DISP_TYPE_RAW_DOC:
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
case WS_DISP_TYPE_CUSTOM_METHOD:
debug("Registering endpoint for custom method");
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
case WS_DISP_TYPE_PRIVATE:
debug("Registering endpoint for private EndPoint");
action = ep->inAction;
callbackProc = (SoapServiceCallback) ep->serviceEndPoint;
break;
default:
debug("unknown dispatch type %lu",
ep->flags & WS_DISP_TYPE_MASK);
break;
}
if (callbackProc != NULL &&
(disp = wsman_dispatch_create(soap, action, NULL, NULL, callbackProc, ep, flags))) {
dispInfo->map[dispInfo->mapCount].ep = ep;
dispInfo->map[dispInfo->mapCount].disp = disp;
dispInfo->mapCount++;
wsman_dispatch_start(disp);
}
if (action && action != ep->inAction) {
u_free(action);
}
return (disp == NULL);
}
/* ENDPOINTS STUBS */
int
wsman_identify_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
void *data;
WsXmlDocH doc = NULL;
WsContextH cntx;
WsDispatchEndPointInfo *info;
XmlSerializerInfo *typeInfo;
WsmanStatus *status;
SoapH soap;
WsEndPointGet endPoint;
status = u_zalloc(sizeof(WsmanStatus *));
soap = soap_get_op_soap(op);
cntx = ws_create_ep_context(soap, soap_get_op_doc(op, 1));
info = (WsDispatchEndPointInfo *) appData;
typeInfo = info->serializationInfo;
endPoint = (WsEndPointGet) info->serviceEndPoint;
debug("Identify called");
if ((data = endPoint(cntx, status, opaqueData)) == NULL) {
error("Identify Fault");
doc = wsman_generate_fault(soap_get_op_doc(op, 1), WSMAN_INTERNAL_ERROR, 0, NULL);
} else {
doc = wsman_create_response_envelope(soap_get_op_doc(op, 1), NULL);
ws_serialize(cntx->serializercntx, ws_xml_get_soap_body(doc), data, typeInfo,
WSMID_IDENTIFY_RESPONSE, (char *) info->data, NULL, 1);
ws_serializer_free_mem(cntx->serializercntx, data, typeInfo);
u_free(data);
}
if (doc) {
soap_set_op_doc(op, doc, 0);
} else {
error("Response doc invalid");
}
ws_destroy_context(cntx);
u_free(status);
return 0;
}
int
ws_transfer_put_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
int retVal = 0;
WsXmlDocH doc = NULL;
void *outData = NULL;
WsmanStatus status;
SoapH soap = soap_get_op_soap(op);
WsContextH cntx = ws_create_ep_context(soap, soap_get_op_doc(op, 1));
WsDispatchEndPointInfo *info = (WsDispatchEndPointInfo *) appData;
XmlSerializerInfo *typeInfo = info->serializationInfo;
WsEndPointPut endPoint = (WsEndPointPut) info->serviceEndPoint;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsXmlNodeH _body = ws_xml_get_soap_body(_doc);
WsXmlNodeH _r = ws_xml_get_child(_body, 0, NULL, NULL);
void *data = ws_deserialize(cntx->serializercntx, _body, typeInfo,
ws_xml_get_node_local_name(_r),
(char *) info->data, NULL, 0, 0);
if ((retVal = endPoint(cntx, data, &outData, &status, opaqueData))) {
doc = wsman_generate_fault( _doc, status.fault_code,
status.fault_detail_code, NULL);
} else {
doc = wsman_create_response_envelope(_doc, NULL);
if (outData) {
ws_serialize(cntx->serializercntx, ws_xml_get_soap_body(doc), outData,
typeInfo, TRANSFER_PUT_RESP,
(char *) info->data, NULL, 1);
ws_serializer_free_mem(cntx->serializercntx, outData, typeInfo);
}
}
if (doc) {
soap_set_op_doc(op, doc, 0);
}
ws_serializer_free_all(cntx->serializercntx);
ws_serializer_cleanup(cntx->serializercntx);
return retVal;
}
int
ws_transfer_delete_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
WsmanStatus status;
SoapH soap = soap_get_op_soap(op);
WsContextH cntx = ws_create_ep_context(soap,
soap_get_op_doc(op, 1));
WsDispatchEndPointInfo *info = (WsDispatchEndPointInfo *) appData;
WsEndPointGet endPoint = (WsEndPointGet) info->serviceEndPoint;
void *data;
WsXmlDocH doc = NULL;
wsman_status_init(&status);
if ((data = endPoint(cntx, &status, opaqueData)) == NULL) {
warning("Transfer Delete fault");
doc = wsman_generate_fault(soap_get_op_doc(op, 1),
WSMAN_INVALID_SELECTORS, 0, NULL);
} else {
debug("Creating Response doc");
doc = wsman_create_response_envelope(soap_get_op_doc(op, 1), NULL);
}
if (doc) {
soap_set_op_doc(op, doc, 0);
} else {
error("Response doc invalid");
}
ws_destroy_context(cntx);
return 0;
}
int
ws_transfer_get_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
WsmanStatus status;
SoapH soap = soap_get_op_soap(op);
WsContextH cntx = ws_create_ep_context(soap, soap_get_op_doc(op, 1));
WsDispatchEndPointInfo *info = (WsDispatchEndPointInfo *) appData;
XmlSerializerInfo *typeInfo = info->serializationInfo;
WsEndPointGet endPoint = (WsEndPointGet) info->serviceEndPoint;
void *data;
WsXmlDocH doc = NULL;
wsman_status_init(&status);
if ((data = endPoint(cntx, &status, opaqueData)) == NULL) {
warning("Transfer Get fault");
doc = wsman_generate_fault( soap_get_op_doc(op, 1),
WSMAN_INVALID_SELECTORS, 0, NULL);
} else {
debug("Creating Response doc");
doc = wsman_create_response_envelope(soap_get_op_doc(op, 1), NULL);
ws_serialize(cntx->serializercntx, ws_xml_get_soap_body(doc), data, typeInfo,
TRANSFER_GET_RESP, (char *) info->data, NULL, 1);
ws_serializer_free_mem(cntx->serializercntx, data, typeInfo);
}
if (doc) {
debug("Setting operation document");
soap_set_op_doc(op, doc, 0);
} else {
warning("Response doc invalid");
}
ws_destroy_context(cntx);
return 0;
}
WsmanMessage *wsman_get_msg_from_op(SoapOpH op)
{
op_t *_op = (op_t *)op;
WsmanMessage *msg = (WsmanMessage *)_op->data;
return msg;
}
unsigned long wsman_get_maxsize_from_op(SoapOpH op)
{
op_t *_op = (op_t *)op;
return _op->maxsize;
}
static
unsigned long get_total_enum_context(WsContextH cntx){
hscan_t hs;
u_lock(cntx->soap);
hash_scan_begin(&hs, cntx->enuminfos);
unsigned long total = hash_count(hs.hash_table);
u_unlock(cntx->soap);
return total;
}
/**
* The following extern methods are defined in wsmand-daemon.c,
* which is compiled into openwsmand binary, which in turn links
* to libwsman.la. So when a call is made to the following methods
* from the openwsmand binary, they should be present.
*
* However, if they are dlopened from somewhere other than
* openwsmand library or linked to some other
* binary or shared object, then these methods may or may not be
* preset, hence marking them as weak symbols and testing to see
* if they are resolved before using them.
*/
#pragma weak wsmand_options_get_max_threads
extern int wsmand_options_get_max_threads(void);
#pragma weak wsmand_options_get_max_connections_per_thread
extern int wsmand_options_get_max_connections_per_thread(void);
/**
* Enumeration Stub for processing enumeration requests
* @param op SOAP pperation handler
* @param appData Application data
* @return status
*/
int
wsenum_enumerate_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
WsXmlDocH doc = NULL;
int retVal = 0;
WsEnumerateInfo *enumInfo = NULL;
WsmanStatus status;
WsXmlNodeH resp_node, body;
WsContextH soapCntx;
SoapH soap = soap_get_op_soap(op);
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
WsEndPointEnumerate endPoint =
(WsEndPointEnumerate)ep->serviceEndPoint;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsContextH epcntx;
int max_threads = 0;
int max_connections_per_thread = 0;
int(* fptr)(void);
if((fptr = wsmand_options_get_max_threads) != 0){
max_threads = (* fptr)();
if((fptr = wsmand_options_get_max_connections_per_thread) != 0){
max_connections_per_thread = (* fptr)();
}
else{
debug("Could not resolve wsmand_options_get_max_connections_per_thread");
max_threads=0;
}
}
else{
debug("Could not resolve wsman_options_get_max_threads");
}
if(max_threads){
if(get_total_enum_context(ws_get_soap_context(soap)) >= (max_threads * max_connections_per_thread)){
debug("enum context queue is full, we wait till some expire or are cleared");
doc = wsman_generate_fault(_doc, WSMAN_QUOTA_LIMIT, OWSMAN_NO_DETAILS,
"The service is busy servicing other requests. Try later.");
if(doc){
soap_set_op_doc(op, doc, 0);
}
return 1;
}
}
epcntx = ws_create_ep_context(soap, _doc);
wsman_status_init(&status);
doc = create_enum_info(op, epcntx, _doc, &enumInfo);
if (doc != NULL) {
/* wrong enum elements met. Fault message generated */
goto DONE;
}
if (endPoint && (retVal = endPoint(epcntx, enumInfo, &status, opaqueData))) {
debug("enumeration fault");
doc = wsman_generate_fault( _doc, status.fault_code,
status.fault_detail_code, status.fault_msg);
destroy_enuminfo(enumInfo);
goto DONE;
}
if (enumInfo->pullResultPtr) {
doc = enumInfo->pullResultPtr;
enumInfo->index++;
} else {
doc = wsman_create_response_envelope( _doc, NULL);
}
if (!doc)
goto DONE;
wsman_set_estimated_total(_doc, doc, enumInfo);
body = ws_xml_get_soap_body(doc);
if (enumInfo->pullResultPtr == NULL) {
resp_node = ws_xml_add_child(body, XML_NS_ENUMERATION,
WSENUM_ENUMERATE_RESP, NULL);
} else {
resp_node = ws_xml_get_child(body, 0,
XML_NS_ENUMERATION, WSENUM_ENUMERATE_RESP);
}
soapCntx = ws_get_soap_context(soap);
if (( enumInfo->flags & WSMAN_ENUMINFO_OPT ) == WSMAN_ENUMINFO_OPT &&
(enumInfo->totalItems == 0 || enumInfo->index == enumInfo->totalItems)) {
ws_serialize_str(epcntx->serializercntx, resp_node, NULL,
XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT, 0);
ws_serialize_str(epcntx->serializercntx, resp_node,
NULL, XML_NS_WS_MAN, WSENUM_END_OF_SEQUENCE, 0);
destroy_enuminfo(enumInfo);
} else {
ws_serialize_str(epcntx->serializercntx, resp_node, enumInfo->enumId,
XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT, 0);
insert_enum_info(soapCntx, enumInfo);
}
DONE:
if (doc) {
soap_set_op_doc(op, doc, 0);
}
ws_destroy_context(epcntx);
u_free(status.fault_msg);
return retVal;
}
int
wsenum_release_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
int retVal = 0;
WsXmlDocH doc = NULL;
WsmanStatus status;
SoapH soap = soap_get_op_soap(op);
WsContextH soapCntx = ws_get_soap_context(soap);
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
WsEndPointRelease endPoint = (WsEndPointRelease) ep->serviceEndPoint;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsEnumerateInfo *enumInfo;
wsman_status_init(&status);
enumInfo = get_locked_enuminfo(soapCntx, _doc,
op, WSENUM_RELEASE, &status);
ws_set_context_xml_doc_val(soapCntx, WSFW_INDOC, _doc);
if (enumInfo == NULL) {
doc = wsman_generate_fault( _doc,
status.fault_code, status.fault_detail_code, NULL);
} else {
if (endPoint && (retVal = endPoint(soapCntx,
enumInfo, &status, opaqueData))) {
error("endPoint error");
doc = wsman_generate_fault( _doc,
WSMAN_INTERNAL_ERROR,
OWSMAN_DETAIL_ENDPOINT_ERROR, NULL);
unlock_enuminfo(soapCntx, enumInfo);
} else {
doc = wsman_create_response_envelope( _doc, NULL);
debug("Releasing context: %s", enumInfo->enumId);
remove_locked_enuminfo(soapCntx, enumInfo);
destroy_enuminfo(enumInfo);
}
}
if (doc) {
soap_set_op_doc(op, doc, 0);
}
return retVal;
}
int
wsenum_pull_stub(SoapOpH op, void *appData,
void *opaqueData)
{
WsXmlNodeH node;
WsmanStatus status;
SoapH soap = soap_get_op_soap(op);
WsContextH soapCntx = ws_get_soap_context(soap);
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
XmlSerializerInfo *typeInfo = ep->serializationInfo;
WsEndPointPull endPoint = (WsEndPointPull) ep->serviceEndPoint;
int retVal = 0, locked = 0;
WsXmlDocH doc = NULL;
char *enumId = NULL;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsEnumerateInfo *enumInfo;
wsman_status_init(&status);
enumInfo = get_locked_enuminfo(soapCntx, _doc,
op, WSENUM_PULL, &status);
if (enumInfo == NULL) {
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, NULL);
goto DONE;
}
locked = 1;
if ((retVal = endPoint(ws_create_ep_context(soap, _doc),
enumInfo, &status, opaqueData))) {
doc = wsman_generate_fault(_doc, status.fault_code, status.fault_detail_code, NULL);
goto DONE;
}
enumInfo->index++;
doc = wsman_create_response_envelope( _doc, NULL);
if (!doc) {
goto DONE;
}
wsman_set_estimated_total(_doc, doc, enumInfo);
node = ws_xml_add_child(ws_xml_get_soap_body(doc),
XML_NS_ENUMERATION, WSENUM_PULL_RESP, NULL);
if (node == NULL) {
goto DONE;
}
if (enumInfo->pullResultPtr) {
if (enumId) {
ws_serialize_str(soapCntx->serializercntx, node, enumId,
XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT, 0);
}
WsXmlNodeH itemsNode = ws_xml_add_child(node,
XML_NS_ENUMERATION, WSENUM_ITEMS, NULL);
ws_serialize(soapCntx->serializercntx, itemsNode, enumInfo->pullResultPtr,
typeInfo, ep->respName, (char *) ep->data, NULL, 1);
ws_serializer_free_mem(soapCntx->serializercntx,
enumInfo->pullResultPtr, typeInfo);
} else {
/*
ws_serialize_str(soapCntx, node, NULL,
XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT, 0);
*/
ws_serialize_str(soapCntx->serializercntx,
node, NULL, XML_NS_ENUMERATION, WSENUM_END_OF_SEQUENCE, 0);
remove_locked_enuminfo(soapCntx, enumInfo);
locked = 0;
destroy_enuminfo(enumInfo);
}
DONE:
if (locked) {
unlock_enuminfo(soapCntx, enumInfo);
}
if (doc) {
soap_set_op_doc(op, doc, 0);
}
return retVal;
}
int
wsenum_pull_direct_stub(SoapOpH op,
void *appData,
void *opaqueData)
{
WsmanStatus status;
WsXmlDocH doc = NULL;
SoapH soap = soap_get_op_soap(op);
WsContextH soapCntx = ws_get_soap_context(soap);
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
#ifdef ENABLE_EVENTING_SUPPORT
WsNotificationInfoH notificationInfo = NULL;
#endif
WsEndPointPull endPoint = (WsEndPointPull) ep->serviceEndPoint;
int retVal = 0;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
int locked = 0;
WsEnumerateInfo *enumInfo;
WsSubscribeInfo *subsInfo = NULL;
wsman_status_init(&status);
enumInfo = get_locked_enuminfo(soapCntx,
_doc, op, WSENUM_PULL, &status);
if (enumInfo == NULL) {
subsInfo = search_pull_subs_info(soap, _doc);
if(subsInfo == NULL) {
error("Invalid enumeration context...");
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, NULL);
goto cleanup;
}
}
if (enumInfo) { //pull things from "enumerate" results
locked = 1;
if ((retVal = endPoint(ws_create_ep_context(soap, _doc),
enumInfo, &status, opaqueData))) {
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, NULL);
// ws_remove_context_val(soapCntx, cntxName);
goto cleanup;
}
enumInfo->index++;
if (enumInfo->pullResultPtr) {
WsXmlNodeH body;
WsXmlNodeH response, items;
doc = enumInfo->pullResultPtr;
wsman_set_estimated_total(_doc, doc, enumInfo);
body = ws_xml_get_soap_body(doc);
response = ws_xml_get_child(body, 0,
XML_NS_ENUMERATION, WSENUM_PULL_RESP);
items = ws_xml_get_child(response, 0,
XML_NS_ENUMERATION, WSENUM_ITEMS);
if (enumInfo->totalItems == 0 || enumInfo->index == enumInfo->totalItems) {
/*
ws_serialize_str(soapCntx, response, NULL,
XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT, 0);
*/
ws_serialize_str(soapCntx->serializercntx, response, NULL,
XML_NS_ENUMERATION, WSENUM_END_OF_SEQUENCE, 0);
remove_locked_enuminfo(soapCntx, enumInfo);
locked = 0;
destroy_enuminfo(enumInfo);
} else {
/* add Context before Items to comply to WS-Enumeration xsd */
ws_xml_add_prev_sibling(items, XML_NS_ENUMERATION,
WSENUM_ENUMERATION_CONTEXT, enumInfo->enumId);
}
}
}
#ifdef ENABLE_EVENTING_SUPPORT
else { //pull things from notifications
ws_xml_destroy_doc(doc);
pthread_mutex_lock(&subsInfo->notificationlock);
int count = soap->eventpoolOpSet->count(subsInfo->subsId);
int max_elements = 1;
if(count > 0) {
doc = ws_xml_create_envelope();
WsXmlNodeH docnode = ws_xml_get_soap_body(doc);
WsXmlNodeH docheader = ws_xml_get_soap_header(doc);
docnode = ws_xml_add_child(docnode, XML_NS_ENUMERATION, WSENUM_PULL_RESP, NULL);
if(docnode) {
ws_xml_add_child_format(docnode, XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT,
"uuid:%s", subsInfo->subsId);
}
WsXmlDocH notidoc = NULL;
WsXmlNodeH header = ws_xml_get_soap_header(_doc);
if (ws_xml_get_child(header, 0,XML_NS_WS_MAN, WSM_REQUEST_TOTAL) != NULL) {
WsXmlNodeH response_header =ws_xml_get_soap_header(doc);
response_header = ws_xml_add_child(response_header, XML_NS_WS_MAN,
WSM_TOTAL_ESTIMATE, NULL);
if(response_header)
ws_xml_add_node_attr(response_header, XML_NS_SCHEMA_INSTANCE, XML_SCHEMA_NIL, "true");
}
header = ws_xml_get_child(header, 0, XML_NS_ENUMERATION, WSENUM_MAX_ELEMENTS);
if(header)
max_elements = atoi(ws_xml_get_node_text(header));
if(max_elements > 1 && count > 1) {
docnode = ws_xml_add_child(docnode, XML_NS_ENUMERATION, WSENUM_ITEMS, NULL);
}
while(max_elements > 0) {
if(soap->eventpoolOpSet->remove(subsInfo->subsId, &notificationInfo))
break;
ws_xml_add_child(docheader, XML_NS_ADDRESSING, WSA_ACTION, notificationInfo->EventAction);
notidoc = notificationInfo->EventContent;
WsXmlNodeH tempnode = ws_xml_get_doc_root(notidoc);
ws_xml_duplicate_tree(docnode, tempnode);
delete_notification_info(notificationInfo);
max_elements--;
}
}
else {
status.fault_code = WSMAN_TIMED_OUT;
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, NULL);
}
pthread_mutex_unlock(&subsInfo->notificationlock);
}
#endif
cleanup:
if (locked) {
unlock_enuminfo(soapCntx, enumInfo);
}
if (doc) {
soap_set_op_doc(op, doc, 0);
} else {
error("doc is null");
}
return retVal;
}
static list_t *
wsman_get_expired_enuminfos(WsContextH cntx)
{
list_t *list = NULL;
hnode_t *hn;
hscan_t hs;
WsEnumerateInfo *enumInfo;
struct timeval tv;
unsigned long mytime;
unsigned long aeit = cntx->enumIdleTimeout;
if (aeit == 0) {
return NULL;
}
gettimeofday(&tv, NULL);
mytime = tv.tv_sec;
u_lock(cntx->soap);
if (hash_isempty(cntx->enuminfos)) {
u_unlock(cntx->soap);
return NULL;
}
hash_scan_begin(&hs, cntx->enuminfos);
while ((hn = hash_scan_next(&hs))) {
enumInfo = (WsEnumerateInfo *)hnode_get(hn);
if (enumInfo->flags & WSMAN_ENUMINFO_INWORK_FLAG) {
debug("Enum in work: %s", enumInfo->enumId);
continue;
}
if ((enumInfo->timeStamp + aeit > mytime) &&
((enumInfo->expires == 0) ||
(enumInfo->expires > mytime))) {
continue;
}
if (list == NULL) {
list = list_create(LISTCOUNT_T_MAX);
}
if (list == NULL) {
u_unlock(cntx->soap);
error("could not create list");
return NULL;
}
hash_scan_delfree(cntx->enuminfos, hn);
list_append(list, lnode_create(enumInfo));
debug("Enum expired list appended: %s", enumInfo->enumId);
}
u_unlock(cntx->soap);
return list;
}
void
wsman_timeouts_manager(WsContextH cntx, void *opaqueData)
{
list_t *list = wsman_get_expired_enuminfos(cntx);
lnode_t *node;
WsEnumerateInfo *enumInfo;
WsmanStatus status;
if (list == NULL) {
return;
}
while ((node = list_del_first(list))) {
enumInfo = (WsEnumerateInfo *)lnode_get(node);
debug("EnumContext expired : %s", enumInfo->enumId);
lnode_destroy(node);
if (enumInfo->releaseproc) {
if (enumInfo->releaseproc(cntx, enumInfo, &status, opaqueData)) {
debug("released with failure: %s",
enumInfo->enumId);
} else {
debug("released: %s", enumInfo->enumId);
}
} else {
debug("no release endpoint: %s", enumInfo->enumId);
}
destroy_enuminfo(enumInfo);
if (list_isempty(list)) {
list_destroy(list);
break;
}
}
return;
}
#ifdef ENABLE_EVENTING_SUPPORT
static int destination_reachable(char *url)
{
int valid = 0;
u_uri_t *uri = NULL;
if(strstr(url, "http") == NULL)
return valid;
if (u_uri_parse((const char *)url, &uri) == 0) {
valid = 1;
}
u_uri_free(uri);
return valid;
}
WsEventThreadContextH
ws_create_event_context(SoapH soap, WsSubscribeInfo *subsInfo, WsXmlDocH doc)
{
WsEventThreadContextH eventcntx = u_malloc(sizeof(*eventcntx));
eventcntx->soap = soap;
eventcntx->subsInfo = subsInfo;
eventcntx->outdoc = doc;
return eventcntx;
}
static void
destroy_subsinfo(WsSubscribeInfo * subsInfo)
{
if(subsInfo == NULL) return;
u_free(subsInfo->uri);
u_free(subsInfo->auth_data.username);
u_free(subsInfo->auth_data.password);
u_free(subsInfo->epr_notifyto);
u_free(subsInfo->locale);
u_free(subsInfo->soapNs);
u_free(subsInfo->contentEncoding);
u_free(subsInfo->cim_namespace);
u_free(subsInfo->username);
u_free(subsInfo->password);
u_free(subsInfo->certificate_thumbprint);
if (subsInfo->filter) {
filter_destroy(subsInfo->filter);
}
ws_xml_destroy_doc(subsInfo->bookmarkDoc);
ws_xml_destroy_doc(subsInfo->templateDoc);
ws_xml_destroy_doc(subsInfo->heartbeatDoc);
u_free(subsInfo);
}
static void
create_notification_template(WsXmlDocH indoc, WsSubscribeInfo *subsInfo)
{
WsXmlDocH notificationDoc = ws_xml_create_envelope();
WsXmlNodeH temp = NULL;
WsXmlNodeH node = NULL;
WsXmlNodeH header = NULL;
header = ws_xml_get_soap_header(notificationDoc);
ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_TO, subsInfo->epr_notifyto);
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_EVENTS ||
subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PUSHWITHACK) {
ws_xml_add_child(header, XML_NS_WS_MAN, WSM_ACKREQUESTED, NULL);
}
node = ws_xml_get_soap_body(indoc);
node = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE);
node = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_DELIVERY);
node = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_NOTIFY_TO);
temp = ws_xml_get_child(node, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PROPERTIES);
if(temp == NULL)
node = ws_xml_get_child(node, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS);
if(node ) {
ws_xml_duplicate_children(header, node);
}
subsInfo->templateDoc = ws_xml_duplicate_doc(notificationDoc);
subsInfo->heartbeatDoc = ws_xml_duplicate_doc( notificationDoc);
temp = ws_xml_get_soap_header(subsInfo->heartbeatDoc);
temp = ws_xml_add_child(temp, XML_NS_ADDRESSING, WSA_ACTION, WSMAN_ACTION_HEARTBEAT);
ws_xml_add_node_attr(temp, XML_NS_XML_SCHEMA, SOAP_MUST_UNDERSTAND, "true");
ws_xml_destroy_doc(notificationDoc);
}
static WsXmlDocH
create_subs_info(SoapOpH op,
WsContextH epcntx,
WsXmlDocH indoc,
WsSubscribeInfo**sInfo)
{
WsXmlNodeH node = ws_xml_get_soap_body(indoc);
WsXmlNodeH subNode = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE);
WsXmlNodeH temp;
WsXmlDocH outdoc = NULL;
WsSubscribeInfo *subsInfo;
WsXmlAttrH attr = NULL;
op_t *_op = (op_t *) op;
WsmanMessage *msg = (WsmanMessage *) _op->data;
WsmanFaultCodeType fault_code = WSMAN_RC_OK;
WsmanFaultDetailType fault_detail_code = WSMAN_DETAIL_OK;
char *str = NULL;
time_t timeout;
int r;
char *soapNs = NULL, *ntext = NULL;
*sInfo = NULL;
subsInfo = (WsSubscribeInfo *)u_zalloc(sizeof (WsSubscribeInfo));
if (subsInfo == NULL) {
error("No memory");
fault_code = WSMAN_INTERNAL_ERROR;
goto DONE;
}
if((r = pthread_mutex_init(&subsInfo->notificationlock, NULL)) != 0) {
fault_code = WSMAN_INTERNAL_ERROR;
goto DONE;
}
subsInfo->uri = u_strdup(wsman_get_resource_uri(epcntx, indoc));
if(!subNode) {
message("No subsribe body");
fault_code = WSE_INVALID_MESSAGE;
goto DONE;
}
soapNs = ws_xml_get_node_name_ns(ws_xml_get_doc_root(indoc));
subsInfo->soapNs = u_strdup(soapNs);
node = ws_xml_get_child(subNode, 0, XML_NS_WS_MAN, WSM_SENDBOOKMARKS);
if(node) {
subsInfo->bookmarksFlag = 1;
}
node = ws_xml_get_child(subNode, 0, XML_NS_WS_MAN, WSM_BOOKMARK);
if(node) {
if(ws_xml_get_node_text(node) &&
!strcmp(ws_xml_get_node_text(node), WSM_DEFAULTBOOKMARK)){
subsInfo->flags |= WSMAN_SUBSCRIBEINFO_BOOKMARK_DEFAULT;
}
else {
subsInfo->bookmarkDoc = ws_xml_create_doc(XML_NS_WS_MAN, WSM_BOOKMARK);
temp = ws_xml_get_doc_root(subsInfo->bookmarkDoc);
ws_xml_duplicate_children(temp, node);
}
}
node = ws_xml_get_child(subNode, 0, XML_NS_EVENTING, WSEVENT_EXPIRES);
if (node == NULL) {
debug("No wsen:Expires");
subsInfo->expires = 0;
}
else {
wsman_set_expiretime(node, &subsInfo->expires, &fault_code);
if (fault_code != WSMAN_RC_OK) {
debug("Invalid expiration time!");
goto DONE;
}
if(time_expired(subsInfo->expires)) {
fault_code = WSE_INVALID_EXPIRATION_TIME;
debug("Invalid expiration time!");
goto DONE;
}
}
node = ws_xml_get_child(subNode, 0, XML_NS_EVENTING, WSEVENT_DELIVERY);
attr = ws_xml_find_node_attr(node, NULL,WSEVENT_DELIVERY_MODE);
if(attr) {
str = ws_xml_get_attr_value(attr);
if (!strcasecmp(str, WSEVENT_DELIVERY_MODE_PUSH)) {
subsInfo->deliveryMode = WS_EVENT_DELIVERY_MODE_PUSH;
}
else if (!strcasecmp(str, WSEVENT_DELIVERY_MODE_PUSHWITHACK)) {
subsInfo->deliveryMode = WS_EVENT_DELIVERY_MODE_PUSHWITHACK;
}
else if (!strcasecmp(str, WSEVENT_DELIVERY_MODE_EVENTS)) {
subsInfo->deliveryMode = WS_EVENT_DELIVERY_MODE_EVENTS;
}
else {
subsInfo->deliveryMode = WS_EVENT_DELIVERY_MODE_PULL;
}
}
else {
//"push" is the default delivery mode
subsInfo->deliveryMode = WS_EVENT_DELIVERY_MODE_PUSH;
}
temp = ws_xml_get_child(node, 0, XML_NS_WS_MAN, WSM_CONTENTCODING);
if(temp){
str = ws_xml_get_node_text(temp);
subsInfo->contentEncoding = u_strdup(str);
}
temp = ws_xml_get_child(node, 0, XML_NS_WS_MAN, WSM_LOCALE);
if(temp) {
attr = ws_xml_find_node_attr(temp, XML_NS_WS_MAN, WSM_LOCALE);
if(attr)
subsInfo->locale = u_strdup(ws_xml_get_attr_value(attr));
}
temp = ws_xml_get_child(node, 0, XML_NS_WS_MAN, WSM_HEARTBEATS);
if(temp) {
str = ws_xml_get_node_text(temp);
debug("[heartbeat interval = %s]",str);
if(str[0]=='P') {
// xml duration
if (ws_deserialize_duration(str, &timeout)) {
fault_code = WSEN_INVALID_EXPIRATION_TIME;
goto DONE;
}
debug("timeout = %d", timeout);
subsInfo->heartbeatInterval = timeout * 1000;
subsInfo->heartbeatCountdown = subsInfo->heartbeatInterval;
}
}
if(subsInfo->deliveryMode != WS_EVENT_DELIVERY_MODE_PULL) {
temp = ws_xml_get_child(node, 0, XML_NS_EVENTING, WSEVENT_NOTIFY_TO);
if(temp == NULL) {
message("No notification destination");
fault_code = WSE_INVALID_MESSAGE;
goto DONE;
}
str = ws_xml_get_node_text(ws_xml_get_child(temp, 0, XML_NS_ADDRESSING, WSA_ADDRESS));
debug("event sink: %s", str);
if(str && strcmp(str, "")) {
subsInfo->epr_notifyto = u_strdup(str);
if(destination_reachable(str) == 0) {
fault_code = WSMAN_EVENT_DELIVER_TO_UNUSABLE;
goto DONE;
}
}
else {
fault_code = WSE_INVALID_MESSAGE;
goto DONE;
}
temp = ws_xml_get_child(node, 0, XML_NS_WS_MAN, WSM_AUTH);
if(temp) {
attr = ws_xml_find_node_attr(temp, NULL, WSM_PROFILE);
if(attr) {
str = ws_xml_get_attr_value(attr);
if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTP_BASIC))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTP_BASIC_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTP_DIGEST))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTP_DIGEST_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_BASIC))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_BASIC_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_DIGEST))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_DIGEST_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_BASIC))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_BASIC_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_DIGEST))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_DIGEST_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_SPNEGO_KERBEROS))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_SPNEGO_KERBEROS_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_SPNEGO_KERBEROS))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_SPNEGO_KERBEROS_TYPE;
else if(!strcasecmp(str, WSMAN_SECURITY_PROFILE_HTTP_SPNEGO_KERBEROS))
subsInfo->deliveryAuthType = WSMAN_SECURITY_PROFILE_HTTP_SPNEGO_KERBEROS_TYPE;
else {
fault_code = WSMAN_INVALID_OPTIONS;
fault_detail_code = WSMAN_DETAIL_AUTHERIZATION_MODE;
goto DONE;
}
debug("auth profile type = %d", subsInfo->deliveryAuthType);
}
}
}
if(wsman_parse_credentials(indoc, subsInfo, &fault_code, &fault_detail_code)) {
goto DONE;
}
if(wsman_parse_event_request(indoc, subsInfo, &fault_code, &fault_detail_code)) {
goto DONE;
}
if (msg->auth_data.username != NULL) {
subsInfo->auth_data.username =
u_strdup(msg->auth_data.username);
subsInfo->auth_data.password =
u_strdup(msg->auth_data.password);
} else {
subsInfo->auth_data.username = NULL;
subsInfo->auth_data.password = NULL;
}
temp = ws_xml_get_soap_header(indoc);
temp = ws_xml_get_child(temp, 0, XML_NS_OPENWSMAN, "FormerUID");
ntext = ws_xml_get_node_text(temp);
if(temp && ntext) { //it is a request from the saved reqeust. So we recover the former UUID
strncpy(subsInfo->subsId, ntext, EUIDLEN);
debug("Recover to uuid:%s",subsInfo->subsId);
}
else
generate_uuid(subsInfo->subsId, EUIDLEN, 1);
if(subsInfo->deliveryMode != WS_EVENT_DELIVERY_MODE_PULL)
create_notification_template(indoc, subsInfo);
DONE:
if (fault_code != WSMAN_RC_OK) {
outdoc = wsman_generate_fault(indoc, fault_code, fault_detail_code, NULL);
destroy_subsinfo(subsInfo);
} else {
*sInfo = subsInfo;
}
return outdoc;
}
/**
* Subscribe Stub for processing subscription requests
* @param op SOAP pperation handler
* @param appData Application data
* @return status
*/
int
wse_subscribe_stub(SoapOpH op, void *appData, void *opaqueData)
{
WsXmlDocH doc = NULL;
int retVal = 0;
WsSubscribeInfo *subsInfo = NULL;
WsmanStatus status;
WsXmlNodeH inNode, body, header, temp;
SoapH soap = soap_get_op_soap(op);
WsContextH soapCntx = ws_get_soap_context(soap);
int i;
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
WsEndPointSubscribe endPoint =
(WsEndPointSubscribe)ep->serviceEndPoint;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsContextH epcntx;
char *buf = NULL;
char *expiresstr = NULL;
int len;
epcntx = ws_create_ep_context(soap, _doc);
wsman_status_init(&status);
doc = create_subs_info(op, epcntx, _doc, &subsInfo);
if (doc != NULL) {
goto DONE;
}
if (endPoint && (retVal = endPoint(epcntx, subsInfo, &status, opaqueData))) {
debug("Subscribe fault");
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, status.fault_msg);
destroy_subsinfo(subsInfo);
goto DONE;
}
doc = wsman_create_response_envelope(_doc, NULL);
if (!doc)
goto DONE;
char str[30];
wsman_expiretime2xmldatetime(subsInfo->expires, str);
if(soap->subscriptionOpSet) {
temp = ws_xml_get_child(ws_xml_get_soap_body(_doc), 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE);
temp = ws_xml_get_child(temp, 0, XML_NS_EVENTING, WSEVENT_EXPIRES);
if(temp) {
expiresstr = strdup(ws_xml_get_node_text(temp));
ws_xml_set_node_text(temp, str);
}
temp = ws_xml_get_soap_header(_doc);
inNode = ws_xml_get_child(temp, 0, XML_NS_OPENWSMAN, "FormerUID");
if(inNode == NULL)
ws_xml_add_child(temp, XML_NS_OPENWSMAN, "FormerUID", subsInfo->subsId);
ws_xml_dump_memory_enc(_doc, &buf, &len, "UTF-8");
if(buf) {
soap->subscriptionOpSet->save_subscritption(soap->uri_subsRepository, subsInfo->subsId, (unsigned char*)buf);
u_free(buf);
}
}
lnode_t * sinfo = lnode_create(subsInfo);
pthread_mutex_lock(&soap->lockSubs);
list_append(soapCntx->subscriptionMemList, sinfo);
pthread_mutex_unlock(&soap->lockSubs);
debug("subscription uuid:%s kept in the memory", subsInfo->subsId);
header = ws_xml_get_soap_header(doc);
inNode = ws_xml_get_soap_header(_doc);
inNode = ws_xml_get_child(inNode, 0, XML_NS_ADDRESSING, WSA_REPLY_TO);
inNode = ws_xml_get_child(inNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PROPERTIES);
if(inNode == NULL)
inNode = ws_xml_get_child(inNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS);
if(inNode) {
for (i = 0;
(temp =
ws_xml_get_child(inNode, i, NULL, NULL)) != NULL;
i++) {
ws_xml_duplicate_tree(header, temp);
}
}
body = ws_xml_get_soap_body(doc);
inNode = ws_xml_add_child(body, XML_NS_EVENTING, WSEVENT_SUBSCRIBE_RESP, NULL);
temp = ws_xml_add_child(inNode, XML_NS_EVENTING, WSEVENT_SUBSCRIPTION_MANAGER, NULL);
if(subsInfo->expires)
ws_xml_add_child(inNode, XML_NS_EVENTING, WSEVENT_EXPIRES, expiresstr);
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PULL)
ws_xml_add_child_format(inNode, XML_NS_ENUMERATION,
WSENUM_ENUMERATION_CONTEXT, "uuid:%s", subsInfo->subsId);
inNode = temp;
if(inNode){
temp = ws_xml_get_soap_header(_doc);
temp = ws_xml_get_child(temp, 0, XML_NS_ADDRESSING, WSA_TO);
ws_xml_add_child(inNode,XML_NS_ADDRESSING,WSA_ADDRESS,ws_xml_get_node_text(temp));
}
temp = ws_xml_add_child(inNode, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS, NULL);
if(temp)
ws_xml_add_child_format(temp, XML_NS_EVENTING, WSEVENT_IDENTIFIER, "uuid:%s", subsInfo->subsId);
DONE:
if (doc) {
soap_set_op_doc(op, doc, 0);
}
u_free(expiresstr);
ws_serializer_free_all(epcntx->serializercntx);
ws_destroy_context(epcntx);
u_free(status.fault_msg);
return retVal;
}
/**
* Unsubscribe Stub for processing unsubscription requests
* @param op SOAP pperation handler
* @param appData Application data
* @return status
*/
int
wse_unsubscribe_stub(SoapOpH op, void *appData, void *opaqueData)
{
WsXmlDocH doc = NULL;
int retVal = 0;
WsSubscribeInfo *subsInfo = NULL;
WsmanStatus status;
WsXmlNodeH inNode;
WsXmlNodeH header;
SoapH soap = soap_get_op_soap(op);
WsContextH soapCntx = ws_get_soap_context(soap);
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
WsEndPointSubscribe endPoint =
(WsEndPointSubscribe)ep->serviceEndPoint;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsContextH epcntx;
epcntx = ws_create_ep_context(soap, _doc);
wsman_status_init(&status);
header = ws_xml_get_soap_header(_doc);
inNode = ws_xml_get_child(header, 0, XML_NS_EVENTING, WSEVENT_IDENTIFIER);
if(inNode == NULL) {
status.fault_code = WSE_INVALID_MESSAGE;
status.fault_detail_code = WSMAN_DETAIL_INVALID_VALUE;
goto DONE;
}
char *uuid = ws_xml_get_node_text(inNode);
lnode_t *t = NULL;
pthread_mutex_lock(&soap->lockSubs);
if(!list_isempty(soapCntx->subscriptionMemList)) {
t = list_first(soapCntx->subscriptionMemList);
subsInfo = (WsSubscribeInfo *)t->list_data;
while(t && strcasecmp(subsInfo->subsId, uuid+5)) {
t = list_next(soapCntx->subscriptionMemList, t);
if(t)
subsInfo = (WsSubscribeInfo *)t->list_data;
}
}
if(t == NULL) {
status.fault_code = WSMAN_INVALID_PARAMETER;
status.fault_detail_code = WSMAN_DETAIL_INVALID_VALUE;
doc = wsman_generate_fault( _doc,
status.fault_code, status.fault_detail_code, NULL);
pthread_mutex_unlock(&soap->lockSubs);
goto DONE;
}
pthread_mutex_unlock(&soap->lockSubs);
if (endPoint && (retVal = endPoint(epcntx, subsInfo, &status, opaqueData))) {
debug("UnSubscribe fault");
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, status.fault_msg);
goto DONE;
}
pthread_mutex_lock(&subsInfo->notificationlock);
subsInfo->flags |= WSMAN_SUBSCRIBEINFO_UNSUBSCRIBE;
pthread_mutex_unlock(&subsInfo->notificationlock);
debug("subscription %s unsubscribed", uuid);
doc = wsman_create_response_envelope( _doc, NULL);
if (!doc)
goto DONE;
DONE:
if (doc) {
soap_set_op_doc(op, doc, 0);
}
ws_serializer_free_all(epcntx->serializercntx);
ws_destroy_context(epcntx);
u_free(status.fault_msg);
return retVal;
}
/**
* Renew Stub for processing renew requests
* @param op SOAP pperation handler
* @param appData Application data
* @return status
*/
int
wse_renew_stub(SoapOpH op, void *appData, void *opaqueData)
{
WsXmlDocH doc = NULL;
int retVal = 0;
WsSubscribeInfo *subsInfo;
WsmanStatus status;
WsXmlNodeH inNode;
WsXmlNodeH body;
WsXmlNodeH header;
SoapH soap = soap_get_op_soap(op);
WsContextH soapCntx = ws_get_soap_context(soap);
char * expirestr = NULL;
WsDispatchEndPointInfo *ep = (WsDispatchEndPointInfo *) appData;
WsEndPointSubscribe endPoint =
(WsEndPointSubscribe)ep->serviceEndPoint;
WsXmlDocH _doc = soap_get_op_doc(op, 1);
WsContextH epcntx;
epcntx = ws_create_ep_context(soap, _doc);
wsman_status_init(&status);
body = ws_xml_get_soap_body(_doc);
header = ws_xml_get_soap_header(_doc);
inNode = ws_xml_get_child(header, 0, XML_NS_EVENTING, WSEVENT_IDENTIFIER);
char *uuid = ws_xml_get_node_text(inNode);
if(uuid == NULL) {
status.fault_code = WSE_INVALID_MESSAGE;
status.fault_detail_code = WSMAN_DETAIL_MISSING_VALUES;
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, NULL);
goto DONE;
}
pthread_mutex_lock(&soap->lockSubs);
lnode_t *t = NULL;
if(!list_isempty(soapCntx->subscriptionMemList)) {
t = list_first(soapCntx->subscriptionMemList);
subsInfo = (WsSubscribeInfo *)t->list_data;
while(t && strcasecmp(subsInfo->subsId, uuid+5)) {
t = list_next(soapCntx->subscriptionMemList, t);
if(t)
subsInfo = (WsSubscribeInfo *)t->list_data;
}
}
if(t == NULL) {
status.fault_code = WSE_UNABLE_TO_RENEW;
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, NULL);
pthread_mutex_unlock(&soap->lockSubs);
goto DONE;
}
pthread_mutex_unlock(&soap->lockSubs);
inNode = ws_xml_get_child(body, 0, XML_NS_EVENTING, WSEVENT_RENEW);
inNode = ws_xml_get_child(inNode, 0, XML_NS_EVENTING ,WSEVENT_EXPIRES);
pthread_mutex_lock(&subsInfo->notificationlock);
wsman_set_expiretime(inNode, &subsInfo->expires, &status.fault_code);
expirestr = ws_xml_get_node_text(inNode);
pthread_mutex_unlock(&subsInfo->notificationlock);
if (status.fault_code != WSMAN_RC_OK) {
status.fault_detail_code = WSMAN_DETAIL_EXPIRATION_TIME;
pthread_mutex_unlock(&subsInfo->notificationlock);
goto DONE;
}
char str[30];
wsman_expiretime2xmldatetime(subsInfo->expires, str);
if(soap->subscriptionOpSet) {
soap->subscriptionOpSet->update_subscription(soap->uri_subsRepository, uuid+5,
str);
debug("subscription %s updated!", uuid);
}
if (endPoint && (retVal = endPoint(epcntx, subsInfo, &status, opaqueData))) {
debug("renew fault in plug-in");
doc = wsman_generate_fault( _doc, status.fault_code, status.fault_detail_code, status.fault_msg);
pthread_mutex_unlock(&subsInfo->notificationlock);
goto DONE;
}
doc = wsman_create_response_envelope( _doc, NULL);
if (!doc)
goto DONE;
body = ws_xml_get_soap_body(doc);
body = ws_xml_add_child(body, XML_NS_EVENTING, WSEVENT_RENEW_RESP, NULL);
ws_xml_add_child(body, XML_NS_EVENTING, WSEVENT_EXPIRES, expirestr);
DONE:
if (doc) {
soap_set_op_doc(op, doc, 0);
}
ws_serializer_free_all(epcntx->serializercntx);
ws_destroy_context(epcntx);
u_free(status.fault_msg);
return retVal;
}
void
wsman_heartbeat_generator(WsContextH cntx, void *opaqueData)
{
SoapH soap = cntx->soap;
WsSubscribeInfo *subsInfo = NULL;
WsEventThreadContextH threadcntx = NULL;
WsContextH soapCntx = ws_get_soap_context(soap);
pthread_t eventsender;
pthread_attr_t pattrs;
int r;
if ((r = pthread_attr_init(&pattrs)) != 0) {
debug("pthread_attr_init failed = %d", r);
return;
}
if ((r = pthread_attr_setdetachstate(&pattrs,
PTHREAD_CREATE_DETACHED)) !=0) {
debug("pthread_attr_setdetachstate = %d", r);
return;
}
pthread_mutex_lock(&soap->lockSubs);
lnode_t *node = list_first(soapCntx->subscriptionMemList);
while(node) {
subsInfo = (WsSubscribeInfo *)node->list_data;
pthread_mutex_lock(&subsInfo->notificationlock);
#if 0
debug("subscription %s : event sent last time = %d, heartbeat= %ld, heartbeatcountdown = %ld, pending events = %d",
subsInfo->subsId, subsInfo->eventSentLastTime, subsInfo->heartbeatInterval, subsInfo->heartbeatCountdown, subsInfo->flags & WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING);
#endif
if(subsInfo->flags & WSMAN_SUBSCRIBEINFO_UNSUBSCRIBE) {
goto LOOP;
}
if(time_expired(subsInfo->expires)) {
goto LOOP;
}
if(subsInfo->heartbeatInterval == 0 || subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PULL) {
goto LOOP;
}
subsInfo->heartbeatCountdown -= 1000;
if(subsInfo->heartbeatCountdown > 0) {
goto LOOP;
}
if(subsInfo->eventSentLastTime) {
subsInfo->eventSentLastTime = 0;
}
else {
debug("one heartbeat document created for %s", subsInfo->subsId);
if((subsInfo->flags & WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING) == 0) {
threadcntx = ws_create_event_context(soap, subsInfo, NULL);
if(pthread_create(&eventsender, &pattrs, wse_heartbeat_sender, threadcntx) == 0)
subsInfo->flags |= WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING;
}
}
subsInfo->heartbeatCountdown = subsInfo->heartbeatInterval;
LOOP:
pthread_mutex_unlock(&subsInfo->notificationlock);
node = list_next(soapCntx->subscriptionMemList, node);
}
pthread_mutex_unlock(&soap->lockSubs);
}
static int wse_send_notification(WsEventThreadContextH cntx, WsXmlDocH outdoc, WsSubscribeInfo *subsInfo, unsigned char acked)
{
int retVal = 0;
WsManClient *notificationSender = wsmc_create_from_uri(subsInfo->epr_notifyto);
if(subsInfo->contentEncoding)
wsmc_set_encoding(notificationSender, subsInfo->contentEncoding);
if(subsInfo->username)
wsman_transport_set_userName(notificationSender, subsInfo->username);
if(subsInfo->password)
wsman_transport_set_password(notificationSender, subsInfo->password);
if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTP_BASIC_TYPE) {
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTP_DIGEST_TYPE) {
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_BASIC_TYPE) {
wsman_transport_set_verify_peer(notificationSender, 0);
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_DIGEST_TYPE) {
wsman_transport_set_verify_peer(notificationSender, 0);
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_TYPE) {
wsman_transport_set_verify_peer(notificationSender, 1);
wsman_transport_set_certhumbprint(notificationSender, subsInfo->certificate_thumbprint);
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_BASIC_TYPE) {
wsman_transport_set_verify_peer(notificationSender, 1);
wsman_transport_set_certhumbprint(notificationSender, subsInfo->certificate_thumbprint);
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_DIGEST_TYPE) {
wsman_transport_set_verify_peer(notificationSender, 1);
wsman_transport_set_certhumbprint(notificationSender, subsInfo->certificate_thumbprint);
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_SPNEGO_KERBEROS_TYPE) {
}
else if(subsInfo->deliveryAuthType ==
WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL_SPNEGO_KERBEROS_TYPE) {
}
else { //WSMAN_SECURITY_PROFILE_HTTP_SPNEGO_KERBEROS_TYPE
}
wsmc_transport_init(notificationSender, NULL);
if (wsman_send_request(notificationSender, outdoc)) {
warning("wse_send_notification: wsman_send_request fails for endpoint %s", subsInfo->epr_notifyto);
/* FIXME: retVal */
}
if(acked) {
retVal = WSE_NOTIFICATION_NOACK;
WsXmlDocH ackdoc = wsmc_build_envelope_from_response(notificationSender);
if(ackdoc) {
WsXmlNodeH node = ws_xml_get_soap_header(ackdoc);
WsXmlNodeH srcnode = ws_xml_get_soap_header(outdoc);
WsXmlNodeH temp = NULL;
srcnode = ws_xml_get_child(srcnode, 0, XML_NS_ADDRESSING, WSA_MESSAGE_ID);
if(node) {
temp = ws_xml_get_child(node, 0, XML_NS_ADDRESSING, WSA_RELATES_TO);
if(temp) {
if(!strcasecmp(ws_xml_get_node_text(srcnode),
ws_xml_get_node_text(temp))) {
node = ws_xml_get_child(node, 0, XML_NS_ADDRESSING, WSA_ACTION);
if(!strcasecmp(ws_xml_get_node_text(node), WSMAN_ACTION_ACK))
retVal = 0;
}
}
}
ws_xml_destroy_doc(ackdoc);
}
}
wsmc_release(notificationSender);
return retVal;
}
static void * wse_event_sender(void * thrdcntx, unsigned char flag)
{
char uuidBuf[50];
WsXmlNodeH header;
if(thrdcntx == NULL) return NULL;
WsEventThreadContextH threadcntx = (WsEventThreadContextH)thrdcntx;
WsSubscribeInfo * subsInfo = threadcntx->subsInfo;
if(flag == 1)
debug("wse_notification_sender for %s started", subsInfo->subsId);
else
debug("wse_heartbeat_sender for %s started", subsInfo->subsId);
WsXmlDocH notificationDoc = NULL;
pthread_mutex_lock(&subsInfo->notificationlock);
if(flag == 1)
subsInfo->eventSentLastTime = 1;
if(!(subsInfo->flags & WSMAN_SUBSCRIBEINFO_UNSUBSCRIBE) &&
!time_expired(subsInfo->expires)) {
if(flag) {
notificationDoc = threadcntx->outdoc;
}
else {
notificationDoc = ws_xml_duplicate_doc(subsInfo->heartbeatDoc);
header = ws_xml_get_soap_header(notificationDoc);
generate_uuid(uuidBuf, sizeof(uuidBuf), 0);
ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_MESSAGE_ID,uuidBuf);
}
if (subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_EVENTS ||
subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PUSHWITHACK){
if(wse_send_notification(threadcntx, notificationDoc, subsInfo, 1) == WSE_NOTIFICATION_NOACK)
subsInfo->flags |= WSMAN_SUBSCRIPTION_CANCELLED;
}
else
wse_send_notification(threadcntx, notificationDoc, subsInfo, 0);
}
ws_xml_destroy_doc(notificationDoc);
subsInfo->flags &= ~WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING;
debug("[ wse_notification_sender thread for %s quit! ]",subsInfo->subsId);
pthread_mutex_unlock(&subsInfo->notificationlock);
u_free(thrdcntx);
return NULL;
}
void * wse_heartbeat_sender(void *thrdcntx)
{
return wse_event_sender(thrdcntx, 0);
}
void *wse_notification_sender(void *thrdcntx)
{
return wse_event_sender(thrdcntx, 1);
}
void wse_notification_manager(void * cntx)
{
int retVal;
WsSubscribeInfo * subsInfo = NULL;
WsXmlDocH notificationDoc =NULL;
WsXmlNodeH header = NULL;
WsXmlNodeH body = NULL;
WsXmlNodeH node = NULL;
WsXmlNodeH eventnode = NULL;
WsXmlNodeH temp = NULL;
lnode_t *subsnode = NULL;
WsEventThreadContextH threadcntx = NULL;
WsContextH contex = (WsContextH)cntx;
SoapH soap = contex->soap;
WsContextH soapCntx = ws_get_soap_context(soap);
pthread_t eventsender;
pthread_attr_t pattrs;
char uuidBuf[50];
int r;
if ((r = pthread_attr_init(&pattrs)) != 0) {
debug("pthread_attr_init failed = %d", r);
return;
}
if ((r = pthread_attr_setdetachstate(&pattrs,
PTHREAD_CREATE_DETACHED)) !=0) {
debug("pthread_attr_setdetachstate = %d", r);
return;
}
pthread_mutex_lock(&soap->lockSubs);
subsnode = list_first(soapCntx->subscriptionMemList);
while(subsnode) {
subsInfo = (WsSubscribeInfo *)subsnode->list_data;
pthread_mutex_lock(&subsInfo->notificationlock);
threadcntx = ws_create_event_context(soap, subsInfo, NULL);
if(((subsInfo->flags & WSMAN_SUBSCRIBEINFO_UNSUBSCRIBE) ||
subsInfo->flags & WSMAN_SUBSCRIPTION_CANCELLED ||
time_expired(subsInfo->expires)) &&
((subsInfo->flags & WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING ) == 0)) {
lnode_t *nodetemp = list_delete2(soapCntx->subscriptionMemList, subsnode);
soap->subscriptionOpSet->delete_subscription(soap->uri_subsRepository, subsInfo->subsId);
soap->eventpoolOpSet->clear(subsInfo->subsId, delete_notification_info);
if(!(subsInfo->flags & WSMAN_SUBSCRIBEINFO_UNSUBSCRIBE) && subsInfo->cancel)
subsInfo->cancel(threadcntx);
if(subsInfo->flags & WSMAN_SUBSCRIBEINFO_UNSUBSCRIBE)
debug("Unsubscribed!uuid:%s deleted", subsInfo->subsId);
else if(subsInfo->flags & WSMAN_SUBSCRIPTION_CANCELLED)
debug("Cancelled! uuid:%s deleted", subsInfo->subsId);
else
debug("Expired! uuid:%s deleted", subsInfo->subsId);
destroy_subsinfo(subsInfo);
lnode_destroy(subsnode);
u_free(threadcntx);
subsnode = nodetemp;
continue;
}
if(subsInfo->eventpoll) { //poll the events
retVal = subsInfo->eventpoll(threadcntx);
if(retVal == WSE_NOTIFICATION_EVENTS_PENDING) {
goto LOOP;
}
}
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PULL)
goto LOOP;
WsNotificationInfoH notificationInfo = NULL;
if(soap->eventpoolOpSet->remove(subsInfo->subsId, &notificationInfo) ) // to get the event and delete it from the event source
goto LOOP;
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_PULL) goto LOOP;
notificationDoc = ws_xml_duplicate_doc(subsInfo->templateDoc);
header = ws_xml_get_soap_header(notificationDoc);
body = ws_xml_get_soap_body(notificationDoc);
if(notificationInfo->headerOpaqueData) {
temp = ws_xml_get_doc_root(notificationInfo->headerOpaqueData);
ws_xml_duplicate_tree(header, temp);
}
if(subsInfo->deliveryMode == WS_EVENT_DELIVERY_MODE_EVENTS) {
ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_ACTION, WSEVENT_DELIVERY_MODE_EVENTS);
generate_uuid(uuidBuf, sizeof(uuidBuf), 0);
ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_MESSAGE_ID,uuidBuf);
eventnode = ws_xml_add_child(body, XML_NS_WS_MAN, WSM_EVENTS, NULL);
while(notificationInfo) {
temp = ws_xml_add_child(eventnode, XML_NS_WS_MAN, WSM_EVENT, NULL);
if(notificationInfo->EventAction) {
ws_xml_add_node_attr(temp, XML_NS_WS_MAN, WSM_ACTION, notificationInfo->EventAction);
}
else {
ws_xml_add_node_attr(temp, XML_NS_WS_MAN, WSM_ACTION, WSMAN_ACTION_EVENT);
}
if(temp) {
node = ws_xml_get_doc_root(notificationInfo->EventContent);
ws_xml_duplicate_children(temp, node);
}
delete_notification_info(notificationInfo);
soap->eventpoolOpSet->remove(subsInfo->subsId, &notificationInfo);
}
}
else{
generate_uuid(uuidBuf, sizeof(uuidBuf), 0);
ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_MESSAGE_ID,uuidBuf);
if(notificationInfo->EventAction)
ws_xml_add_child(header, XML_NS_WS_MAN, WSM_ACTION, notificationInfo->EventAction);
else
ws_xml_add_child(header, XML_NS_WS_MAN, WSM_ACTION, WSMAN_ACTION_EVENT);
node = ws_xml_get_doc_root(notificationInfo->EventContent);
ws_xml_duplicate_children(body, node);
delete_notification_info(notificationInfo);
}
if(subsInfo->deliveryMode != WS_EVENT_DELIVERY_MODE_PULL) {
if((subsInfo->flags & WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING) == 0) {
WsEventThreadContextH threadcntx2 = ws_create_event_context(soap, subsInfo, notificationDoc);
if(pthread_create(&eventsender, &pattrs, wse_notification_sender, threadcntx2) == 0) {
subsInfo->flags |= WSMAN_SUBSCRIPTION_NOTIFICAITON_PENDING;
}
else {
debug("thread created for %s failed![ %s ]", subsInfo->subsId, strerror(errno));
}
}
}
LOOP:
if(threadcntx)
u_free(threadcntx);
pthread_mutex_unlock(&subsInfo->notificationlock);
subsnode = list_next(soapCntx->subscriptionMemList, subsnode);
}
pthread_mutex_unlock(&soap->lockSubs);
}
#endif
WsContextH
ws_get_soap_context(SoapH soap)
{
return soap->cntx;
}
int
ws_remove_context_val(WsContextH cntx, char *name)
{
int retVal = 1;
if (cntx && name) {
hnode_t *hn;
u_lock(cntx->soap);
hn = hash_lookup(cntx->entries, name);
if (hn) {
debug("Found context entry: %s", name);
hash_delete_free(cntx->entries, hn);
retVal = 0;
}
u_unlock(cntx->soap);
}
return retVal;
}
int
ws_set_context_ulong_val(WsContextH cntx,
char *name,
unsigned long val)
{
int retVal = set_context_val(cntx, name, &val, sizeof(unsigned long),
0, WS_CONTEXT_TYPE_ULONG);
return retVal;
}
int
ws_set_context_xml_doc_val(WsContextH cntx,
char *name,
WsXmlDocH val)
{
cntx->indoc = val;
return 0;
}
WsContextH
ws_create_ep_context(SoapH soap,
WsXmlDocH doc)
{
WsContextH cntx = ws_create_context(soap);
if (cntx)
ws_set_context_xml_doc_val(cntx, WSFW_INDOC, doc);
return cntx;
}
int
ws_destroy_context(WsContextH cntx)
{
int retVal = 1;
if (cntx && cntx->owner) {
ws_clear_context_entries(cntx);
ws_clear_context_enuminfos(cntx);
ws_serializer_cleanup(cntx->serializercntx);
if(cntx->subscriptionMemList) {
list_destroy_nodes(cntx->subscriptionMemList);
list_destroy(cntx->subscriptionMemList);
}
u_free(cntx);
retVal = 0;
}
return retVal;
}
hnode_t*
create_context_entry(hash_t * h,
char *name,
void *val)
{
char *key = u_strdup(name);
hnode_t *hn = hnode_create(val);
hash_insert(h, hn, (void *) key);
return hn;
}
SoapH
ws_context_get_runtime(WsContextH cntx)
{
SoapH soap = NULL;
if (cntx)
soap = cntx->soap;
return soap;
}
const void *
get_context_val(WsContextH cntx, const char *name)
{
const char *val = NULL;
if (cntx && name) {
u_lock(cntx->soap);
if (cntx->entries) {
hnode_t *hn = hash_lookup(cntx->entries, name);
if (hn)
val = hnode_get(hn);
}
u_unlock(cntx->soap);
}
return val;
}
const void *
ws_get_context_val(WsContextH cntx, const char *name, int *size)
{
return get_context_val(cntx, name);
}
unsigned long
ws_get_context_ulong_val(WsContextH cntx, char *name)
{
const void *ptr = get_context_val(cntx, name);
if (ptr != NULL)
return *((unsigned long *) ptr);
return 0;
}
SoapOpH
soap_create_op(SoapH soap,
char *inboundAction,
char *outboundAction, //optional
char *role,
SoapServiceCallback callbackProc,
void *callbackData,
unsigned long flags)
{
SoapDispatchH disp = NULL;
op_t *entry = NULL;
if ((disp = wsman_dispatch_create(soap, inboundAction, outboundAction,
NULL, //reserved, must be NULL
callbackProc, callbackData, flags)) != NULL) {
entry = create_op_entry(soap, disp, NULL);
}
return (SoapOpH) entry;
}
/**
* Get Operation Document
* @param op Operation Handle
* @param inbound Direction flag
* @return XML Document
*/
WsXmlDocH
soap_get_op_doc(SoapOpH op,
int inbound)
{
WsXmlDocH doc = NULL;
if (op) {
op_t *e = (op_t *) op;
doc = (!inbound) ? e->out_doc : e->in_doc;
}
return doc;
}
WsXmlDocH
soap_detach_op_doc(SoapOpH op,
int inbound)
{
WsXmlDocH doc = NULL;
if (op) {
op_t *e = (op_t *) op;
if (!inbound) {
doc = e->out_doc;
e->out_doc = NULL;
} else {
doc = e->in_doc;
e->in_doc = NULL;
}
}
return doc;
}
int
soap_set_op_doc(SoapOpH op,
WsXmlDocH doc,
int inbound)
{
int retVal = 1;
if (op) {
op_t *e = (op_t *) op;
if (!inbound)
e->out_doc = doc;
else
e->in_doc = doc;
retVal = 0;
}
return retVal;
}
SoapH
soap_get_op_soap(SoapOpH op)
{
if (op)
return (SoapH) ((op_t *) op)->dispatch->soap;
return NULL;
}
void
soap_destroy_op(SoapOpH op)
{
destroy_op_entry((op_t *) op);
}
op_t *
create_op_entry(SoapH soap,
SoapDispatchH dispatch,
WsmanMessage * data)
{
op_t *entry = (op_t *) u_zalloc(sizeof(op_t));
if (entry) {
entry->dispatch = dispatch;
entry->cntx = ws_create_context(soap);
entry->data = data;
// entry->processed_headers = list_create(LISTCOUNT_T_MAX);
}
return entry;
}
void
destroy_op_entry(op_t * entry)
{
SoapH soap;
debug("destroy op");
if (!entry) {
debug("nothing to destroy...");
return;
}
soap = entry->dispatch->soap;
if (soap == NULL) {
goto NULL_SOAP;
}
u_lock(soap);
if (soap->dispatchList && list_contains(soap->dispatchList, &entry->dispatch->node)) {
list_delete(soap->dispatchList, &entry->dispatch->node);
}
u_unlock(soap);
NULL_SOAP:
destroy_dispatch_entry(entry->dispatch);
ws_destroy_context(entry->cntx);
#if 0
list_destroy_nodes(entry->processed_headers);
list_destroy(entry->processed_headers);
#endif
u_free(entry);
}
void
destroy_dispatch_entry(SoapDispatchH entry)
{
int usageCount;
list_t *dlist;
if (!entry) {
return;
}
u_lock(entry->soap);
entry->usageCount--;
usageCount = entry->usageCount;
dlist = entry->soap->dispatchList;
if (!usageCount && dlist != NULL &&
list_contains(dlist, &entry->node)) {
lnode_t *n = list_delete(dlist, &entry->node);
lnode_destroy(n);
}
u_unlock(entry->soap);
if (!usageCount) {
if (entry->inboundFilterList) {
list_destroy_nodes(entry->inboundFilterList);
list_destroy(entry->inboundFilterList);
}
if (entry->outboundFilterList) {
list_destroy_nodes(entry->outboundFilterList);
list_destroy(entry->outboundFilterList);
}
u_free(entry->inboundAction);
u_free(entry->outboundAction);
u_free(entry);
}
}
void
soap_destroy(SoapH soap)
{
if (soap == NULL )
return;
if (soap->dispatcherProc)
soap->dispatcherProc(soap->cntx, soap->dispatcherData, NULL);
if (soap->dispatchList) {
while (!list_isempty(soap->dispatchList)) {
destroy_dispatch_entry(
(SoapDispatchH)list_first(soap->dispatchList));
}
list_destroy(soap->dispatchList);
}
if (soap->processedMsgIdList) {
while (!list_isempty(soap->processedMsgIdList)) {
lnode_t *node = list_del_first(soap->processedMsgIdList);
u_free(node->list_data);
lnode_destroy(node);
}
list_destroy(soap->processedMsgIdList);
}
if (soap->inboundFilterList) {
list_destroy_nodes(soap->inboundFilterList);
list_destroy(soap->inboundFilterList);
}
if (soap->outboundFilterList) {
list_destroy_nodes(soap->outboundFilterList);
list_destroy(soap->outboundFilterList);
}
ws_xml_parser_destroy();
ws_destroy_context(soap->cntx);
u_free(soap);
return;
}
void
wsman_status_init(WsmanStatus * status)
{
status->fault_code = 0;
status->fault_detail_code = 0;
status->fault_msg = NULL;
}
int
wsman_check_status(WsmanStatus * status)
{
return status->fault_code;
}