Writing Client - adedov/libiqxmlrpc GitHub Wiki

Quick Start

Lets start with simple example that will demonstrate basic XML-RPC client. This client example designed to be compatible with server sample.

    #include <iostream>
    #include <libiqxmlrpc/libiqxmlrpc.h>
    #include <libiqxmlrpc/client.h>
    #include <libiqxmlrpc/http_client.h>
    
    int main()
    {
      using namespace iqxmlrpc;
    
      // 1: Create a client object
      Client<Http_client_connection> client(iqnet::Inet_addr(3344));
    
      // 2: Fill method parameters
      Param_list pl;
      pl.push_back(Struct());
      pl[0].insert("var1", 1);
      pl[0].insert("var2", "value");
    
      // 3: Call a remote method
      Response r = client.execute("echo", pl);
    
      // 4: Process method output
      assert(r.value()["var1"].get_int() == 1);
      assert(r.value()["var2"].get_string() == "value");
    }

Comments with figures state different phases of a process of writing client code with Libiqxmlrpc. Here they are:

  • Create and configure client object
  • Make remote invocations
  • Construct a set of parameters
  • Call a remote method
  • Treat method output

A following sections say more about those phases.

Setting Up a Client

An abstract base class iqxmlrpc::Client_base provides interface for client configuration and execution of remote methods. In summary, this interface allows one to:

  • Configure client connections:
  • Specify Proxy Settings
  • Specify Connection Timeout
  • Specify Keep-alive Flag
  • Manage Client Authorization
  • Method Execution

Create Client

However, the first thing a developer need, is to create an instance of Client_base. Concrete sub-classes of Client_base take care of a transport used to communicate remote service. There is template class iqxmlrpc::Client that should be used for instantiating Client_base children. User must specify appropriate TRANSPORT parameter for his situation, depending on transport required (HTTP or HTTPS).

Possible options are:

  • iqxmlrpc::Http_client_connection
  • iqxmlrpc::Https_client_connection

In a common case client creation code will look like a following:

    iqxmlrpc::Client<TRANSPORT> client( iqnet::Inet_addr(host, port), "/RPC2" );

An /RPC2 string is an URI that can be configured by a owner of a remote service.

One can fearlessly substitute TRANSPORT template argument with Http_client_connection in an example above. However, enabling HTTPS needs some additional magic from a developer. I.e. one must initialize SSL subsystem before creating any SSL connection:

    #include <libiqxmlrpc/libiqxmlrpc.h>
    #include <libiqxmlrpc/https_client.h>
    
    using namespace iqxmlrpc;
    
    Client_base*
    create_https_client(iqnet::Inet_addr addr, const std::string& uri)
    {
    	// Initialize SSL subsystem
    	iqnet::ssl::ctx = iqnet::ssl::Ctx::client_only();
    
    	return new Client<Https_client_connection>(addr, uri);
    }

Configure Client Connections

Specify Proxy Settings

Client_base::set_proxy : This method allows one set an HTTP proxy host for all client's outgoing connections.

    Client<Http_client_connection> client(Inet_addr("host.com", 8080));
    	client.set_proxy(Inet_addr("my.proxy.com", 80));

Specify Connection Timeout

Client_base::set_timeout : This method sets connection timeout in seconds. A negative value means no timeout. Library throws iqxmlrpc::Client_timeout exception during processing remote call in case when time is out.

    void timed_call(Client_base& client, int timeout)
    {
    	client.set_timeout(timeout);
    
    	try {
    		Response r = client.execute("foo", Value());
    		// work with r ...
    
    	} catch(const Client_timeout&) {
    		// handle connection timeout
    	}
    }

Specify Keep-alive Flag

Client_base::set_keep_alive : This method manages HTTP keep-alive facility on a client connection. If one enables this flag and remote server supports this facility then all subsequent method execution request will go through the same open connection.

    void banch_of_requests(Client_base& client)
    {
    	// Ask server to not close connection after response
    	client.set_keep_alive(true);
    
    	client.execute("foo", Value());
    
    	// Hope, the same connection.
    	// Depending on server implementation.
    	client.execute("bar", Value());
    }

Manage Client Authorization

Client_base::set_authinfo : This method sets user/password pair to pass through HTTP authentication mechanism.

    client.set_authinfo("admin", "12345");

Note: Though library allows use set_authinfo with plain a HTTP connections, one should not rely on it because in this case your credential information may become available to traffic sniffers.

Method Execution

Calling Remote Method

XML-RPC standard allows transfer a number of input parameters to a remote procedure. Actually, quite often XML-RPC APIs take in account only first of them, and require transferring parameters in a key-value form. Just because this method is much more convenient and reflects to a dynamic nature of XML-RPC it-self.

Library provides comfortable way for both approaches. The iqxmlrpc::Client provides two overloaded interface for calling remote methods:

    namespace iqxmlrpc {
    
    typedef std::vector<Value> Param_list;
    
    class Client {
    public:
    	// ...
    	Response execute( const std::string& method, const Param_list& );
    	Response execute( const std::string& method, const Value& );
    };
    
    } // namespace iqxmlrpc

Both methods accept name of calling method as a first parameter. A former allows transfer an array of input parameters (as the standard suggests).

A second one puts specified value into first element of array of parameters and just calls a first one.

Processing Responses

An XML-RPC response may be of two types: method output, and failure report. Objects of iqxmlrpc::Response class serve a destination for result of a remote call and may hold either type of response.

A Response::value method gives user access to a received result. And Response::is_fault allows user check if received XML-RPC packet contained failure notice. If user try access response value with value method and an object is actually containing an XML-RPC failure notice then exception that contain all information about failure would be thrown. This behavior gives user ability write a code in optimistic manner.

Response::fault_code and Response::fault_string methods gives an alternative way to retrieve information about failure.

Note: Please note that Response objects may contain only XML-RPC failures. Failures form a network layer or some HTTP issues are always exceptions.

    std::string get_name_of_object(Client_base& client, int object_id)
    {
    	try {
    		Response r = client("get_object_name", object_id);
    		return r.value().get_string();
    
    	} catch (const Client_timeout&) {
    		std::cerr << "Timeout" << std::endl;
    		exit(1);
    
    	} catch (const Exception& e) {
    		std::cerr
    		    << "XML-RPC error "
    		    << e.code() << ": " << e.what()
    		    << std::endl;
    		exit(2);
    	}
    }
⚠️ **GitHub.com Fallback** ⚠️