1 // A simple standalone XML-RPC server written in C++.
2 //
3 // This server returns to the caller his IP address and port number,
4 // as a demonstration of how to access such information.
5 //
6 // This works only on Unix (to wit, something that uses Abyss's
7 // ChanSwitchUnix channel switch to accept TCP connections from clients).
8 //
9 // See xmlrpc_sample_add_server.cpp for a more basic example.
10 //
11 // To run this:
12 //
13 // $ ./callinfo_abyss_server &
14 // $ xmlrpc localhost:8080 getCallInfo
15
16 #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.hpp */
17
18 #include <cassert>
19 #include <stdexcept>
20 #include <iostream>
21 #include <unistd.h>
22 #include <stdio.h>
23 #ifndef _WIN32
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #endif
27
28 using namespace std;
29
30 #include <xmlrpc-c/base.hpp>
31 #include <xmlrpc-c/registry.hpp>
32 #include <xmlrpc-c/server_abyss.hpp>
33 #include <xmlrpc-c/abyss.h>
34
35
36 struct tcpPortAddr {
37 unsigned char ipAddr[4];
38 unsigned short portNumber;
39 };
40
41
42 static struct tcpPortAddr
tcpAddrFromSockAddr(struct sockaddr const sockAddr)43 tcpAddrFromSockAddr(struct sockaddr const sockAddr) {
44
45 const struct sockaddr_in * const sockAddrInP(
46 static_cast<struct sockaddr_in *>((void *)&sockAddr));
47
48 const unsigned char * const ipAddr(
49 static_cast<const unsigned char *>(
50 (const void *)&sockAddrInP->sin_addr.s_addr)
51 ); // 4 byte array
52
53 assert(sockAddrInP->sin_family == AF_INET);
54
55 struct tcpPortAddr retval;
56
57 retval.ipAddr[0] = ipAddr[0];
58 retval.ipAddr[1] = ipAddr[1];
59 retval.ipAddr[2] = ipAddr[2];
60 retval.ipAddr[3] = ipAddr[3];
61 retval.portNumber = ntohs(sockAddrInP->sin_port);
62
63 return retval;
64 }
65
66
67
68 /* On Windows, we have struct abyss_win_chaninfo, while on Unix we have
69 struct abyss_unix_chaninfo, but for what we're doing here, they're
70 fungible -- we use only members that exist in both. So we refer to the
71 generically with macro CHANINFO_TYPE.
72 */
73
74 #ifdef _WIN32
75 #define CHANINFO_TYPE abyss_win_chaninfo
76 #else
77 #define CHANINFO_TYPE abyss_unix_chaninfo
78 #endif
79
80 static string
rpcIpAddrMsg(xmlrpc_c::callInfo_serverAbyss const & callInfo)81 rpcIpAddrMsg(xmlrpc_c::callInfo_serverAbyss const& callInfo) {
82
83 void * chanInfoPtr;
84 SessionGetChannelInfo(callInfo.abyssSessionP, &chanInfoPtr);
85
86 struct CHANINFO_TYPE * const chanInfoP(
87 static_cast<struct CHANINFO_TYPE *>(chanInfoPtr));
88
89 struct tcpPortAddr const tcpAddr(tcpAddrFromSockAddr(chanInfoP->peerAddr));
90
91 char msg[128];
92
93 sprintf(msg, "RPC is from IP address %u.%u.%u.%u, Port %hu",
94 tcpAddr.ipAddr[0],
95 tcpAddr.ipAddr[1],
96 tcpAddr.ipAddr[2],
97 tcpAddr.ipAddr[3],
98 tcpAddr.portNumber);
99
100 return string(msg);
101 }
102
103
104
105 class getCallInfoMethod : public xmlrpc_c::method2 {
106 public:
107 void
execute(xmlrpc_c::paramList const & paramList,const xmlrpc_c::callInfo * const callInfoPtr,xmlrpc_c::value * const retvalP)108 execute(xmlrpc_c::paramList const& paramList,
109 const xmlrpc_c::callInfo * const callInfoPtr,
110 xmlrpc_c::value * const retvalP) {
111
112 const xmlrpc_c::callInfo_serverAbyss * const callInfoP(
113 dynamic_cast<const xmlrpc_c::callInfo_serverAbyss *>(callInfoPtr));
114
115 paramList.verifyEnd(0);
116
117 // Because this gets called via a xmlrpc_c::serverAbyss:
118 assert(callInfoP != NULL);
119
120 *retvalP = xmlrpc_c::value_string(rpcIpAddrMsg(*callInfoP));
121 }
122 };
123
124
125
126 int
main(int const,const char ** const)127 main(int const,
128 const char ** const) {
129
130 try {
131 xmlrpc_c::registry myRegistry;
132
133 xmlrpc_c::methodPtr const getCallInfoMethodP(new getCallInfoMethod);
134
135 myRegistry.addMethod("getCallInfo", getCallInfoMethodP);
136
137 xmlrpc_c::serverAbyss myAbyssServer(xmlrpc_c::serverAbyss::constrOpt()
138 .registryP(&myRegistry)
139 .portNumber(8080)
140 );
141
142 myAbyssServer.run();
143 // xmlrpc_c::serverAbyss.run() never returns
144 assert(false);
145 } catch (exception const& e) {
146 cerr << "Something failed. " << e.what() << endl;
147 }
148 return 0;
149 }
150