/******************************************************************************* * 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 #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 : ""); 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, ¬ificationInfo)) 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, ¬ificationInfo) ) // 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, ¬ificationInfo); } } 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; }