add xmlrpc-c 1.03.14 to in tree libs

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3772 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris
2006-12-21 03:57:49 +00:00
parent 6d9679b164
commit 3abb7730b2
338 changed files with 98032 additions and 2 deletions

View File

@@ -0,0 +1 @@
cpptest

View File

@@ -0,0 +1,177 @@
ifeq ($(SRCDIR)x,x)
SRCDIR = $(CURDIR)/../..
endif
SUBDIR = src/cpp
BUILDDIR = $(SRCDIR)
VPATH = .:$(SRCDIR)
include $(BUILDDIR)/Makefile.config
default: all
WININET_TRANSPORT_DIR = $(SRCDIR)/lib/wininet_transport
CURL_TRANSPORT_DIR = $(SRCDIR)/lib/curl_transport
LIBWWW_TRANSPORT_DIR = $(SRCDIR)/lib/libwww_transport
ifeq ($(ENABLE_LIBXML2_BACKEND),yes)
LIBXML_INCLUDES = $(LIBXML2_CFLAGS)
LIBXML = $(LIBXML2_LIBS)
else
LIBXML_INCLUDES = -I$(SRCDIR)/lib/expat/xmlparse
LIBXML = $(BUILDDIR)/lib/expat/xmlparse/libxmlrpc_xmlparse.la \
$(BUILDDIR)/lib/expat/xmltok/libxmlrpc_xmltok.la
endif
ifeq ($(ENABLE_LIBXML2),yes)
XMLRPC_XML_PARSER = xmlrpc_libxml2.lo
else
XMLRPC_XML_PARSER = xmlrpc_expat.lo
endif
LIBXMLRPC = $(BUILDDIR)/src/libxmlrpc.la
LIBXMLRPC_SERVER = $(BUILDDIR)/src/libxmlrpc_server.la
LIBXMLRPC_CLIENT = $(BUILDDIR)/src/libxmlrpc_client.la
LIBXMLRPCPP_OBJS = girmem.o value.o fault.o outcome.o param_list.o xml.o
LIBXMLRPC_SERVERPP_OBJS = registry.o
LIBXMLRPC_SERVER_ABYSSPP_OBJS = server_abyss.o
LIBXMLRPC_CLIENTPP_OBJS = client.o client_simple.o
$(LIBXMLRPC_CLIENTPP_OBJS): $(BUILDDIR)/transport_config.h
TRANSPORT_OBJS =
ifeq ($(MUST_BUILD_WININET_CLIENT),yes)
TRANSPORT_OBJS += $(WININET_TRANSPORT_DIR)/xmlrpc_wininet_transport.lo
endif
ifeq ($(MUST_BUILD_CURL_CLIENT),yes)
TRANSPORT_OBJS += $(CURL_TRANSPORT_DIR)/xmlrpc_curl_transport.lo
endif
ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes)
TRANSPORT_OBJS += $(LIBWWW_TRANSPORT_DIR)/xmlrpc_libwww_transport.lo
endif
TRANSPORT_INCLUDES = \
-I$(WININET_TRANSPORT_DIR) \
-I$(CURL_TRANSPORT_DIR) \
-I$(LIBWWW_TRANSPORT_DIR) \
BASIC_INCLUDES = -I$(SRCDIR)/include -I$(BUILDDIR) -I$(SRCDIR) \
-I$(SRCDIR)/lib/util/include
# We always statically-link our C++ code because it's tiny, and C++ is
# no good at shared libraries, anyway. It's actually getting bigger,
# but since I'm determined not to expand the use of libtool (because
# it obfuscates the build process), I haven't figured out yet how to
# get the shared libraries to build for all the platforms.
# libxmlrpc_cpp.a is the legacy C++ wrapper library. The others are the
# more elaborate replacements.
TARGET_LIBRARIES = \
libxmlrpc_cpp.a \
libxmlrpc++.a \
libxmlrpc_server++.a \
libxmlrpc_server_abyss++.a \
libxmlrpc_client++.a \
TARGET_PROGS = cpptest
all: $(TARGET_LIBRARIES)
ifeq ($(MUST_BUILD_CURL_CLIENT),yes)
LDFLAGS += $(shell curl-config --libs) -lpthread
endif
ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes)
LDFLAGS += $(shell libwww-config --libs)
endif
LDFLAGS += $(LADD)
cpptest:%:%.o libxmlrpc_server_abyss++.a libxmlrpc_server++.a \
libxmlrpc_client++.a libxmlrpc++.a libxmlrpc_cpp.a \
$(LIBXMLRPC) $(LIBXMLRPC_SERVER) $(LIBXMLRPC_CLIENT) $(LIBXML)
$(LIBTOOL) --mode=link $(CXXLD) -o $@ $(LDFLAGS) $^
LIBLDFLAGS = $(LADD)
libxmlrpc_cpp.a: XmlRpcCpp.o
-rm -f $@
$(AR) cru $@ $^
$(RANLIB) $@
libxmlrpc++.a: $(LIBXMLRPCPP_OBJS)
-rm -f $@
$(AR) cru $@ $^
$(RANLIB) $@
libxmlrpc_server++.a: $(LIBXMLRPC_SERVERPP_OBJS)
-rm -f $@
$(AR) cru $@ $^
$(RANLIB) $@
libxmlrpc_server_abyss++.a: $(LIBXMLRPC_SERVER_ABYSSPP_OBJS)
-rm -f $@
$(AR) cru $@ $^
$(RANLIB) $@
libxmlrpc_client++.a: $(LIBXMLRPC_CLIENTPP_OBJS)
-rm -f $@
$(AR) cru $@ $^
$(RANLIB) $@
CXXFLAGS = $(CXXFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD)
cpptest.o:%.o:%.cpp
$(CXX) -c $(BASIC_INCLUDES) $(CXXFLAGS) $<
XmlRpcCpp.o:%.o:%.cpp
$(CXX) -c $(BASIC_INCLUDES) $(CXXFLAGS) $<
$(LIBXMLRPCPP_OBJS):%.o:%.cpp
$(CXX) -c $(BASIC_INCLUDES) $(CXXFLAGS) $<
SERVER_INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES)
$(LIBXMLRPC_SERVERPP_OBJS):%.o:%.cpp
$(CXX) -c $(SERVER_INCLUDES) $(CXXFLAGS) $<
SERVER_ABYSS_INCLUDES = $(SERVER_INCLUDES) -I$(SRCDIR)/lib/abyss/src
$(LIBXMLRPC_SERVER_ABYSSPP_OBJS):%.o:%.cpp
$(CXX) -c $(SERVER_ABYSS_INCLUDES) $(CXXFLAGS) $<
CLIENT_INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES) $(TRANSPORT_INCLUDES)
$(LIBXMLRPC_CLIENTPP_OBJS):%.o:%.cpp
$(CXX) -c $(CLIENT_INCLUDES) $(CXXFLAGS) $<
LIBRARIES_TO_INSTALL = $(TARGET_LIBRARIES)
check: cpptest
for tst in $^; do \
./$$tst; \
done;
.PHONY: install
install: install-common
.PHONY: clean clean-local distclean
clean: clean-common clean-local
clean-local:
rm -f $(TARGET_PROGS)
distclean: clean distclean-common
# INCLUDES and DEP_SOURCES are used by dep-common target
INCLUDES = $(BASIC_INCLUDES) $(CLIENT_INCLUDES) $(LIBXML_INCLUDES) \
$(SERVER_INCLUDES) $(SERVER_ABYSS_INCLUDES) $(TRANSPORT_INCLUDES)
DEP_SOURCES = *.cpp
.PHONY: dep
dep: $(BUILDDIR)/transport_config.h dep-common
include $(SRCDIR)/Makefile.common
include Makefile.depend

View File

View File

