// A simple standalone XML-RPC server written in C++. // // This server returns to the caller his IP address and port number, // as a demonstration of how to access such information. // // This works only on Unix (to wit, something that uses Abyss's // ChanSwitchUnix channel switch to accept TCP connections from clients). // // See xmlrpc_sample_add_server.cpp for a more basic example. // // To run this: // // $ ./callinfo_abyss_server & // $ xmlrpc localhost:8080 getCallInfo #include #include #include #include #include #include #include #include #include #include #include using namespace std; struct tcpPortAddr { unsigned char ipAddr[4]; unsigned short portNumber; }; static struct tcpPortAddr tcpAddrFromSockAddr(struct sockaddr const sockAddr) { const struct sockaddr_in * const sockAddrInP( static_cast((void *)&sockAddr)); const unsigned char * const ipAddr( static_cast( (const void *)&sockAddrInP->sin_addr.s_addr) ); // 4 byte array assert(sockAddrInP->sin_family == AF_INET); struct tcpPortAddr retval; retval.ipAddr[0] = ipAddr[0]; retval.ipAddr[1] = ipAddr[1]; retval.ipAddr[2] = ipAddr[2]; retval.ipAddr[3] = ipAddr[3]; retval.portNumber = ntohs(sockAddrInP->sin_port); return retval; } static std::string rpcIpAddrMsg(xmlrpc_c::callInfo_serverAbyss const& callInfo) { void * chanInfoPtr; SessionGetChannelInfo(callInfo.abyssSessionP, &chanInfoPtr); struct abyss_unix_chaninfo * const chanInfoP( static_cast(chanInfoPtr)); struct tcpPortAddr const tcpAddr(tcpAddrFromSockAddr(chanInfoP->peerAddr)); char msg[128]; sprintf(msg, "RPC is from IP address %u.%u.%u.%u, Port %hu", tcpAddr.ipAddr[0], tcpAddr.ipAddr[1], tcpAddr.ipAddr[2], tcpAddr.ipAddr[3], tcpAddr.portNumber); return std::string(msg); } class getCallInfoMethod : public xmlrpc_c::method2 { public: void execute(xmlrpc_c::paramList const& paramList, const xmlrpc_c::callInfo * const callInfoPtr, xmlrpc_c::value * const retvalP) { const xmlrpc_c::callInfo_serverAbyss * const callInfoP( dynamic_cast(callInfoPtr)); paramList.verifyEnd(0); // Because this gets called via a xmlrpc_c::serverAbyss: assert(callInfoP != NULL); *retvalP = xmlrpc_c::value_string(rpcIpAddrMsg(*callInfoP)); } }; int main(int const, const char ** const) { try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const getCallInfoMethodP(new getCallInfoMethod); myRegistry.addMethod("getCallInfo", getCallInfoMethodP); xmlrpc_c::serverAbyss myAbyssServer(xmlrpc_c::serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(8080) ); myAbyssServer.run(); // xmlrpc_c::serverAbyss.run() never returns assert(false); } catch (exception const& e) { cerr << "Something failed. " << e.what() << endl; } return 0; }