callinfo_abyss_server.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. #include <cassert>
  16. #include <stdexcept>
  17. #include <iostream>
  18. #include <unistd.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <stdio.h>
  22. #include <xmlrpc-c/base.hpp>
  23. #include <xmlrpc-c/registry.hpp>
  24. #include <xmlrpc-c/server_abyss.hpp>
  25. #include <xmlrpc-c/abyss.h>
  26. using namespace std;
  27. struct tcpPortAddr {
  28. unsigned char ipAddr[4];
  29. unsigned short portNumber;
  30. };
  31. static struct tcpPortAddr
  32. tcpAddrFromSockAddr(struct sockaddr const sockAddr) {
  33. const struct sockaddr_in * const sockAddrInP(
  34. static_cast<struct sockaddr_in *>((void *)&sockAddr));
  35. const unsigned char * const ipAddr(
  36. static_cast<const unsigned char *>(
  37. (const void *)&sockAddrInP->sin_addr.s_addr)
  38. ); // 4 byte array
  39. assert(sockAddrInP->sin_family == AF_INET);
  40. struct tcpPortAddr retval;
  41. retval.ipAddr[0] = ipAddr[0];
  42. retval.ipAddr[1] = ipAddr[1];
  43. retval.ipAddr[2] = ipAddr[2];
  44. retval.ipAddr[3] = ipAddr[3];
  45. retval.portNumber = ntohs(sockAddrInP->sin_port);
  46. return retval;
  47. }
  48. static std::string
  49. rpcIpAddrMsg(xmlrpc_c::callInfo_serverAbyss const& callInfo) {
  50. void * chanInfoPtr;
  51. SessionGetChannelInfo(callInfo.abyssSessionP, &chanInfoPtr);
  52. struct abyss_unix_chaninfo * const chanInfoP(
  53. static_cast<struct abyss_unix_chaninfo *>(chanInfoPtr));
  54. struct tcpPortAddr const tcpAddr(tcpAddrFromSockAddr(chanInfoP->peerAddr));
  55. char msg[128];
  56. sprintf(msg, "RPC is from IP address %u.%u.%u.%u, Port %hu",
  57. tcpAddr.ipAddr[0],
  58. tcpAddr.ipAddr[1],
  59. tcpAddr.ipAddr[2],
  60. tcpAddr.ipAddr[3],
  61. tcpAddr.portNumber);
  62. return std::string(msg);
  63. }
  64. class getCallInfoMethod : public xmlrpc_c::method2 {
  65. public:
  66. void
  67. execute(xmlrpc_c::paramList const& paramList,
  68. const xmlrpc_c::callInfo * const callInfoPtr,
  69. xmlrpc_c::value * const retvalP) {
  70. const xmlrpc_c::callInfo_serverAbyss * const callInfoP(
  71. dynamic_cast<const xmlrpc_c::callInfo_serverAbyss *>(callInfoPtr));
  72. paramList.verifyEnd(0);
  73. // Because this gets called via a xmlrpc_c::serverAbyss:
  74. assert(callInfoP != NULL);
  75. *retvalP = xmlrpc_c::value_string(rpcIpAddrMsg(*callInfoP));
  76. }
  77. };
  78. int
  79. main(int const,
  80. const char ** const) {
  81. try {
  82. xmlrpc_c::registry myRegistry;
  83. xmlrpc_c::methodPtr const getCallInfoMethodP(new getCallInfoMethod);
  84. myRegistry.addMethod("getCallInfo", getCallInfoMethodP);
  85. xmlrpc_c::serverAbyss myAbyssServer(xmlrpc_c::serverAbyss::constrOpt()
  86. .registryP(&myRegistry)
  87. .portNumber(8080)
  88. );
  89. myAbyssServer.run();
  90. // xmlrpc_c::serverAbyss.run() never returns
  91. assert(false);
  92. } catch (exception const& e) {
  93. cerr << "Something failed. " << e.what() << endl;
  94. }
  95. return 0;
  96. }