@@ -0,0 +1,393 @@
// Copyright (C) 2001 by Eric Kidd. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. 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.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR 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.
#include <string>
#include "xmlrpc-c/oldcppwrapper.hpp"
using std::string;
//=========================================================================
// XmlRpcFault Methods
//=========================================================================
XmlRpcFault::XmlRpcFault (const XmlRpcFault &fault) {
xmlrpc_env_init(&mFault);
xmlrpc_env_set_fault(&mFault,
fault.mFault.fault_code,
fault.mFault.fault_string);
}
XmlRpcFault::XmlRpcFault (const int faultCode, const string faultString) {
xmlrpc_env_init(&mFault);
xmlrpc_env_set_fault(&mFault, faultCode,
const_cast<char*>(faultString.c_str()));
}
XmlRpcFault::XmlRpcFault (const xmlrpc_env *env) {
if (!env->fault_string)
throw XmlRpcFault(XMLRPC_INTERNAL_ERROR,
"Tried to create empty fault");
xmlrpc_env_init(&mFault);
xmlrpc_env_set_fault(&mFault, env->fault_code,
const_cast<char*>(env->fault_string));
}
XmlRpcFault::~XmlRpcFault (void) {
xmlrpc_env_clean(&mFault);
}
string XmlRpcFault::getFaultString (void) const {
XMLRPC_ASSERT(mFault.fault_occurred);
return string(mFault.fault_string);
}
//=========================================================================
// XmlRpcEnv Methods
//=========================================================================
XmlRpcEnv::XmlRpcEnv (const XmlRpcEnv &env) {
xmlrpc_env_init(&mEnv);
if (env.hasFaultOccurred())
xmlrpc_env_set_fault(&mEnv,
env.mEnv.fault_code,
env.mEnv.fault_string);
}
XmlRpcFault XmlRpcEnv::getFault (void) const {
return XmlRpcFault(&mEnv);
}
void XmlRpcEnv::throwMe (void) const {
throw XmlRpcFault(&mEnv);
}
//=========================================================================
// XmlRpcValue Methods
//=========================================================================
// If the user doesn't tell us what kind of value to create, use
// a false boolean value as the default.
XmlRpcValue::XmlRpcValue (void) {
XmlRpcEnv env;
mValue = xmlrpc_build_value(env, "b", (xmlrpc_bool) 0);
env.throwIfFaultOccurred();
}
XmlRpcValue XmlRpcValue::makeInt (const XmlRpcValue::int32 i) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "i", i);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeBool (const bool b) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "b", (xmlrpc_bool) b);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeDouble (const double d) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "d", d);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeDateTime (const string& dateTime) {
XmlRpcEnv env;
xmlrpc_value *value;
const char *data = dateTime.c_str(); // Make sure we're not using wchar_t.
value = xmlrpc_build_value(env, "8", data);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeString (const string& str) {
XmlRpcEnv env;
const char *data = str.data(); // Make sure we're not using wchar_t.
size_t size = str.size();
xmlrpc_value *value = xmlrpc_build_value(env, "s#", data, size);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeString (const char *const str) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "s", str);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeString (const char *const str, size_t len) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "s#", str, len);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeArray (void) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "()");
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeStruct (void) {
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_struct_new(env);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue XmlRpcValue::makeBase64 (const unsigned char *const data,
size_t len)
{
XmlRpcEnv env;
xmlrpc_value *value = xmlrpc_build_value(env, "6", data, len);
env.throwIfFaultOccurred();
return XmlRpcValue(value, CONSUME_REFERENCE);
}
XmlRpcValue::int32 XmlRpcValue::getInt (void) const {
XmlRpcEnv env;
XmlRpcValue::int32 result;
xmlrpc_parse_value(env, mValue, "i", &result);
env.throwIfFaultOccurred();
return result;
}
bool XmlRpcValue::getBool (void) const {
XmlRpcEnv env;
xmlrpc_bool result;
xmlrpc_parse_value(env, mValue, "b", &result);
env.throwIfFaultOccurred();
return result;
}
double XmlRpcValue::getDouble (void) const {
XmlRpcEnv env;
double result;
xmlrpc_parse_value(env, mValue, "d", &result);
env.throwIfFaultOccurred();
return result;
}
string XmlRpcValue::getRawDateTime (void) const {
XmlRpcEnv env;
char *result;
xmlrpc_parse_value(env, mValue, "8", &result);
env.throwIfFaultOccurred();
return string(result);
}
string XmlRpcValue::getString (void) const {
XmlRpcEnv env;
char *result;
size_t result_len;
xmlrpc_parse_value(env, mValue, "s#", &result, &result_len);
env.throwIfFaultOccurred();
return string(result, result_len);
}
XmlRpcValue XmlRpcValue::getArray (void) const {
XmlRpcEnv env;
xmlrpc_value *result;
xmlrpc_parse_value(env, mValue, "A", &result);
env.throwIfFaultOccurred();
return XmlRpcValue(result);
}
XmlRpcValue XmlRpcValue::getStruct (void) const {
XmlRpcEnv env;
xmlrpc_value *result;
xmlrpc_parse_value(env, mValue, "S", &result);
env.throwIfFaultOccurred();
return XmlRpcValue(result);
}
void XmlRpcValue::getBase64 (const unsigned char *& out_data,
size_t& out_len) const
{
XmlRpcEnv env;
xmlrpc_parse_value(env, mValue, "6", &out_data, &out_len);
env.throwIfFaultOccurred();
}
size_t XmlRpcValue::arraySize (void) const {
XmlRpcEnv env;
size_t result = xmlrpc_array_size(env, mValue);
env.throwIfFaultOccurred();
return result;
}
void XmlRpcValue::arrayAppendItem (const XmlRpcValue& value) {
XmlRpcEnv env;
xmlrpc_array_append_item(env, mValue, value.borrowReference());
env.throwIfFaultOccurred();
}
XmlRpcValue XmlRpcValue::arrayGetItem (int index) const {
XmlRpcEnv env;
xmlrpc_value *result = xmlrpc_array_get_item(env, mValue, index);
env.throwIfFaultOccurred();
return XmlRpcValue(result);
}
size_t XmlRpcValue::structSize (void) const {
XmlRpcEnv env;
size_t result = xmlrpc_struct_size(env, mValue);
env.throwIfFaultOccurred();
return result;
}
bool XmlRpcValue::structHasKey (const string& key) const {
XmlRpcEnv env;
const char *keystr = key.data();
size_t keylen = key.size();
bool result = xmlrpc_struct_has_key_n(env, mValue,
const_cast<char*>(keystr), keylen);
env.throwIfFaultOccurred();
return result;
}
XmlRpcValue XmlRpcValue::structGetValue (const string& key) const {
XmlRpcEnv env;
const char *keystr = key.data();
size_t keylen = key.size();
xmlrpc_value *result =
xmlrpc_struct_get_value_n(env, mValue,
const_cast<char*>(keystr), keylen);
env.throwIfFaultOccurred();
return XmlRpcValue(result);
}
void XmlRpcValue::structSetValue (const string& key, const XmlRpcValue& value)
{
XmlRpcEnv env;
const char *keystr = key.data();
size_t keylen = key.size();
xmlrpc_struct_set_value_n(env, mValue, (char*) keystr, keylen,
value.borrowReference());
env.throwIfFaultOccurred();
}
void XmlRpcValue::structGetKeyAndValue (const int index,
string& out_key,
XmlRpcValue& out_value) const
{
XmlRpcEnv env;
xmlrpc_value *key, *value;
xmlrpc_struct_get_key_and_value(env, mValue, index, &key, &value);
env.throwIfFaultOccurred();
out_key = XmlRpcValue(key).getString();
out_value = XmlRpcValue(value);
}
XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name,
xmlrpc_method method,
void *data)
{
XmlRpcEnv env;
xmlrpc_registry_add_method (env, mRegistry, NULL,
name.c_str (),
method, data);
env.throwIfFaultOccurred ();
return (*this);
}
XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name,
xmlrpc_method method,
void* data,
const string& signature,
const string& help)
{
XmlRpcEnv env;
xmlrpc_registry_add_method_w_doc (env, mRegistry, NULL,
name.c_str (),
method, data,
signature.c_str (),
help.c_str ());
env.throwIfFaultOccurred ();
return (*this);
}
xmlrpc_mem_block* XmlRpcGenSrv::alloc (XmlRpcEnv& env, const string& body) const
{
xmlrpc_mem_block* result = NULL;
char* contents;
result = xmlrpc_mem_block_new (env, body.length ());
env.throwIfFaultOccurred ();
contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result);
memcpy (contents, body.c_str (), body.length ());
return result;
}
string XmlRpcGenSrv::handle (const string& body) const
{
XmlRpcEnv env;
string result;
xmlrpc_mem_block* input = NULL, * output = NULL;
char* input_data, * output_data;
size_t input_size, output_size;
if (body.length () > xmlrpc_limit_get (XMLRPC_XML_SIZE_LIMIT_ID))
throw XmlRpcFault (XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large");
input = alloc (env, body);
input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input);
input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input);
output = xmlrpc_registry_process_call (env, mRegistry, NULL,
input_data, input_size);
if (output)
{
output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output);
output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
result.assign (output_data, output_size);
xmlrpc_mem_block_free (output);
}
xmlrpc_mem_block_free (input);
if (!result.length ())
throw XmlRpcFault (env);
return result;
}

View File

