| // -*- C++ -*- <-- an Emacs control |
| |
| // Copyright information is at the bottom of the file. |
| |
| //========================================================================= |
| // XML-RPC C++ API |
| //========================================================================= |
| |
| |
| #ifndef _XMLRPCCPP_H_ |
| #define _XMLRPCCPP_H_ 1 |
| |
| // The C++ standard says we should either include <string.h> (which gets |
| // us the wrong header), or say 'using namespace std;' (which doesn't |
| // work with our version of g++). So this header name is technically wrong. |
| // Tell me what your compiler does; I can provide some autoconf magic to the |
| // Right Thing on most platforms. |
| // |
| // 2004.12.22 Bryan: This looks like a problem with whatever g++ he was |
| // using, so if anything, the special case should be for that. In any case, |
| // we've already added using namespace std to other files, without knowing |
| // there was an issue, so I'm just going to do the "using namespace" |
| // unconditionally and see who complains. If there are complaints, we can |
| // improve the documentation here. |
| // |
| // Formerly, the "using namespace std" was under |
| // "#if defined(__GNUC__) && (__GNUC__ >= 3)". |
| |
| |
| #include <string> |
| |
| using namespace std; |
| |
| #include <xmlrpc_config.h> |
| #include <xmlrpc.h> |
| #include <xmlrpc_client.h> |
| #include <xmlrpc_server.h> |
| |
| #define XMLRPC_NO_ASSIGNMENT \ |
| XMLRPC_FATAL_ERROR("Assignment operator not available"); return *this; |
| |
| |
| //========================================================================= |
| // XmlRpcFault |
| //========================================================================= |
| // A C++ exception class representing an XML-RPC fault. |
| |
| class XmlRpcFault { |
| |
| private: |
| xmlrpc_env mFault; |
| |
| XmlRpcFault& operator= (const XmlRpcFault& f) |
| { (void) f; XMLRPC_NO_ASSIGNMENT } |
| |
| public: |
| XmlRpcFault (const XmlRpcFault &fault); |
| XmlRpcFault (const int faultCode, const string faultString); |
| XmlRpcFault (const xmlrpc_env *env); |
| ~XmlRpcFault (void); |
| |
| int getFaultCode (void) const; |
| string getFaultString (void) const; |
| xmlrpc_env *getFaultEnv (void); |
| }; |
| |
| inline int XmlRpcFault::getFaultCode (void) const { |
| return mFault.fault_code; |
| } |
| |
| inline xmlrpc_env *XmlRpcFault::getFaultEnv (void) { |
| return &mFault; |
| } |
| |
| |
| //========================================================================= |
| // XmlRpcEnv |
| //========================================================================= |
| // This class can be used to wrap xmlrpc_env object. Use it as follows: |
| // |
| // XmlRpcEnv env; |
| // xmlrpc_parse_value(env, v, "(i)", &i); |
| // env.throwIfFaultOccurred(); |
| |
| class XmlRpcEnv { |
| |
| private: |
| xmlrpc_env mEnv; |
| |
| void throwMe (void) const; |
| XmlRpcEnv& operator= (const XmlRpcEnv& e) |
| { (void) e; XMLRPC_NO_ASSIGNMENT } |
| |
| public: |
| XmlRpcEnv (const XmlRpcEnv &env); |
| XmlRpcEnv (void) { xmlrpc_env_init(&mEnv); } |
| ~XmlRpcEnv (void) { xmlrpc_env_clean(&mEnv); } |
| |
| bool faultOccurred (void) const { return mEnv.fault_occurred; }; |
| bool hasFaultOccurred (void) const { return faultOccurred(); }; |
| /* hasFaultOccurred() is for backward compatibility. |
| faultOccurred() is a superior name for this. |
| */ |
| XmlRpcFault getFault (void) const; |
| |
| void throwIfFaultOccurred (void) const; |
| |
| operator xmlrpc_env * (void) { return &mEnv; } |
| }; |
| |
| inline void XmlRpcEnv::throwIfFaultOccurred (void) const { |
| if (faultOccurred()) |
| throwMe(); |
| } |
| |
| |
| //========================================================================= |
| // XmlRpcValue |
| //========================================================================= |
| // An object in this class is an XML-RPC value. |
| // |
| // We have a complex structure to allow C code mixed in with C++ code |
| // which uses this class to refer to the same XML-RPC value object. |
| // This is especially important because there aren't proper C++ facilities |
| // for much of Xmlrpc-c; you have to use the C facilities even if you'd |
| // rather use proper C++. |
| // |
| // The XmlRpcValue object internally represents the value as an |
| // xmlrpc_value. It hold one reference to the xmlrpc_value. Users |
| // of XmlRpcValue never see that xmlrpc_value, but C code can. the |
| // C code might create the xmlrpc_value and then bind it to an XmlRpcValue, |
| // or it might get the xmlrpc_value handle from the XmlRpcValue. Finally, |
| // C code can simply use the XmlRpcValue where an xmlrpc_value handle is |
| // required and it gets converted automatically. |
| // |
| // So reference counting for the xmlrpc_value is quite a nightmare. |
| |
| class XmlRpcValue { |
| |
| private: |
| xmlrpc_value *mValue; |
| |
| public: |
| enum ReferenceBehavior { |
| MAKE_REFERENCE, |
| CONSUME_REFERENCE |
| }; |
| |
| typedef xmlrpc_int32 int32; |
| |
| XmlRpcValue (void); |
| XmlRpcValue (xmlrpc_value *value, |
| ReferenceBehavior behavior = MAKE_REFERENCE); |
| XmlRpcValue (const XmlRpcValue& value); |
| ~XmlRpcValue (void); |
| |
| XmlRpcValue& operator= (const XmlRpcValue& value); |
| |
| // Accessing the value's type (think of this as lightweight RTTI). |
| xmlrpc_type getType(void) const; |
| |
| // We don't supply an automatic conversion operator--you need to say |
| // whether you want to make or borrow this object's reference. |
| // XXX - Is it really OK for these to be const? |
| xmlrpc_value *makeReference (void) const; |
| xmlrpc_value *borrowReference (void) const; |
| |
| // Some static "constructor" functions. |
| static XmlRpcValue makeInt (const XmlRpcValue::int32 i); |
| static XmlRpcValue makeBool (const bool b); |
| static XmlRpcValue makeDouble (const double d); |
| static XmlRpcValue makeDateTime (const string& dateTime); |
| static XmlRpcValue makeString (const string& str); |
| static XmlRpcValue makeString (const char *const str); |
| static XmlRpcValue makeString (const char *const str, size_t len); |
| static XmlRpcValue makeArray (void); |
| static XmlRpcValue makeStruct (void); |
| static XmlRpcValue makeBase64 (const unsigned char *const data, |
| size_t len); |
| /* |
| // An interface to xmlrpc_build_value. |
| static XmlRpcValue buildValue (const char *const format, ...); |
| */ |
| |
| // Some functions to get the underlying data. |
| // These will throw an XmlRpcFault if the data is the wrong type. |
| XmlRpcValue::int32 getInt (void) const; |
| bool getBool (void) const; |
| double getDouble (void) const; |
| string getRawDateTime (void) const; |
| string getString (void) const; |
| XmlRpcValue getArray (void) const; |
| XmlRpcValue getStruct (void) const; |
| |
| // This returns an internal pointer which will become invalid when |
| // all references to the underlying value are destroyed. |
| void getBase64 (const unsigned char *& out_data, |
| size_t& out_len) const; |
| |
| /* |
| // An interface to xmlrpc_parse_value. |
| void parseValue (const char *const format, ...); |
| */ |
| |
| // Array functions. These will throw an XmlRpcFault if the value |
| // isn't an array. |
| size_t arraySize (void) const; |
| void arrayAppendItem (const XmlRpcValue& value); |
| XmlRpcValue arrayGetItem (int index) const; |
| |
| // Struct functions. These will throw an XmlRpcFault if the value |
| // isn't a struct. |
| size_t structSize (void) const; |
| bool structHasKey (const string& key) const; |
| XmlRpcValue structGetValue (const string& key) const; |
| void structSetValue (const string& key, const XmlRpcValue& value); |
| void structGetKeyAndValue (const int index, |
| string& out_key, |
| XmlRpcValue& out_value) const; |
| }; |
| |
| inline XmlRpcValue::XmlRpcValue (xmlrpc_value *value, |
| ReferenceBehavior behavior) |
| { |
| mValue = value; |
| |
| if (behavior == MAKE_REFERENCE) |
| xmlrpc_INCREF(value); |
| } |
| |
| inline XmlRpcValue::XmlRpcValue (const XmlRpcValue& value) { |
| mValue = value.mValue; |
| xmlrpc_INCREF(mValue); |
| } |
| |
| inline XmlRpcValue::~XmlRpcValue (void) { |
| xmlrpc_DECREF(mValue); |
| } |
| |
| inline XmlRpcValue& XmlRpcValue::operator= (const XmlRpcValue& value) { |
| // Must increment before we decrement, in case of assignment to self. |
| xmlrpc_INCREF(value.mValue); |
| xmlrpc_DECREF(mValue); |
| mValue = value.mValue; |
| return *this; |
| } |
| |
| inline xmlrpc_type XmlRpcValue::getType (void) const { |
| return xmlrpc_value_type(mValue); |
| } |
| |
| inline xmlrpc_value *XmlRpcValue::makeReference (void) const { |
| xmlrpc_INCREF(mValue); |
| return mValue; |
| } |
| |
| inline xmlrpc_value *XmlRpcValue::borrowReference (void) const { |
| return mValue; |
| } |
| |
| |
| //========================================================================= |
| // XmlRpcClient |
| //========================================================================= |
| |
| class XmlRpcClient { |
| |
| private: |
| string mServerUrl; |
| |
| public: |
| static void Initialize (string appname, string appversion); |
| static void Terminate (void); |
| |
| XmlRpcClient (const string& server_url) : mServerUrl(server_url) {} |
| ~XmlRpcClient (void) {} |
| |
| XmlRpcClient (const XmlRpcClient& client); |
| XmlRpcClient& operator= (const XmlRpcClient& client); |
| |
| XmlRpcValue call (string method_name, XmlRpcValue param_array); |
| void call_asynch (string method_name, |
| XmlRpcValue param_array, |
| xmlrpc_response_handler callback, |
| void* user_data); |
| void event_loop_asynch (unsigned long milliseconds); |
| }; |
| |
| inline void XmlRpcClient::call_asynch(string method_name, |
| XmlRpcValue param_array, |
| xmlrpc_response_handler callback, |
| void* user_data) |
| { |
| xmlrpc_client_call_asynch_params( |
| mServerUrl.c_str(), |
| method_name.c_str(), |
| callback, |
| user_data, |
| param_array.borrowReference()); |
| } |
| |
| inline void XmlRpcClient::event_loop_asynch(unsigned long milliseconds) |
| { |
| xmlrpc_client_event_loop_finish_asynch_timeout(milliseconds); |
| } |
| |
| |
| //========================================================================= |
| // XmlRpcClient Methods |
| //========================================================================= |
| // These are inline for now, so we don't need to screw with linker issues |
| // and build a separate client library. |
| |
| inline XmlRpcClient::XmlRpcClient (const XmlRpcClient& client) |
| : mServerUrl(client.mServerUrl) |
| { |
| } |
| |
| inline XmlRpcClient& XmlRpcClient::operator= (const XmlRpcClient& client) { |
| if (this != &client) |
| mServerUrl = client.mServerUrl; |
| return *this; |
| } |
| |
| inline void XmlRpcClient::Initialize (string appname, string appversion) { |
| xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, |
| appname.c_str(), |
| appversion.c_str()); |
| } |
| |
| inline void XmlRpcClient::Terminate (void) { |
| xmlrpc_client_cleanup(); |
| } |
| |
| inline XmlRpcValue XmlRpcClient::call (string method_name, |
| XmlRpcValue param_array) |
| { |
| XmlRpcEnv env; |
| xmlrpc_value *result = |
| xmlrpc_client_call_params(env, |
| mServerUrl.c_str(), |
| method_name.c_str(), |
| param_array.borrowReference()); |
| env.throwIfFaultOccurred(); |
| return XmlRpcValue(result, XmlRpcValue::CONSUME_REFERENCE); |
| } |
| |
| //========================================================================= |
| // XmlRpcGenSrv |
| //========================================================================= |
| |
| class XmlRpcGenSrv { |
| |
| private: |
| |
| xmlrpc_registry* mRegistry; |
| |
| xmlrpc_mem_block* alloc (XmlRpcEnv& env, const string& body) const; |
| |
| public: |
| |
| XmlRpcGenSrv (int flags); |
| ~XmlRpcGenSrv (void); |
| |
| xmlrpc_registry* getRegistry (void) const; |
| |
| XmlRpcGenSrv& addMethod (const string& name, |
| xmlrpc_method method, |
| void *data); |
| XmlRpcGenSrv& addMethod (const string& name, |
| xmlrpc_method method, |
| void* data, |
| const string& signature, |
| const string& help); |
| |
| string handle (const string& body) const; |
| }; |
| |
| inline XmlRpcGenSrv::XmlRpcGenSrv (int flags) { |
| |
| XmlRpcEnv env; |
| |
| if (flags == flags){}; |
| |
| mRegistry = xmlrpc_registry_new (env); |
| env.throwIfFaultOccurred(); |
| } |
| |
| inline XmlRpcGenSrv::~XmlRpcGenSrv (void) { |
| |
| xmlrpc_registry_free (mRegistry); |
| } |
| |
| inline xmlrpc_registry* XmlRpcGenSrv::getRegistry () const { |
| |
| return mRegistry; |
| } |
| |
| #undef XMLRPC_NO_ASSIGNMENT |
| |
| |
| // 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. |
| |
| |
| #endif /* _XMLRPCCPP_H_ */ |