//---------------------------------------------------------------------------- | |
// | |
// Copyright (C) Intel Corporation, 2007. | |
// | |
// File: OpenWsmanClient.cpp | |
// | |
// Contents: An implementation of the WsmanClient interface using openwsman | |
// | |
//---------------------------------------------------------------------------- | |
#include "OpenWsmanClient.h" | |
extern "C" { | |
#include "wsman-api.h" | |
} | |
#include "wsman-client-transport.h" | |
#include "wsman-filter.h" | |
#define WSMAN_ENCODING "UTF-8" | |
using namespace WsmanClientNamespace; | |
static bool CheckWsmanResponse(WsManClient* cl, WsXmlDocH& doc); | |
static bool ResourceNotFound(WsManClient* cl, WsXmlDocH& enumerationRes); | |
static string XmlDocToString(WsXmlDocH& doc); | |
static client_opt_t *SetOptions(WsManClient* cl); | |
static string GetSubscribeContext(WsXmlDocH& doc); | |
static string ExtractPayload(WsXmlDocH& doc); | |
static string ExtractItems(WsXmlDocH& doc); | |
// Construct from params. | |
OpenWsmanClient::OpenWsmanClient(const char *host, | |
const int port, | |
const char *path , | |
const char *scheme, | |
const char *auth_method , | |
const char *username, | |
const char *password, | |
// proxy address include proxy port | |
const char *proxy, | |
//proxy user name | |
const char *proxy_username, | |
//proxy password | |
const char *proxy_password | |
#ifdef _WIN32 | |
// determines which cert store to search | |
,const bool local, | |
// search for a client cert with this name | |
const char *cert, | |
// search for a cient cert with this oid | |
const char *oid | |
#endif | |
) | |
{ | |
cl = wsmc_create(host, port, path, scheme, username, password); | |
SetAuth(auth_method); | |
#ifdef _WIN32 | |
SetClientCert(oid, cert, local); | |
#endif | |
SetProxy(proxy,proxy_username,proxy_password); | |
wsmc_transport_init(cl, (void*)NULL); | |
} | |
// Destructor. | |
OpenWsmanClient::~OpenWsmanClient() | |
{ | |
wsmc_transport_fini(cl); | |
wsmc_release(cl); | |
} | |
string OpenWsmanClient::Identify() const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH identifyResponse = wsmc_action_identify(cl, | |
options | |
); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, identifyResponse); | |
string xml = ExtractPayload(identifyResponse); | |
ws_xml_destroy_doc(identifyResponse); | |
return xml; | |
} | |
string OpenWsmanClient::Create(const string &resourceUri, const string &data) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH createResponse = wsmc_action_create_fromtext(cl, | |
resourceUri.c_str(), | |
options, | |
data.c_str(), data.length(), WSMAN_ENCODING); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, createResponse); | |
string xml = ExtractPayload(createResponse); | |
ws_xml_destroy_doc(createResponse); | |
return xml; | |
} | |
void OpenWsmanClient::Delete(const string &resourceUri, const NameValuePairs *s) const | |
{ | |
client_opt_t *options; | |
options = SetOptions(cl); | |
if(s) | |
{ | |
// Add selectors. | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
WsXmlDocH deleteResponse = wsmc_action_delete( cl, | |
(char *)resourceUri.c_str(), | |
options); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, deleteResponse); | |
ws_xml_destroy_doc(deleteResponse); | |
} | |
void OpenWsmanClient::Enumerate(const string &resourceUri, vector<string> &enumRes, const NameValuePairs *s) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
if(s) | |
{ | |
// Add selectors. | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
WsXmlDocH doc; | |
char *enumContext; | |
WsXmlDocH enum_response = wsmc_action_enumerate(cl, (char *)resourceUri.c_str(), options, NULL); | |
try | |
{ | |
if(ResourceNotFound(cl, enum_response)) | |
{ | |
wsmc_options_destroy(options); | |
return; | |
} | |
} | |
catch(WsmanSoapFault& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
catch(WsmanClientException& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
catch(exception& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
enumContext = wsmc_get_enum_context(enum_response); | |
ws_xml_destroy_doc(enum_response); | |
while (enumContext != NULL && enumContext[0] != 0 ) { | |
doc = wsmc_action_pull(cl, resourceUri.c_str(), options, NULL, enumContext); | |
try | |
{ | |
CheckWsmanResponse(cl, doc); | |
} | |
catch(exception& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
string payload = ExtractItems(doc); | |
if (payload.length() > 0) | |
enumRes.push_back(payload); | |
u_free(enumContext); | |
enumContext = wsmc_get_enum_context(doc); | |
ws_xml_destroy_doc(doc); | |
} | |
u_free(enumContext); | |
wsmc_options_destroy(options); | |
} | |
void OpenWsmanClient::Enumerate(const string & resourceUri, WsmanFilter & filter, vector<string> &enumRes) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
char *enumContext; | |
WsXmlDocH enum_response = wsmc_action_enumerate(cl, (char *)resourceUri.c_str(), options, filter.getfilter()); | |
try | |
{ | |
if(ResourceNotFound(cl, enum_response)) | |
{ | |
wsmc_options_destroy(options); | |
return; | |
} | |
} | |
catch(WsmanSoapFault& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
catch(WsmanClientException& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
catch(exception& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
enumContext = wsmc_get_enum_context(enum_response); | |
ws_xml_destroy_doc(enum_response); | |
while (enumContext != NULL && enumContext[0] != 0 ) { | |
doc = wsmc_action_pull(cl, resourceUri.c_str(), options, NULL, enumContext); | |
try | |
{ | |
CheckWsmanResponse(cl, doc); | |
} | |
catch(exception& e) | |
{ | |
wsmc_options_destroy(options); | |
throw e; | |
} | |
string payload = ExtractItems(doc); | |
if (payload.length() > 0) | |
enumRes.push_back(payload); | |
u_free(enumContext); | |
enumContext = wsmc_get_enum_context(doc); | |
ws_xml_destroy_doc(doc); | |
} | |
u_free(enumContext); | |
wsmc_options_destroy(options); | |
} | |
string OpenWsmanClient::Get(const string &resourceUri, const NameValuePairs *s) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
// Add selectors. | |
if (s) { | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
doc = wsmc_action_get(cl, (char *)resourceUri.c_str(), options); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, doc); | |
string xml = ExtractPayload(doc); | |
ws_xml_destroy_doc(doc); | |
return xml; | |
} | |
string OpenWsmanClient::Put(const string &resourceUri, const string &content, const NameValuePairs *s) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
// Add selectors. | |
if (s) { | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
doc = wsmc_action_put_fromtext(cl, resourceUri.c_str(), options, content.c_str(), content.length(), WSMAN_ENCODING); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, doc); | |
string xml = ExtractPayload(doc); | |
ws_xml_destroy_doc(doc); | |
return xml; | |
} | |
string OpenWsmanClient::Invoke(const string &resourceUri, const string &methodName, const string &content, const NameValuePairs *s) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
string error; | |
// Add selectors. | |
if (s) { | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
doc = wsmc_action_invoke_fromtext(cl, resourceUri.c_str(), options, | |
(char *)methodName.c_str(), content.c_str(), | |
content.length(), WSMAN_ENCODING); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, doc); | |
string xml = ExtractPayload(doc); | |
ws_xml_destroy_doc(doc); | |
return xml; | |
} | |
string OpenWsmanClient::Subscribe(const string &resourceUri, const SubscribeInfo &info, string &subsContext) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
options->delivery_mode = (WsmanDeliveryMode)info.delivery_mode; | |
options->delivery_uri = u_strdup(info.delivery_uri.c_str()); | |
if(info.dialect != "" && info.filter != "") { | |
filter_create_simple(info.dialect.c_str(), info.filter.c_str()); | |
} | |
if(info.refenceParam != "") | |
options->reference = u_strdup(info.refenceParam.c_str()); | |
// Add selectors. | |
if (info.selectorset) { | |
for (PairsIterator p = info.selectorset->begin(); p != info.selectorset->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
options->expires = info.expires; | |
options->heartbeat_interval = info.heartbeat_interval; | |
doc = wsmc_action_subscribe(cl, (char *)resourceUri.c_str(), options, NULL); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, doc); | |
string xml = ExtractPayload(doc); | |
subsContext = GetSubscribeContext(doc); | |
ws_xml_destroy_doc(doc); | |
return xml; | |
} | |
string OpenWsmanClient::Renew(const string &resourceUri, const string &subsContext, float expire, const NameValuePairs *s) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
options->expires = expire; | |
if (s) { | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
doc = wsmc_action_renew(cl, (char *)resourceUri.c_str(), options, subsContext.c_str()); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, doc); | |
string xml = ExtractPayload(doc); | |
ws_xml_destroy_doc(doc); | |
return xml; | |
} | |
void OpenWsmanClient::Unsubscribe(const string &resourceUri, const string &subsContext, const NameValuePairs *s) const | |
{ | |
client_opt_t *options = NULL; | |
options = SetOptions(cl); | |
WsXmlDocH doc; | |
if (s) { | |
for (PairsIterator p = s->begin(); p != s->end(); ++p) { | |
if(p->second != "") | |
wsmc_add_selector(options, | |
(char *)p->first.c_str(), (char *)p->second.c_str()); | |
} | |
} | |
doc = wsmc_action_unsubscribe(cl, (char *)resourceUri.c_str(), options, subsContext.c_str()); | |
wsmc_options_destroy(options); | |
CheckWsmanResponse(cl, doc); | |
ws_xml_destroy_doc(doc); | |
return; | |
} | |
string GetSubscribeContext(WsXmlDocH& doc) | |
{ | |
string str; | |
char *buf = NULL; | |
WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc); | |
WsXmlNodeH tmp = NULL; | |
if(bodyNode == NULL) return str; | |
bodyNode = ws_xml_get_child(bodyNode, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE_RESP); | |
if(bodyNode == NULL) return str; | |
bodyNode = ws_xml_get_child(bodyNode, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIPTION_MANAGER); | |
if(bodyNode == NULL) return str; | |
tmp = ws_xml_get_child(bodyNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS); | |
if(tmp == NULL) { | |
tmp = ws_xml_get_child(bodyNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PROPERTIES); | |
if(tmp == NULL) return str; | |
} | |
wsmc_node_to_buf(tmp, &buf); | |
str = string(buf); | |
u_free(buf); | |
return str; | |
} | |
string ExtractPayload(WsXmlDocH& doc) | |
{ | |
WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc); | |
WsXmlNodeH payloadNode = ws_xml_get_child(bodyNode, 0, NULL, NULL); | |
char *buf = NULL; | |
wsmc_node_to_buf( payloadNode, &buf); | |
string payload = string(buf); | |
u_free(buf); | |
return payload; | |
} | |
string ExtractItems(WsXmlDocH& doc) | |
{ | |
string payload; | |
WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc); | |
WsXmlNodeH pullResponse = ws_xml_get_child(bodyNode, 0, XML_NS_ENUMERATION, WSENUM_PULL_RESP); | |
WsXmlNodeH itemsNode = ws_xml_get_child(pullResponse, 0, XML_NS_ENUMERATION, WSENUM_ITEMS); | |
WsXmlNodeH n = ws_xml_get_child(itemsNode, 0 , NULL, NULL ); | |
if (n) { | |
char *buf = NULL; | |
wsmc_node_to_buf( n, &buf); | |
payload = string(buf); | |
u_free(buf); | |
} | |
return payload; | |
} | |
string XmlDocToString(WsXmlDocH& doc) { | |
char *buf; | |
int len; | |
ws_xml_dump_memory_enc(doc, &buf, &len, WSMAN_ENCODING); | |
string str = string(buf); // This constructor copies the data. | |
if (buf) | |
#ifdef _WIN32 | |
ws_xml_free_memory(buf); | |
#else | |
u_free(buf); | |
#endif | |
return str; | |
} | |
client_opt_t * SetOptions(WsManClient* cl) | |
{ | |
client_opt_t *options = wsmc_options_init(); | |
char *ns = wsmc_get_namespace(cl); | |
if(ns) | |
options->cim_ns = u_strdup(ns); | |
return options; | |
} | |
bool CheckWsmanResponse(WsManClient* cl, WsXmlDocH& doc) | |
{ | |
long lastError = wsmc_get_last_error(cl); | |
string error; | |
if(lastError) | |
{ | |
char tmp[10]; | |
error = "Failed to establish a connection with the server.\n"; | |
sprintf(tmp, "%ld", lastError); | |
error.append("Openwsman last error = ").append(tmp); | |
ws_xml_destroy_doc(doc); | |
throw WsmanClientException(error.c_str(), WSMAN_CONNECT_ERROR); | |
} | |
long responseCode = wsmc_get_response_code(cl); | |
if (responseCode != 200 && | |
responseCode != 400 && | |
responseCode != 500) | |
{ | |
char tmp[10]; | |
error = "An HTTP error occurred.\n"; | |
sprintf(tmp, "%ld", responseCode); | |
error.append("HTTP Error = ").append(tmp); | |
ws_xml_destroy_doc(doc); | |
throw WsmanClientException(error.c_str(), WSMAN_HTTP_ERROR); | |
} | |
if(!doc) | |
{ | |
throw WsmanClientException("The Wsman response was NULL."); | |
} | |
if (wsmc_check_for_fault(doc)) { | |
char tmp[10]; | |
WsManFault *fault = wsmc_fault_new(); | |
wsmc_get_fault_data(doc, fault); | |
string subcode_s = fault->subcode ? string(fault->subcode) : ""; | |
string code_s = fault->code ? string(fault->code) : ""; | |
string reason_s = fault->reason ? string(fault->reason) : ""; | |
string detail_s = fault->fault_detail ? string(fault->fault_detail) : ""; | |
ws_xml_destroy_doc(doc); | |
wsmc_fault_destroy(fault); | |
error = "A Soap Fault was received:"; | |
error.append("\nFaultCode: " + code_s); | |
error.append("\nFaultSubCode: " + subcode_s); | |
error.append("\nFaultReason: " + reason_s); | |
error.append("\nFaultDetail: " + detail_s); | |
sprintf(tmp, "%ld", responseCode); | |
error.append("\nHttpCode: = ").append(tmp); | |
throw WsmanSoapFault(error.c_str(), code_s, subcode_s, reason_s, detail_s); | |
} | |
return true; | |
} | |
bool ResourceNotFound(WsManClient* cl, WsXmlDocH& enumerationRes) | |
{ | |
long responseCode = wsmc_get_response_code(cl); | |
if(wsmc_get_last_error(cl) || | |
(responseCode != 200 && responseCode != 400 && responseCode != 500) || | |
!enumerationRes) | |
{ | |
CheckWsmanResponse(cl, enumerationRes); | |
} | |
if (!wsmc_check_for_fault(enumerationRes)) | |
{ | |
return false; | |
} | |
WsManFault *fault = wsmc_fault_new(); | |
bool ret = false; | |
wsmc_get_fault_data(enumerationRes, fault); | |
string subcode_s = fault->subcode ? string(fault->subcode) : ""; | |
if(subcode_s.find("DestinationUnreachable") != string::npos) | |
{ | |
wsmc_fault_destroy(fault); | |
return true; | |
} | |
wsmc_fault_destroy(fault); | |
if(!ret) | |
{ | |
CheckWsmanResponse(cl, enumerationRes); | |
} | |
return ret; | |
} | |
void OpenWsmanClient::SetAuth(const char *auth_method) | |
{ | |
wsman_transport_set_auth_method (cl , (char *)auth_method); | |
if (wsmc_transport_get_auth_value(cl) == WS_MAX_AUTH ) { | |
// Authentication method not supported, reverting to digest | |
wsman_transport_set_auth_method(cl, "digest"); | |
} | |
} | |
void OpenWsmanClient::SetUserName(const char *user_name) | |
{ | |
if (user_name) { | |
wsman_transport_set_userName(cl, (char*)user_name); | |
} | |
} | |
void OpenWsmanClient::SetPassword(const char *password) | |
{ | |
if (password) { | |
wsman_transport_set_password(cl, (char*)password); | |
} | |
} | |
void OpenWsmanClient::SetEncoding(const char *encoding) | |
{ | |
if(encoding) { | |
wsmc_set_encoding(cl,(char *)encoding); | |
} | |
} | |
void OpenWsmanClient::SetNamespace(const char *ns) | |
{ | |
if(ns) { | |
wsmc_set_namespace(cl, (char *)ns); | |
} | |
} | |
void OpenWsmanClient::SetProxy(const char *proxy, const char *proxy_username, const char *proxy_password) | |
{ | |
if (proxy) { | |
wsman_transport_set_proxy(cl, (char*)proxy); | |
} | |
if (proxy_username) { | |
wsman_transport_set_proxy_username(cl, (char*)proxy_username); | |
} | |
if (proxy_password) { | |
wsman_transport_set_proxy_password(cl, (char*)proxy_password); | |
} | |
} | |
#ifdef _WIN32 | |
void OpenWsmanClient::SetClientCert(const char *oid, const char *cert, const bool local) | |
{ | |
if (cert) { | |
wsman_transport_set_cainfo(cl, (char*)cert); | |
} | |
if (oid) { | |
wsman_transport_set_caoid(cl, (char*)oid); | |
} | |
wsman_transport_set_calocal(cl, local); | |
} | |
#else | |
// Set server certificate params | |
// params: cainfo - string naming a file holding one or more certificates to verify the peer with. | |
// capath - string naming a dierctory holding multiple CA certificates to verify the peer with. | |
// Give null arguments if you want curl to search for certificates inthe default path | |
// | |
void OpenWsmanClient::SetServerCert(const char *cainfo, const char *capath) | |
{ | |
// This means curl verifies the server certificate | |
wsman_transport_set_verify_peer(cl, 1); | |
// This means the certificate must indicate that the server is the server to which you meant to connect. | |
wsman_transport_set_verify_host(cl, 2); | |
if (cainfo) { | |
wsman_transport_set_cainfo(cl, (char*)cainfo); | |
} | |
if (capath) { | |
wsman_transport_set_capath(cl, (char*)capath); | |
} | |
} | |
// Set client certificates params | |
// params: cert - file name of your certificate. | |
// key - file name of your private key. | |
void OpenWsmanClient::SetClientCert(const char *cert, const char *key) | |
{ | |
if (cert) { | |
wsman_transport_set_cert(cl, (char*)cert); | |
} | |
if (key) { | |
wsman_transport_set_key(cl, (char*)key); | |
} | |
} | |
#endif |