@@ -0,0 +1,851 @@
/*=============================================================================
client.cpp
===============================================================================
This is the C++ XML-RPC client library for Xmlrpc-c.
Note that unlike most of Xmlprc-c's C++ API, this is _not_ based on the
C client library. This code is independent of the C client library, and
is based directly on the client XML transport libraries (with a little
help from internal C utility libraries).
=============================================================================*/
#include <cassert>
#include <string>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/girmem.hpp"
using girmem::autoObjectPtr;
using girmem::autoObject;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/client.h"
#include "xmlrpc-c/transport.h"
/* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT,
MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT,
MUST_BUILD_LIBWWW_CLIENT
*/
#include "transport_config.h"
#if MUST_BUILD_WININET_CLIENT
#include "xmlrpc_wininet_transport.h"
#endif
#if MUST_BUILD_CURL_CLIENT
#include "xmlrpc_curl_transport.h"
#endif
#if MUST_BUILD_LIBWWW_CLIENT
#include "xmlrpc_libwww_transport.h"
#endif
#include "xmlrpc-c/base.hpp"
#include "xmlrpc-c/xml.hpp"
#include "xmlrpc-c/client.hpp"
using namespace std;
using namespace xmlrpc_c;
namespace {
class memblockStringWrapper {
public:
memblockStringWrapper(string const value) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->memblockP = XMLRPC_MEMBLOCK_NEW(char, &env, 0);
if (env.fault_occurred)
throw(error(env.fault_string));
XMLRPC_MEMBLOCK_APPEND(char, &env, this->memblockP,
value.c_str(), value.size());
if (env.fault_occurred)
throw(error(env.fault_string));
}
memblockStringWrapper(xmlrpc_mem_block * const memblockP) :
memblockP(memblockP) {};
~memblockStringWrapper() {
XMLRPC_MEMBLOCK_FREE(char, this->memblockP);
}
xmlrpc_mem_block * memblockP;
};
} // namespace
namespace xmlrpc_c {
carriageParm::carriageParm() {}
carriageParm::~carriageParm() {}
carriageParm_http0::carriageParm_http0() :
c_serverInfoP(NULL) {}
carriageParm_http0::carriageParm_http0(string const serverUrl) {
this->c_serverInfoP = NULL;
this->instantiate(serverUrl);
}
carriageParm_http0::~carriageParm_http0() {
if (this->c_serverInfoP)
xmlrpc_server_info_free(this->c_serverInfoP);
}
void
carriageParm_http0::instantiate(string const serverUrl) {
if (c_serverInfoP)
throw(error("object already instantiated"));
xmlrpc_env env;
xmlrpc_env_init(&env);
this->c_serverInfoP = xmlrpc_server_info_new(&env, serverUrl.c_str());
if (env.fault_occurred)
throw(error(env.fault_string));
}
void
carriageParm_http0::setBasicAuth(string const username,
string const password) {
if (!c_serverInfoP)
throw(error("object not instantiated"));
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_server_info_set_basic_auth(
&env, this->c_serverInfoP, username.c_str(), password.c_str());
if (env.fault_occurred)
throw(error(env.fault_string));
}
carriageParm_curl0::carriageParm_curl0(
string const serverUrl
) {
this->instantiate(serverUrl);
}
carriageParm_libwww0::carriageParm_libwww0(
string const serverUrl
) {
this->instantiate(serverUrl);
}
carriageParm_wininet0::carriageParm_wininet0(
string const serverUrl
) {
this->instantiate(serverUrl);
}
xmlTransaction::xmlTransaction() {}
void
xmlTransaction::finish(string const& responseXml) const {
xml::trace("XML-RPC RESPONSE", responseXml);
}
void
xmlTransaction::finishErr(error const&) const {
}
xmlTransactionPtr::xmlTransactionPtr() {}
xmlTransaction *
xmlTransactionPtr::operator->() const {
autoObject * const p(this->objectP);
return dynamic_cast<xmlTransaction *>(p);
}
clientXmlTransport::~clientXmlTransport() {}
void
clientXmlTransport::start(carriageParm * const carriageParmP,
string const& callXml,
xmlTransactionPtr const& xmlTranP) {
string responseXml;
this->call(carriageParmP, callXml, &responseXml);
xmlTranP->finish(responseXml);
}
void
clientXmlTransport::finishAsync(xmlrpc_c::timeout const timeout) {
if (timeout.finite == timeout.finite)
throw(error("This class does not have finishAsync()"));
}
void
clientXmlTransport::asyncComplete(
struct xmlrpc_call_info * const callInfoP,
xmlrpc_mem_block * const responseXmlMP,
xmlrpc_env const transportEnv) {
xmlTransactionPtr * const xmlTranPP =
reinterpret_cast<xmlTransactionPtr *>(callInfoP);
try {
if (transportEnv.fault_occurred) {
(*xmlTranPP)->finishErr(error(transportEnv.fault_string));
} else {
string const responseXml(
XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlMP),
XMLRPC_MEMBLOCK_SIZE(char, responseXmlMP));
(*xmlTranPP)->finish(responseXml);
}
} catch(error) {
/* We can't throw an error back to C code, and the async_complete
interface does not provide for failure, so we define ->finish()
as not being capable of throwing an error.
*/
assert(false);
}
delete(xmlTranPP);
/* Ordinarily, *xmlTranPP is the last reference to **xmlTranPP
(The xmlTransaction), so it will get destroyed too. But
->finish() could conceivably create a new reference to
**xmlTranPP, and then it would keep living.
*/
}
clientXmlTransport_http::~clientXmlTransport_http() {}
void
clientXmlTransport_http::call(
carriageParm * const carriageParmP,
string const& callXml,
string * const responseXmlP) {
xmlrpc_env env;
xmlrpc_env_init(&env);
carriageParm_http0 * const carriageParmHttpP =
dynamic_cast<carriageParm_http0 *>(carriageParmP);
if (carriageParmHttpP == NULL)
throw(error("HTTP client XML transport called with carriage "
"parameter object not of class carriageParm_http"));
memblockStringWrapper callXmlM(callXml);
xmlrpc_mem_block * responseXmlMP;
this->c_transportOpsP->call(&env,
this->c_transportP,
carriageParmHttpP->c_serverInfoP,
callXmlM.memblockP,
&responseXmlMP);
if (env.fault_occurred)
throw(error(env.fault_string));
memblockStringWrapper responseHolder(responseXmlMP);
// Makes responseXmlMP get freed at end of scope
*responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlMP),
XMLRPC_MEMBLOCK_SIZE(char, responseXmlMP));
}
void
clientXmlTransport_http::start(
carriageParm * const carriageParmP,
string const& callXml,
xmlTransactionPtr const& xmlTranP) {
xmlrpc_env env;
xmlrpc_env_init(&env);
carriageParm_http0 * const carriageParmHttpP =
dynamic_cast<carriageParm_http0 *>(carriageParmP);
if (carriageParmHttpP == NULL)
throw(error("HTTP client XML transport called with carriage "
"parameter object not of type carriageParm_http"));
memblockStringWrapper callXmlM(callXml);
/* xmlTranP2 is the reference to the XML transaction that is held by
the running transaction, in C code. It lives in dynamically allocated
storage and xmlTranP2P points to it.
*/
xmlTransactionPtr * const xmlTranP2P(new xmlTransactionPtr(xmlTranP));
try {
this->c_transportOpsP->send_request(
&env,
this->c_transportP,
carriageParmHttpP->c_serverInfoP,
callXmlM.memblockP,
&this->asyncComplete,
reinterpret_cast<xmlrpc_call_info *>(xmlTranP2P));
if (env.fault_occurred)
throw(error(env.fault_string));
} catch (...) {
delete xmlTranP2P;
throw;
}
}
void
clientXmlTransport_http::finishAsync(xmlrpc_c::timeout const timeout) {
xmlrpc_timeoutType const c_timeoutType(
timeout.finite ? timeout_yes : timeout_no);
xmlrpc_timeout const c_timeout(timeout.duration);
this->c_transportOpsP->finish_asynch(
this->c_transportP, c_timeoutType, c_timeout);
}
#if MUST_BUILD_CURL_CLIENT
clientXmlTransport_curl::clientXmlTransport_curl(
string const networkInterface,
bool const noSslVerifyPeer,
bool const noSslVerifyHost,
string const userAgent) {
struct xmlrpc_curl_xportparms transportParms;
transportParms.network_interface =
networkInterface.size() > 0 ? networkInterface.c_str() : NULL;
transportParms.no_ssl_verifypeer = noSslVerifyPeer;
transportParms.no_ssl_verifyhost = noSslVerifyHost;
transportParms.user_agent =
userAgent.size() > 0 ? userAgent.c_str() : NULL;
this->c_transportOpsP = &xmlrpc_curl_transport_ops;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_curl_transport_ops.create(
&env, 0, "", "", (xmlrpc_xportparms *)&transportParms,
XMLRPC_CXPSIZE(user_agent),
&this->c_transportP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
#else // MUST_BUILD_CURL_CLIENT
clientXmlTransport_curl::clientXmlTransport_curl(string, bool, bool, string) {
throw("There is no Curl client XML transport in this XML-RPC client "
"library");
}
#endif
clientXmlTransport_curl::~clientXmlTransport_curl() {
this->c_transportOpsP->destroy(this->c_transportP);
}
#if MUST_BUILD_LIBWWW_CLIENT
clientXmlTransport_libwww::clientXmlTransport_libwww(
string const appname,
string const appversion) {
this->c_transportOpsP = &xmlrpc_libwww_transport_ops;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_libwww_transport_ops.create(
&env, 0, appname.c_str(), appversion.c_str(), NULL, 0,
&this->c_transportP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
#else // MUST_BUILD_LIBWWW_CLIENT
clientXmlTransport_libwww::clientXmlTransport_libwww(string, string) {
throw(error("There is no Libwww client XML transport "
"in this XML-RPC client library"));
}
#endif
clientXmlTransport_libwww::~clientXmlTransport_libwww() {
this->c_transportOpsP->destroy(this->c_transportP);
}
#if MUST_BUILD_WININET_CLIENT
clientXmlTransport_wininet::clientXmlTransport_wininet(
bool const allowInvalidSslCerts
) {
struct xmlrpc_wininet_xportparms transportParms;
transportParms.allowInvalidSSLCerts = allowInvalidSslCerts;
this->c_transportOpsP = &xmlrpc_wininet_transport_ops;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_wininet_transport_ops.create(
&env, 0, "", "", &transportParms, XMLRPC_WXPSIZE(allowInvalidSSLCerts),
&this->c_transportP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
#else // MUST_BUILD_WININET_CLIENT
clientXmlTransport_wininet::clientXmlTransport_wininet(bool const) {
throw(error("There is no Wininet client XML transport "
"in this XML-RPC client library"));
}
#endif
clientXmlTransport_wininet::~clientXmlTransport_wininet() {
this->c_transportOpsP->destroy(this->c_transportP);
}
clientTransaction::clientTransaction() {}
clientTransactionPtr::clientTransactionPtr() {}
clientTransactionPtr::~clientTransactionPtr() {}
clientTransaction *
clientTransactionPtr::operator->() const {
autoObject * const p(this->objectP);
return dynamic_cast<clientTransaction *>(p);
}
client::~client() {}
void
client::start(carriageParm * const carriageParmP,
string const methodName,
paramList const& paramList,
clientTransactionPtr const& tranP) {
/*----------------------------------------------------------------------------
Start an RPC, wait for it to complete, and finish it.
Usually, a derived class overrides this with something that does
not wait for the RPC to complete, but rather arranges for something
to finish the RPC later when the RPC does complete.
-----------------------------------------------------------------------------*/
rpcOutcome outcome;
this->call(carriageParmP, methodName, paramList, &outcome);
tranP->finish(outcome);
}
client_xml::client_xml(clientXmlTransport * const transportP) :
transportP(transportP) {}
void
client_xml::call(carriageParm * const carriageParmP,
string const methodName,
paramList const& paramList,
rpcOutcome * const outcomeP) {
string callXml;
string responseXml;
xml::generateCall(methodName, paramList, &callXml);
xml::trace("XML-RPC CALL", callXml);
this->transportP->call(carriageParmP, callXml, &responseXml);
xml::trace("XML-RPC RESPONSE", responseXml);
xml::parseResponse(responseXml, outcomeP);
}
void
client_xml::start(carriageParm * const carriageParmP,
string const methodName,
paramList const& paramList,
clientTransactionPtr const& tranP) {
string callXml;
xml::generateCall(methodName, paramList, &callXml);
xml::trace("XML-RPC CALL", callXml);
xmlTransaction_clientPtr const xmlTranP(tranP);
this->transportP->start(carriageParmP, callXml, xmlTranP);
}
void
client_xml::finishAsync(xmlrpc_c::timeout const timeout) {
transportP->finishAsync(timeout);
}
connection::connection(client * const clientP,
carriageParm * const carriageParmP) :
clientP(clientP), carriageParmP(carriageParmP) {}
connection::~connection() {}
rpc::rpc(string const methodName,
xmlrpc_c::paramList const& paramList) {
this->state = STATE_UNFINISHED;
this->methodName = methodName;
this->paramList = paramList;
}
rpc::~rpc() {
if (this->state == STATE_ERROR)
delete(this->errorP);
}
void
rpc::call(client * const clientP,
carriageParm * const carriageParmP) {
if (this->state != STATE_UNFINISHED)
throw(error("Attempt to execute an RPC that has already been "
"executed"));
clientP->call(carriageParmP,
this->methodName,
this->paramList,
&this->outcome);
this->state = outcome.succeeded() ? STATE_SUCCEEDED : STATE_FAILED;
}
void
rpc::call(connection const& connection) {
this->call(connection.clientP, connection.carriageParmP);
}
void
rpc::start(client * const clientP,
carriageParm * const carriageParmP) {
if (this->state != STATE_UNFINISHED)
throw(error("Attempt to execute an RPC that has already been "
"executed"));
clientP->start(carriageParmP,
this->methodName,
this->paramList,
rpcPtr(this));
}
void
rpc::start(xmlrpc_c::connection const& connection) {
this->start(connection.clientP, connection.carriageParmP);
}
void
rpc::finish(rpcOutcome const& outcome) {
this->state = outcome.succeeded() ? STATE_SUCCEEDED : STATE_FAILED;
this->outcome = outcome;
this->notifyComplete();
}
void
rpc::finishErr(error const& error) {
this->state = STATE_ERROR;
this->errorP = new girerr::error(error);
this->notifyComplete();
}
void
rpc::notifyComplete() {
/*----------------------------------------------------------------------------
Anyone who does RPCs asynchronously and doesn't use polling will
want to make his own class derived from 'rpc' and override this
with a notifyFinish() that does something.
Typically, notifyFinish() will queue the RPC so some other thread
will deal with the fact that the RPC is finished.
In the absence of the aforementioned queueing, the RPC becomes
unreferenced as soon as our Caller releases his reference, so the
RPC gets destroyed when we return.
-----------------------------------------------------------------------------*/
}
value
rpc::getResult() const {
switch (this->state) {
case STATE_UNFINISHED:
throw(error("Attempt to get result of RPC that is not finished."));
break;
case STATE_ERROR:
throw(*this->errorP);
break;
case STATE_FAILED:
throw(error("RPC failed. " +
this->outcome.getFault().getDescription()));
break;
case STATE_SUCCEEDED: {
// All normal
}
}
return this->outcome.getResult();
}
fault
rpc::getFault() const {
switch (this->state) {
case STATE_UNFINISHED:
throw(error("Attempt to get fault from RPC that is not finished"));
break;
case STATE_ERROR:
throw(*this->errorP);
break;
case STATE_SUCCEEDED:
throw(error("Attempt to get fault from an RPC that succeeded"));
break;
case STATE_FAILED: {
// All normal
}
}
return this->outcome.getFault();
}
bool
rpc::isFinished() const {
return (this->state != STATE_UNFINISHED);
}
bool
rpc::isSuccessful() const {
return (this->state == STATE_SUCCEEDED);
}
rpcPtr::rpcPtr() {}
rpcPtr::rpcPtr(rpc * const rpcP) {
this->instantiate(rpcP);
}
rpcPtr::rpcPtr(string const methodName,
xmlrpc_c::paramList const& paramList) {
this->instantiate(new rpc(methodName, paramList));
}
rpc *
rpcPtr::operator->() const {
autoObject * const p(this->objectP);
return dynamic_cast<rpc *>(p);
}
xmlTransaction_client::xmlTransaction_client(
clientTransactionPtr const& tranP) :
tranP(tranP) {}
void
xmlTransaction_client::finish(string const& responseXml) const {
xml::trace("XML-RPC RESPONSE", responseXml);
try {
rpcOutcome outcome;
xml::parseResponse(responseXml, &outcome);
this->tranP->finish(outcome);
} catch (error const caughtError) {
this->tranP->finishErr(caughtError);
}
}
void
xmlTransaction_client::finishErr(error const& error) const {
this->tranP->finishErr(error);
}
xmlTransaction_clientPtr::xmlTransaction_clientPtr() {}
xmlTransaction_clientPtr::xmlTransaction_clientPtr(
clientTransactionPtr const& tranP) {
this->instantiate(new xmlTransaction_client(tranP));
}
xmlTransaction_client *
xmlTransaction_clientPtr::operator->() const {
autoObject * const p(this->objectP);
return dynamic_cast<xmlTransaction_client *>(p);
}
} // namespace

View File

@@ -0,0 +1,180 @@
#include <string>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base.hpp"
#include "xmlrpc-c/client.hpp"
#include <xmlrpc-c/client.hpp>
/* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT,
MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT,
MUST_BUILD_LIBWWW_CLIENT
*/
#include "transport_config.h"
#include "xmlrpc-c/client_simple.hpp"
using namespace std;
using namespace xmlrpc_c;
namespace xmlrpc_c {
namespace {
/*----------------------------------------------------------------------------
Use an object of this class to set up to remove a reference to an
xmlrpc_value object (a C object with manual reference management)
at then end of a scope -- even if the scope ends with a throw.
-----------------------------------------------------------------------------*/
class cValueWrapper {
xmlrpc_value * valueP;
public:
cValueWrapper(xmlrpc_value * valueP) : valueP(valueP) {}
~cValueWrapper() { xmlrpc_DECREF(valueP); }
};
} // namespace
clientSimple::clientSimple() {
if (string(XMLRPC_DEFAULT_TRANSPORT) == string("curl"))
this->transportP = new clientXmlTransport_curl;
else if (string(XMLRPC_DEFAULT_TRANSPORT) == string("libwww"))
this->transportP = new clientXmlTransport_libwww;
else if (string(XMLRPC_DEFAULT_TRANSPORT) == string("wininet"))
this->transportP = new clientXmlTransport_wininet;
else
throw(error("INTERNAL ERROR: "
"Default client XML transport is not one we recognize"));
this->clientP = new client_xml(transportP);
}
clientSimple::~clientSimple() {
delete this->clientP;
delete this->transportP;
}
void
clientSimple::call(string const serverUrl,
string const methodName,
value * const resultP) {
carriageParm_http0 carriageParm(serverUrl);
rpcPtr rpcPtr(methodName, paramList());
rpcPtr->call(this->clientP, &carriageParm);
*resultP = rpcPtr->getResult();
}
namespace {
void
makeParamArray(string const format,
xmlrpc_value ** const paramArrayPP,
va_list args) {
xmlrpc_env env;
xmlrpc_env_init(&env);
/* The format is a sequence of parameter specifications, such as
"iiii" for 4 integer parameters. We add parentheses to make it
an array of those parameters: "(iiii)".
*/
string const arrayFormat("(" + string(format) + ")");
const char * tail;
xmlrpc_build_value_va(&env, arrayFormat.c_str(),
args, paramArrayPP, &tail);
if (env.fault_occurred)
throw(error(env.fault_string));
if (strlen(tail) != 0) {
/* xmlrpc_build_value_va() parses off a single value specification
from its format string, and 'tail' points to whatever is after
it. Our format string should have been a single array value,
meaning tail is end-of-string. If it's not, that means
something closed our array early.
*/
xmlrpc_DECREF(*paramArrayPP);
throw(error("format string is invalid. It apparently has a "
"stray right parenthesis"));
}
}
} // namespace
void
clientSimple::call(string const serverUrl,
string const methodName,
string const format,
value * const resultP,
...) {
carriageParm_http0 carriageParm(serverUrl);
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_value * paramArrayP;
va_list args;
va_start(args, resultP);
makeParamArray(format, &paramArrayP, args);
va_end(args);
if (env.fault_occurred)
throw(error(env.fault_string));
else {
cValueWrapper paramArrayWrapper(paramArrayP); // ensure destruction
unsigned int const paramCount = xmlrpc_array_size(&env, paramArrayP);
if (env.fault_occurred)
throw(error(env.fault_string));
paramList paramList;
for (unsigned int i = 0; i < paramCount; ++i) {
xmlrpc_value * paramP;
xmlrpc_array_read_item(&env, paramArrayP, i, &paramP);
if (env.fault_occurred)
throw(error(env.fault_string));
else {
cValueWrapper paramWrapper(paramP); // ensure destruction
paramList.add(value(paramP));
}
}
rpcPtr rpcPtr(methodName, paramList);
rpcPtr->call(this->clientP, &carriageParm);
*resultP = rpcPtr->getResult();
}
}
void
clientSimple::call(string const serverUrl,
string const methodName,
paramList const& paramList,
value * const resultP) {
carriageParm_http0 carriageParm(serverUrl);
rpcPtr rpcPtr(methodName, paramList);
rpcPtr->call(this->clientP, &carriageParm);
*resultP = rpcPtr->getResult();
}
} // namespace

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
#include <string>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.hpp"
using namespace std;
namespace xmlrpc_c {
fault::fault() : valid(false) {};
fault::fault(string const _description,
xmlrpc_c::fault::code_t const _code
) :
valid(true),
code(_code),
description(_description)
{}
xmlrpc_c::fault::code_t
fault::getCode() const {
if (!valid)
throw(error("Attempt to access placeholder xmlrpc_c::fault object"));
return this->code;
}
string
fault::getDescription() const {
if (!valid)
throw(error("Attempt to access placeholder xmlrpc_c::fault object"));
return this->description;
}
} // namespace

View File

@@ -0,0 +1,123 @@
#include "pthreadx.h"
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/girmem.hpp"
using namespace std;
using namespace girmem;
namespace girmem {
void
autoObject::incref() {
pthread_mutex_lock(&this->refcountLock);
++this->refcount;
pthread_mutex_unlock(&this->refcountLock);
}
void
autoObject::decref(bool * const unreferencedP) {
if (this->refcount == 0)
throw(error("Decrementing ref count of unreferenced object"));
pthread_mutex_lock(&this->refcountLock);
--this->refcount;
*unreferencedP = (this->refcount == 0);
pthread_mutex_unlock(&this->refcountLock);
}
autoObject::autoObject() {
int rc;
rc = pthread_mutex_init(&this->refcountLock, NULL);
if (rc != 0)
throw(error("Unable to initialize pthread mutex"));
this->refcount = 0;
}
autoObject::~autoObject() {
if (this->refcount > 0)
throw(error("Destroying referenced object"));
int rc;
rc = pthread_mutex_destroy(&this->refcountLock);
if (rc != 0)
throw(error("Unable to destroy pthread mutex"));
}
autoObjectPtr::autoObjectPtr() : objectP(NULL) {}
autoObjectPtr::autoObjectPtr(autoObject * const objectP) {
this->objectP = objectP;
objectP->incref();
}
autoObjectPtr::autoObjectPtr(autoObjectPtr const& autoObjectPtr) {
// copy constructor
this->objectP = autoObjectPtr.objectP;
if (this->objectP)
this->objectP->incref();
}
autoObjectPtr::~autoObjectPtr() {
if (this->objectP) {
bool dead;
this->objectP->decref(&dead);
if (dead)
delete(this->objectP);
}
}
void
autoObjectPtr::instantiate(autoObject * const objectP) {
this->objectP = objectP;
objectP->incref();
}
autoObjectPtr
autoObjectPtr::operator=(autoObjectPtr const& autoObjectPtr) {
if (this->objectP != NULL)
throw(error("Already instantiated"));
this->objectP = autoObjectPtr.objectP;
this->objectP->incref();
return *this;
}
autoObject *
autoObjectPtr::operator->() const {
return this->objectP;
}
} // namespace

View File

@@ -0,0 +1,57 @@
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.hpp"
using namespace std;
namespace xmlrpc_c {
rpcOutcome::rpcOutcome() : valid(false) {}
rpcOutcome::rpcOutcome(xmlrpc_c::value const result) :
valid(true), _succeeded(true), result(result)
{}
rpcOutcome::rpcOutcome(xmlrpc_c::fault const fault) :
valid(true), _succeeded(false), fault(fault)
{}
bool
rpcOutcome::succeeded() const {
if (!valid)
throw(error("Attempt to access rpcOutcome object before setting it"));
return _succeeded;
}
fault
rpcOutcome::getFault() const {
if (!valid)
throw(error("Attempt to access rpcOutcome object before setting it"));
if (_succeeded)
throw(error("Attempt to get fault description from a non-failure "
"RPC outcome"));
return fault;
}
value
rpcOutcome::getResult() const {
if (!valid)
throw(error("Attempt to access rpcOutcome object before setting it"));
if (!_succeeded)
throw(error("Attempt to get result from an unsuccessful RPC outcome"));
return result;
}
} // namespace

View File

@@ -0,0 +1,259 @@
#include <climits>
#include <cfloat>
#include <ctime>
#include <string>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base.hpp"
using namespace std;
using namespace xmlrpc_c;
namespace xmlrpc_c {
paramList::paramList(unsigned int const paramCount) {
this->paramVector.reserve(paramCount);
}
void
paramList::add(xmlrpc_c::value const param) {
this->paramVector.push_back(param);
}
unsigned int
paramList::size() const {
return this->paramVector.size();
}
xmlrpc_c::value
paramList::operator[](unsigned int const subscript) const {
if (subscript >= this->paramVector.size())
throw(girerr::error(
"Subscript of xmlrpc_c::paramList out of bounds"));
return this->paramVector[subscript];
}
int
paramList::getInt(unsigned int const paramNumber,
int const minimum,
int const maximum) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
if (this->paramVector[paramNumber].type() != value::TYPE_INT)
throw(fault("Parameter that is supposed to be integer is not",
fault::CODE_TYPE));
int const intvalue(static_cast<int>(
value_int(this->paramVector[paramNumber])));
if (intvalue < minimum)
throw(fault("Integer parameter too low", fault::CODE_TYPE));
if (intvalue > maximum)
throw(fault("Integer parameter too high", fault::CODE_TYPE));
return intvalue;
}
bool
paramList::getBoolean(unsigned int const paramNumber) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
if (this->paramVector[paramNumber].type() != value::TYPE_BOOLEAN)
throw(fault("Parameter that is supposed to be boolean is not",
fault::CODE_TYPE));
return static_cast<bool>(value_boolean(this->paramVector[paramNumber]));
}
double
paramList::getDouble(unsigned int const paramNumber,
double const minimum,
double const maximum) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
if (this->paramVector[paramNumber].type() != value::TYPE_DOUBLE)
throw(fault("Parameter that is supposed to be floating point number "
"is not",
fault::CODE_TYPE));
double const doublevalue(static_cast<double>(
value_double(this->paramVector[paramNumber])));
if (doublevalue < minimum)
throw(fault("Floating point number parameter too low",
fault::CODE_TYPE));
if (doublevalue > maximum)
throw(fault("Floating point number parameter too high",
fault::CODE_TYPE));
return doublevalue;
}
time_t
paramList::getDatetime_sec(
unsigned int const paramNumber,
paramList::timeConstraint const constraint) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]);
if (paramP->type() != value::TYPE_DATETIME)
throw(fault("Parameter that is supposed to be a datetime is not",
fault::CODE_TYPE));
time_t const timeValue(static_cast<time_t>(value_datetime(*paramP)));
time_t const now(time(NULL));
switch (constraint) {
case TC_ANY:
/* He'll take anything; no problem */
break;
case TC_NO_FUTURE:
if (timeValue > now)
throw(fault("Datetime parameter that is not supposed to be in "
"the future is.", fault::CODE_TYPE));
break;
case TC_NO_PAST:
if (timeValue < now)
throw(fault("Datetime parameter that is not supposed to be in "
"the past is.", fault::CODE_TYPE));
break;
}
return timeValue;
}
string
paramList::getString(unsigned int const paramNumber) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
if (this->paramVector[paramNumber].type() != value::TYPE_STRING)
throw(fault("Parameter that is supposed to be a string is not",
fault::CODE_TYPE));
return static_cast<string>(value_string(this->paramVector[paramNumber]));
}
std::vector<unsigned char>
paramList::getBytestring(unsigned int const paramNumber) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]);
if (paramP->type() != value::TYPE_BYTESTRING)
throw(fault("Parameter that is supposed to be a byte string is not",
fault::CODE_TYPE));
return value_bytestring(*paramP).vectorUcharValue();
}
std::vector<xmlrpc_c::value>
paramList::getArray(unsigned int const paramNumber,
unsigned int const minSize,
unsigned int const maxSize) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]);
if (paramP->type() != value::TYPE_ARRAY)
throw(fault("Parameter that is supposed to be an array is not",
fault::CODE_TYPE));
xmlrpc_c::value_array const arrayValue(*paramP);
if (arrayValue.size() < minSize)
throw(fault("Array parameter has too few elements",
fault::CODE_TYPE));
if (arrayValue.size() > maxSize)
throw(fault("Array parameter has too many elements",
fault::CODE_TYPE));
return value_array(*paramP).vectorValueValue();
}
std::map<string, xmlrpc_c::value>
paramList::getStruct(unsigned int const paramNumber) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]);
if (paramP->type() != value::TYPE_STRUCT)
throw(fault("Parameter that is supposed to be a structure is not",
fault::CODE_TYPE));
return static_cast<std::map<string, xmlrpc_c::value> >(
value_struct(*paramP));
}
void
paramList::getNil(unsigned int const paramNumber) const {
if (paramNumber >= this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
if (this->paramVector[paramNumber].type() != value::TYPE_NIL)
throw(fault("Parameter that is supposed to be nil is not",
fault::CODE_TYPE));
}
void
paramList::verifyEnd(unsigned int const paramNumber) const {
if (paramNumber < this->paramVector.size())
throw(fault("Too many parameters", fault::CODE_TYPE));
if (paramNumber > this->paramVector.size())
throw(fault("Not enough parameters", fault::CODE_TYPE));
}
} // namespace

