nlib
exi/xml-rpc/xml-rpc.cpp

Sample of a front-end that processes an XML-RPC request and generates a response.

The body of the XML-RPC request is XML similar to the following.

<?xml version="1.0"?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>41</i4></value>
</param>
</params>
</methodCall>

By writing the XML in this way, it attempts to run the following procedure at certain timing:

examples.getStateName(41);

The application that receives the request parses the request, runs the appropriate function, and returns the return value. The response must also be sent back in XML format, and might look something like the following.

<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string>South Dakota</string></value>
</param>
</params>
</methodResponse>

This sample sends "South Dakota" as the return value.

It is just a single-threaded sample that implements code for easily generating and handling a XML-RPC request and response from C++. The use of binary XML provides a moderate reduction in overhead for the protocol used to exchange the otherwise verbose data.

The Japanese translation of the XML-RPC specifications can be found here. http://lowlife.jp/yasusii/stories/9.html

The source code of the sample is shown below.

/*--------------------------------------------------------------------------------*
Project: CrossRoad
Copyright (C)Nintendo All rights reserved.
These coded instructions, statements, and computer programs contain proprietary
information of Nintendo and/or its licensed developers and are protected by
national and international copyright laws. They may not be disclosed to third
parties or copied or duplicated in any form, in whole or in part, without the
prior written consent of Nintendo.
The content herein is highly confidential and should be handled accordingly.
*--------------------------------------------------------------------------------*/
#include <vector>
#include "./xmlrpc_clientserver.h"
#include "./xmlrpc_value.h"
const int kBufSize = 1024 * 128;
unsigned char g_buf[kBufSize];
class Sum : public XmlRpcServerMethod {
public:
explicit Sum(XmlRpcServer* server) : XmlRpcServerMethod(N("MyFunc.Sum"), server) {}
virtual void Execute(const XmlRpcValue& params, XmlRpcValue* result);
};
void Sum::Execute(const XmlRpcValue& params, XmlRpcValue* result) {
// Sums the int/double values and returns the result as double.
double sum = 0;
const XmlRpcArray* ar = params.AsArray();
size_t n = ar->Size();
for (size_t i = 0; i < n; ++i) {
const XmlRpcValue* item = ar->Get(i);
if (!item) continue;
if (item->GetValueType() == XmlRpcValue::INT) {
sum += *item->AsInt();
} else if (item->GetValueType() == XmlRpcValue::DOUBLE) {
sum += *item->AsDouble();
}
}
result->SetDouble(sum);
}
class MyServer {
XmlRpcServer server_;
std::vector<XmlRpcServerMethod*> vec_;
public:
MyServer() {}
~MyServer() {
size_t n = vec_.size();
for (size_t i = 0; i < n; ++i) delete vec_[i];
}
void SetupMethods() {
Sum* sum = new (std::nothrow) Sum(&server_);
vec_.push_back(sum);
}
XmlRpcServer* GetServer() { return &server_; }
};
// Assumes the server in the distant place.....
MyServer g_server;
bool SampleMain(int, char**) {
g_server.SetupMethods();
XmlRpcClient client;
// This sample simplifies the server connections....
client.SetServer(g_server.GetServer());
// Calls the remotely defined function in the server:
// double MyFunc.Sum(list of int/double)
XmlRpcValue params;
params.SetArray();
params.AsArray()->Append()->SetDouble(1.0);
params.AsArray()->Append()->SetInt(2);
params.AsArray()->Append()->SetDouble(3.0);
nlib_printf("MyFunc.Sum([1.0, 2, 3.0])=");
// methodName = L"MyFunc.Sum"
// params = [1.0, 2, 3.0]
//
// Sends the XML below:
// <methodCall>
// <methodName>MyFunc.Sum</methodName>
// <params>
// <param><value><double>1.0</double></value></param>
// <param><value><i4>2</i4></value></param>
// <param><value><double>3.0</double></value></param>
// </params>
// </methodCall>
XmlRpcValue result;
XmlRpcCallResult future;
if (!client.Execute(N("MyFunc.Sum"), params, &future)) {
nlib_printf("client.Execute failed\n");
return false;
}
// Receives the response below:
// <methodResponse>
// <params>
// <param><value><double>6.0000</double></value></param>
// </params>
// </methodResponse>
if (!future.GetResult(&result)) {
nlib_printf("GetResult failed\n");
return false;
}
nlib_printf("%f\n", *result.AsArray()->Get(0)->AsDouble());
return true;
}
NLIB_MAINFUNC