View File

@@ -0,0 +1,341 @@
#include <string>
#include <memory>
#include <algorithm>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/girmem.hpp"
using girmem::autoObject;
using girmem::autoObjectPtr;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base.hpp"
#include "xmlrpc-c/registry.hpp"
using namespace std;
using namespace xmlrpc_c;
namespace xmlrpc_c {
method::method() :
_signature("?"),
_help("No help is available for this method")
{};
method *
method::self() {
return this;
}
method::~method() {}
methodPtr::methodPtr(method * const methodP) {
this->instantiate(methodP);
}
method *
methodPtr::operator->() const {
autoObject * const p(this->objectP);
return dynamic_cast<method *>(p);
}
defaultMethod::~defaultMethod() {}
defaultMethodPtr::defaultMethodPtr() {}
defaultMethodPtr::defaultMethodPtr(defaultMethod * const methodP) {
this->instantiate(methodP);
}
defaultMethod *
defaultMethodPtr::operator->() const {
autoObject * const p(this->objectP);
return dynamic_cast<defaultMethod *>(p);
}
defaultMethod *
defaultMethod::self() {
return this;
}
registry::registry() {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->c_registryP = xmlrpc_registry_new(&env);
if (env.fault_occurred)
throw(error(env.fault_string));
}
registry::~registry(void) {
xmlrpc_registry_free(this->c_registryP);
}
static xmlrpc_c::paramList
pListFromXmlrpcArray(xmlrpc_value * const arrayP) {
/*----------------------------------------------------------------------------
Convert an XML-RPC array in C (not C++) form to a parameter list object
that can be passed to a method execute method.
This is glue code to allow us to hook up C++ Xmlrpc-c code to
C Xmlrpc-c code.
-----------------------------------------------------------------------------*/
xmlrpc_env env;
xmlrpc_env_init(&env);
XMLRPC_ASSERT_ARRAY_OK(arrayP);
unsigned int const arraySize = xmlrpc_array_size(&env, arrayP);
xmlrpc_c::paramList paramList(arraySize);
for (unsigned int i = 0; i < arraySize; ++i) {
xmlrpc_value * arrayItemP;
xmlrpc_array_read_item(&env, arrayP, i, &arrayItemP);
paramList.add(xmlrpc_c::value(arrayItemP));
xmlrpc_DECREF(arrayItemP);
}
return paramList;
}
static xmlrpc_value *
c_executeMethod(xmlrpc_env * const envP,
xmlrpc_value * const paramArrayP,
void * const methodPtr) {
/*----------------------------------------------------------------------------
This is a function designed to be called via a C registry to
execute an XML-RPC method, but use a C++ method object to do the
work. You register this function as the method function and a
pointer to the C++ method object as the method data in the C
registry.
If we had a pure C++ registry, this would be unnecessary.
Since we can't throw an error back to the C code, we catch anything
the XML-RPC method's execute() method throws, and any error we
encounter in processing the result it returns, and turn it into an
XML-RPC method failure. This will cause a leak if the execute()
method actually created a result, since it will not get destroyed.
-----------------------------------------------------------------------------*/
xmlrpc_c::method * const methodP =
static_cast<xmlrpc_c::method *>(methodPtr);
xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP));
xmlrpc_value * retval;
try {
xmlrpc_c::value result;
try {
methodP->execute(paramList, &result);
} catch (xmlrpc_c::fault caughtFault) {
xmlrpc_env_set_fault(envP, caughtFault.getCode(),
caughtFault.getDescription().c_str());
} catch (girerr::error caughtError) {
xmlrpc_env_set_fault(envP, 0, caughtError.what());
}
if (envP->fault_occurred)
retval = NULL;
else
retval = result.cValue();
} catch (...) {
xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
"Unexpected error executing the code for this "
"particular method, detected by the Xmlrpc-c "
"method registry code. The method did not "
"fail; rather, it did not complete at all.");
retval = NULL;
}
return retval;
}
static xmlrpc_value *
c_executeDefaultMethod(xmlrpc_env * const envP,
const char * const , // host
const char * const methodName,
xmlrpc_value * const paramArrayP,
void * const methodPtr) {
/*----------------------------------------------------------------------------
This is a function designed to be called via a C registry to
execute an XML-RPC method, but use a C++ method object to do the
work. You register this function as the default method function and a
pointer to the C++ default method object as the method data in the C
registry.
If we had a pure C++ registry, this would be unnecessary.
Since we can't throw an error back to the C code, we catch anything
the XML-RPC method's execute() method throws, and any error we
encounter in processing the result it returns, and turn it into an
XML-RPC method failure. This will cause a leak if the execute()
method actually created a result, since it will not get destroyed.
-----------------------------------------------------------------------------*/
xmlrpc_c::defaultMethod * const methodP =
static_cast<xmlrpc_c::defaultMethod *>(methodPtr);
xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP));
xmlrpc_value * retval;
try {
xmlrpc_c::value result;
try {
methodP->execute(methodName, paramList, &result);
} catch (xmlrpc_c::fault caughtFault) {
xmlrpc_env_set_fault(envP, caughtFault.getCode(),
caughtFault.getDescription().c_str());
} catch (girerr::error caughtError) {
xmlrpc_env_set_fault(envP, 0, caughtError.what());
}
if (envP->fault_occurred)
retval = NULL;
else
retval = result.cValue();
} catch (...) {
xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR,
"Unexpected error executing the default "
"method code, detected by the Xmlrpc-c "
"method registry code. The method did not "
"fail; rather, it did not complete at all.");
retval = NULL;
}
return retval;
}
void
registry::addMethod(string const name,
xmlrpc_c::methodPtr const methodPtr) {
this->methodList.push_back(methodPtr);
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_c::method * const methodP(methodPtr->self());
xmlrpc_registry_add_method_w_doc(
&env, this->c_registryP, NULL,
name.c_str(), &c_executeMethod,
(void*) methodP,
methodP->signature().c_str(), methodP->help().c_str());
if (env.fault_occurred)
throw(error(env.fault_string));
}
void
registry::setDefaultMethod(defaultMethodPtr const methodPtr) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->defaultMethodP = methodPtr;
xmlrpc_c::defaultMethod * const methodP(methodPtr->self());
xmlrpc_registry_set_default_method(
&env, this->c_registryP, &c_executeDefaultMethod, (void*) methodP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
void
registry::disableIntrospection() {
xmlrpc_registry_disable_introspection(this->c_registryP);
}
void
registry::processCall(string const& callXml,
string * const responseXmlP) const {
/*----------------------------------------------------------------------------
Process an XML-RPC call whose XML is 'callXml'.
Return the response XML as *responseXmlP.
If we are unable to execute the call, we throw an error. But if
the call executes and the method merely fails in an XML-RPC sense, we
don't. In that case, *responseXmlP indicates the failure.
-----------------------------------------------------------------------------*/
xmlrpc_env env;
xmlrpc_mem_block * output;
xmlrpc_env_init(&env);
// For the pure C++ version, this will have to parse 'callXml'
// into a method name and parameters, look up the method name in
// the registry, call the method's execute() method, then marshall
// the result into XML and return it as *responseXmlP. It will
// also have to execute system methods (e.g. introspection)
// itself. This will be more or less like what
// xmlrpc_registry_process_call() does.
output = xmlrpc_registry_process_call(
&env, this->c_registryP, NULL, callXml.c_str(), callXml.length());
if (env.fault_occurred)
throw(error(env.fault_string));
*responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, output),
XMLRPC_MEMBLOCK_SIZE(char, output));
xmlrpc_mem_block_free(output);
}
xmlrpc_registry *
registry::c_registry() const {
return this->c_registryP;
}
} // namespace

View File

@@ -0,0 +1,196 @@
#include <cassert>
#include <string>
#include <memory>
#include <signal.h>
#include <sys/wait.h>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base.hpp"
#include "xmlrpc-c/server_abyss.h"
#include "xmlrpc-c/registry.hpp"
#include "xmlrpc-c/server_abyss.hpp"
using namespace std;
using namespace xmlrpc_c;
namespace xmlrpc_c {
serverAbyss::serverAbyss(
xmlrpc_c::registry const& registry,
unsigned int const portNumber,
string const& logFileName,
unsigned int const keepaliveTimeout,
unsigned int const keepaliveMaxConn,
unsigned int const timeout,
bool const dontAdvertise) {
this->registryP = &registry;
this->logFileName = logFileName;
this->keepaliveTimeout = keepaliveTimeout;
this->keepaliveMaxConn = keepaliveMaxConn;
this->timeout = timeout;
this->dontAdvertise = dontAdvertise;
if (portNumber > 0xffff)
throw(error("Port number exceeds the maximum possible port number "
"(65535)"));
else {
this->portNumber = portNumber;
}
}
serverAbyss::~serverAbyss() {
}
namespace {
static void
sigterm(int const sig) {
TraceExit("Signal %d received. Exiting...\n",sig);
}
static void
sigchld(int const sig) {
/*----------------------------------------------------------------------------
This is a signal handler for a SIGCHLD signal (which informs us that
one of our child processes has terminated).
We respond by reaping the zombie process.
Implementation note: In some systems, just setting the signal handler
to SIG_IGN (ignore signal) does this. In others, it doesn't.
-----------------------------------------------------------------------------*/
#ifndef _WIN32
/* Reap zombie children until there aren't any more. */
bool zombiesExist;
bool error;
assert(sig == SIGCHLD);
zombiesExist = true; // initial assumption
error = false; // no error yet
while (zombiesExist && !error) {
int status;
pid_t const pid = waitpid((pid_t) -1, &status, WNOHANG);
if (pid == 0)
zombiesExist = false;
else if (pid < 0) {
/* because of ptrace */
if (errno == EINTR) {
// This is OK - it's a ptrace notification
} else
error = true;
}
}
#endif /* _WIN32 */
}
void
setupSignalHandlers(void) {
#ifndef _WIN32
struct sigaction mysigaction;
sigemptyset(&mysigaction.sa_mask);
mysigaction.sa_flags = 0;
/* These signals abort the program, with tracing */
mysigaction.sa_handler = sigterm;
sigaction(SIGTERM, &mysigaction, NULL);
sigaction(SIGINT, &mysigaction, NULL);
sigaction(SIGHUP, &mysigaction, NULL);
sigaction(SIGUSR1, &mysigaction, NULL);
/* This signal indicates connection closed in the middle */
mysigaction.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &mysigaction, NULL);
/* This signal indicates a child process (request handler) has died */
mysigaction.sa_handler = sigchld;
sigaction(SIGCHLD, &mysigaction, NULL);
#endif
}
static void
setAdditionalServerParms(
unsigned int const keepaliveTimeout,
unsigned int const keepaliveMaxConn,
unsigned int const timeout,
bool const dontAdvertise,
TServer * const srvP) {
/* The following ought to be parameters on ServerCreate(), but it
looks like plugging them straight into the TServer structure is
the only way to set them.
*/
if (keepaliveTimeout > 0)
srvP->keepalivetimeout = keepaliveTimeout;
if (keepaliveMaxConn > 0)
srvP->keepalivemaxconn = keepaliveMaxConn;
if (timeout > 0)
srvP->timeout = timeout;
srvP->advertise = !dontAdvertise;
}
} // namespace
void
serverAbyss::run() {
xmlrpc_env env;
xmlrpc_env_init(&env);
DateInit();
MIMETypeInit();
TServer srv;
const char * const logfileArg(this->logFileName.length() == 0 ?
NULL : this->logFileName.c_str());
ServerCreate(&srv, "XmlRpcServer", this->portNumber,
DEFAULT_DOCS, logfileArg);
setAdditionalServerParms(
this->keepaliveTimeout, this->keepaliveMaxConn, this->timeout,
this->dontAdvertise, &srv);
xmlrpc_c::server_abyss_set_handlers(&srv, *this->registryP);
ServerInit(&srv);
setupSignalHandlers();
ServerRun(&srv);
/* We can't exist here because ServerRun doesn't return */
assert(false);
}
void
server_abyss_set_handlers(TServer * const srvP,
xmlrpc_c::registry const& registry) {
xmlrpc_server_abyss_set_handlers(srvP, registry.c_registry());
}
} // namespace

View File

@@ -0,0 +1,807 @@
/*****************************************************************************
xmlrpc_value.cpp
******************************************************************************
This module provides services for dealwith XML-RPC values. Each type
of XML-RPC value is a C++ class. An object represents a particular
XML-RPC value.
Everything is based on the C services in libxmlrpc.
We could make things more efficient by using the internal interfaces
via xmlrpc_int.h. We could make them even more efficient by dumping
libxmlrpc altogether for some or all of these services.
An xmlrpc_c::value object is really just a handle for a C xmlrpc_value
object. You're not supposed to make a pointer to an xmlrpc_c::value
object, but rather copy the object around.
Because the C xmlrpc_value object does reference counting, it
disappears automatically when the last handle does. To go pure C++,
we'd have to have a C++ object for the value itself and a separate
handle object, like Boost's shared_ptr<>.
The C++ is designed so that the user never sees the C interface at
all. Unfortunately, the user can see it if he wants because some
class members had to be declared public so that other components of
the library could see them, but the user is not supposed to access
those members.
*****************************************************************************/
#include <string>
#include <vector>
#include <time.h>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base_int.h"
#include "xmlrpc-c/base.hpp"
using namespace std;
namespace {
class cDatetimeValueWrapper {
public:
xmlrpc_value * valueP;
cDatetimeValueWrapper(time_t const cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_datetime_new_sec(&env, cppvalue);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cDatetimeValueWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
class cStringWrapper {
public:
const char * str;
size_t length;
cStringWrapper(xmlrpc_value * valueP) {
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_read_string_lp(&env, valueP, &length, &str);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cStringWrapper() {
free((char*)str);
}
};
} // namespace
namespace xmlrpc_c {
value::value() {
this->cValueP = NULL;
}
value::value(xmlrpc_value * const valueP) { // default constructor
this->instantiate(valueP);
}
value::value(xmlrpc_c::value const& value) { // copy constructor
this->cValueP = value.cValue();
}
xmlrpc_c::value&
value::operator=(xmlrpc_c::value const& value) {
if (this->cValueP != NULL)
throw(error("Assigning to already instantiated xmlrpc_c::value"));
this->cValueP = value.cValue();
return *this; // The result of the (a = b) expression
}
value::~value() {
if (this->cValueP) {
xmlrpc_DECREF(this->cValueP);
}
}
void
value::instantiate(xmlrpc_value * const valueP) {
xmlrpc_INCREF(valueP);
this->cValueP = valueP;
}
xmlrpc_value *
value::cValue() const {
if (this->cValueP) {
xmlrpc_INCREF(this->cValueP); // For Caller
}
return this->cValueP;
}
void
value::appendToCArray(xmlrpc_value * const arrayP) const {
/*----------------------------------------------------------------------------
Append this value to the C array 'arrayP'.
----------------------------------------------------------------------------*/
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_array_append_item(&env, arrayP, this->cValueP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
void
value::addToCStruct(xmlrpc_value * const structP,
string const key) const {
/*----------------------------------------------------------------------------
Add this value to the C array 'arrayP' with key 'key'.
----------------------------------------------------------------------------*/
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_struct_set_value_n(&env, structP,
key.c_str(), key.length(),
this->cValueP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
value::type_t
value::type() const {
/* You'd think we could just cast from xmlrpc_type to
value:type_t, but Gcc warns if we do that. So we have to do this
even messier union nonsense.
*/
union {
xmlrpc_type x;
value::type_t y;
} u;
u.x = xmlrpc_value_type(this->cValueP);
return u.y;
}
value_int::value_int(int const cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(int const cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_int_new(&env, cppvalue);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper(cppvalue);
this->instantiate(wrapper.valueP);
}
value_int::value_int(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_INT)
throw(error("Not integer type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_int::operator int() const {
int retval;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_read_int(&env, this->cValueP, &retval);
if (env.fault_occurred)
throw(error(env.fault_string));
return retval;
}
value_double::value_double(double const cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(double const cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_double_new(&env, cppvalue);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
this->instantiate(cWrapper(cppvalue).valueP);
}
value_double::value_double(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_DOUBLE)
throw(error("Not double type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_double::operator double() const {
double retval;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_read_double(&env, this->cValueP, &retval);
if (env.fault_occurred)
throw(error(env.fault_string));
return retval;
}
value_boolean::value_boolean(bool const cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(xmlrpc_bool const cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_bool_new(&env, cppvalue);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper(cppvalue);
this->instantiate(wrapper.valueP);
}
value_boolean::operator bool() const {
xmlrpc_bool retval;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_read_bool(&env, this->cValueP, &retval);
if (env.fault_occurred)
throw(error(env.fault_string));
return (bool)retval;
}
value_boolean::value_boolean(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_BOOLEAN)
throw(error("Not boolean type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_datetime::value_datetime(string const cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(string const cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_datetime_new_str(&env, cppvalue.c_str());
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper(cppvalue);
this->instantiate(wrapper.valueP);
}
value_datetime::value_datetime(time_t const cppvalue) {
cDatetimeValueWrapper wrapper(cppvalue);
this->instantiate(wrapper.valueP);
}
value_datetime::value_datetime(struct timeval const& cppvalue) {
cDatetimeValueWrapper wrapper(cppvalue.tv_sec);
this->instantiate(wrapper.valueP);
}
value_datetime::value_datetime(struct timespec const& cppvalue) {
cDatetimeValueWrapper wrapper(cppvalue.tv_sec);
this->instantiate(wrapper.valueP);
}
value_datetime::value_datetime(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_DATETIME)
throw(error("Not datetime type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_datetime::operator time_t() const {
time_t retval;
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_read_datetime_sec(&env, this->cValueP, &retval);
if (env.fault_occurred)
throw(error(env.fault_string));
return retval;
}
value_string::value_string(string const& cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(string const cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_string_new(&env, cppvalue.c_str());
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper(cppvalue);
this->instantiate(wrapper.valueP);
}
value_string::value_string(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_STRING)
throw(error("Not string type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_string::operator string() const {
xmlrpc_env env;
xmlrpc_env_init(&env);
cStringWrapper adapter(this->cValueP);
return string(adapter.str, adapter.length);
}
value_bytestring::value_bytestring(
vector<unsigned char> const& cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(vector<unsigned char> const& cppvalue) {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP =
xmlrpc_base64_new(&env, cppvalue.size(), &cppvalue[0]);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper(cppvalue);
this->instantiate(wrapper.valueP);
}
vector<unsigned char>
value_bytestring::vectorUcharValue() const {
class cWrapper {
public:
const unsigned char * contents;
size_t length;
cWrapper(xmlrpc_value * const valueP) {
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_read_base64(&env, valueP, &length, &contents);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
free((void*)contents);
}
};
cWrapper wrapper(this->cValueP);
return vector<unsigned char>(&wrapper.contents[0],
&wrapper.contents[wrapper.length]);
}
size_t
value_bytestring::length() const {
xmlrpc_env env;
xmlrpc_env_init(&env);
size_t length;
xmlrpc_read_base64_size(&env, this->cValueP, &length);
if (env.fault_occurred)
throw(error(env.fault_string));
return length;
}
value_bytestring::value_bytestring(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_BYTESTRING)
throw(error("Not byte string type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_array::value_array(vector<xmlrpc_c::value> const& cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper() {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_array_new(&env);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper;
vector<xmlrpc_c::value>::const_iterator i;
for (i = cppvalue.begin(); i != cppvalue.end(); ++i)
i->appendToCArray(wrapper.valueP);
this->instantiate(wrapper.valueP);
}
value_array::value_array(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_ARRAY)
throw(error("Not array type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
vector<xmlrpc_c::value>
value_array::vectorValueValue() const {
xmlrpc_env env;
xmlrpc_env_init(&env);
unsigned int arraySize;
arraySize = xmlrpc_array_size(&env, this->cValueP);
if (env.fault_occurred)
throw(error(env.fault_string));
vector<xmlrpc_c::value> retval(arraySize);
for (unsigned int i = 0; i < arraySize; ++i) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper(xmlrpc_value * const arrayP,
unsigned int const index) {
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_array_read_item(&env, arrayP, index, &valueP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(valueP);
}
};
cWrapper wrapper(this->cValueP, i);
retval[i].instantiate(wrapper.valueP);
}
return retval;
}
size_t
value_array::size() const {
xmlrpc_env env;
xmlrpc_env_init(&env);
unsigned int arraySize;
arraySize = xmlrpc_array_size(&env, this->cValueP);
if (env.fault_occurred)
throw(error(env.fault_string));
return arraySize;
}
value_struct::value_struct(
map<string, xmlrpc_c::value> const &cppvalue) {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper() {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_struct_new(&env);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper;
map<string, xmlrpc_c::value>::const_iterator i;
for (i = cppvalue.begin(); i != cppvalue.end(); ++i) {
xmlrpc_c::value mapvalue(i->second);
string mapkey(i->first);
mapvalue.addToCStruct(wrapper.valueP, mapkey);
}
this->instantiate(wrapper.valueP);
}
value_struct::value_struct(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_STRUCT)
throw(error("Not struct type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
value_struct::operator map<string, xmlrpc_c::value>() const {
xmlrpc_env env;
xmlrpc_env_init(&env);
unsigned int structSize;
structSize = xmlrpc_struct_size(&env, this->cValueP);
if (env.fault_occurred)
throw(error(env.fault_string));
map<string, xmlrpc_c::value> retval;
for (unsigned int i = 0; i < structSize; ++i) {
class cMemberWrapper {
public:
xmlrpc_value * keyP;
xmlrpc_value * valueP;
cMemberWrapper(xmlrpc_value * const structP,
unsigned int const index) {
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_struct_read_member(&env, structP, index,
&keyP, &valueP);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cMemberWrapper() {
xmlrpc_DECREF(keyP);
xmlrpc_DECREF(valueP);
}
};
cMemberWrapper memberWrapper(this->cValueP, i);
cStringWrapper keyWrapper(memberWrapper.keyP);
string const key(keyWrapper.str, keyWrapper.length);
retval[key] = xmlrpc_c::value(memberWrapper.valueP);
}
return retval;
}
value_nil::value_nil() {
class cWrapper {
public:
xmlrpc_value * valueP;
cWrapper() {
xmlrpc_env env;
xmlrpc_env_init(&env);
this->valueP = xmlrpc_nil_new(&env);
if (env.fault_occurred)
throw(error(env.fault_string));
}
~cWrapper() {
xmlrpc_DECREF(this->valueP);
}
};
cWrapper wrapper;
this->instantiate(wrapper.valueP);
}
value_nil::value_nil(xmlrpc_c::value const baseValue) {
if (baseValue.type() != xmlrpc_c::value::TYPE_NIL)
throw(error("Not nil type. See type() method"));
else {
this->instantiate(baseValue.cValueP);
}
}
} // namespace

View File

@@ -0,0 +1,166 @@
#include <string>
#include "xmlrpc-c/girerr.hpp"
using girerr::error;
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/base_int.h"
#include "xmlrpc-c/base.hpp"
#include "xmlrpc-c/xml.hpp"
using namespace std;
using namespace xmlrpc_c;
namespace {
class cValueWrapper {
/*----------------------------------------------------------------------------
Use an object of this class to set up to remove a reference to an
xmlrpc_value object (a C object with manual reference management)
at then end of a scope -- even if the scope ends with a throw.
-----------------------------------------------------------------------------*/
public:
xmlrpc_value * valueP;
cValueWrapper(xmlrpc_value * valueP) : valueP(valueP) {}
~cValueWrapper() { xmlrpc_DECREF(valueP); }
};
xmlrpc_value *
cArrayFromParamList(paramList const& paramList) {
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_value * paramArrayP;
paramArrayP = xmlrpc_array_new(&env);
if (!env.fault_occurred) {
for (unsigned int i = 0;
i < paramList.size() && !env.fault_occurred;
++i) {
cValueWrapper const param(paramList[i].cValue());
xmlrpc_array_append_item(&env, paramArrayP, param.valueP);
}
}
if (env.fault_occurred) {
xmlrpc_DECREF(paramArrayP);
throw(error(env.fault_string));
}
return paramArrayP;
}
} // namespace
namespace xmlrpc_c {
namespace xml {
void
generateCall(string const& methodName,
paramList const& paramList,
string * const callXmlP) {
/*----------------------------------------------------------------------------
Generate the XML for an XML-RPC call, given a method name and parameter
list.
-----------------------------------------------------------------------------*/
class memblockWrapper {
xmlrpc_mem_block * const memblockP;
public:
memblockWrapper(xmlrpc_mem_block * const memblockP) :
memblockP(memblockP) {}
~memblockWrapper() {
XMLRPC_MEMBLOCK_FREE(char, memblockP);
}
};
xmlrpc_mem_block * callXmlMP;
xmlrpc_env env;
xmlrpc_env_init(&env);
callXmlMP = XMLRPC_MEMBLOCK_NEW(char, &env, 0);
if (!env.fault_occurred) {
memblockWrapper callXmlHolder(callXmlMP);
// Makes callXmlMP get freed at end of scope
xmlrpc_value * const paramArrayP(cArrayFromParamList(paramList));
xmlrpc_serialize_call(&env, callXmlMP, methodName.c_str(),
paramArrayP);
*callXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, callXmlMP),
XMLRPC_MEMBLOCK_SIZE(char, callXmlMP));
xmlrpc_DECREF(paramArrayP);
}
if (env.fault_occurred)
throw(error(env.fault_string));
}
void
parseResponse(string const& responseXml,
rpcOutcome * const outcomeP) {
/*----------------------------------------------------------------------------
Parse the XML for an XML-RPC response into an XML-RPC result value.
-----------------------------------------------------------------------------*/
xmlrpc_env env;
xmlrpc_env_init(&env);
xmlrpc_value * c_resultP;
c_resultP =
xmlrpc_parse_response(&env, responseXml.c_str(), responseXml.size());
/* Unfortunately, xmlrpc_parse_response() does not distinguish between
unparseable XML and XML that cleanly indicates an RPC failure or
other failure on the server end. We'll fix that some day, but for
now, we just assume any failure is an XML-RPC RPC failure.
*/
if (env.fault_occurred)
*outcomeP =
rpcOutcome(fault(env.fault_string,
static_cast<fault::code_t>(env.fault_code)));
else {
*outcomeP = rpcOutcome(value(c_resultP));
xmlrpc_DECREF(c_resultP);
}
}
void
parseSuccessfulResponse(string const& responseXml,
value * const resultP) {
/*----------------------------------------------------------------------------
Same as parseResponse(), but expects the response to indicate success;
throws an error if it doesn't.
-----------------------------------------------------------------------------*/
rpcOutcome outcome;
parseResponse(responseXml, &outcome);
if (!outcome.succeeded())
throw(error("RPC failed. " + outcome.getFault().getDescription()));
*resultP = outcome.getResult();
}
void
trace(string const& label,
string const& xml) {
xmlrpc_traceXml(label.c_str(), xml.c_str(), xml.size());
}
}} // namespace