/*============================================================================= pstream =============================================================================== Client XML transport for Xmlrpc-c based on a very simple byte stream. The protocol we use is the "packet socket" protocol, which is an Xmlrpc-c invention. It is an almost trivial representation of a sequence of packets on a byte stream. A transport object talks to exactly one server over its lifetime. You can create a pstream transport from any file descriptor from which you can read and write a bidirectional character stream. Typically, it's a TCP socket. This transport is synchronous only. It does not provide a working 'start' method. You have at most one outstanding RPC and wait for it to complete. By Bryan Henderson 07.05.12. Contributed to the public domain by its author. =============================================================================*/ #include #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/packetsocket.hpp" #include "xmlrpc-c/client_transport.hpp" using namespace std; namespace xmlrpc_c { struct clientXmlTransport_pstream::constrOpt_impl { constrOpt_impl(); struct { int fd; } value; struct { bool fd; } present; }; clientXmlTransport_pstream::constrOpt_impl::constrOpt_impl() { this->present.fd = false; } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ clientXmlTransport_pstream::constrOpt & \ clientXmlTransport_pstream::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->implP->value.OPTION_NAME = arg; \ this->implP->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(fd, xmlrpc_socket); #undef DEFINE_OPTION_SETTER clientXmlTransport_pstream::constrOpt::constrOpt() { this->implP = new clientXmlTransport_pstream::constrOpt_impl(); } clientXmlTransport_pstream::constrOpt::~constrOpt() { delete(this->implP); } clientXmlTransport_pstream::constrOpt::constrOpt(constrOpt& arg) { this->implP = new clientXmlTransport_pstream::constrOpt_impl(*arg.implP); } clientXmlTransport_pstream::clientXmlTransport_pstream( constrOpt const& optExt) { constrOpt_impl const opt(*optExt.implP); if (!opt.present.fd) throwf("You must provide a 'fd' constructor option."); auto_ptr packetSocketAP; try { auto_ptr p(new packetSocket(opt.value.fd)); packetSocketAP = p; } catch (exception const& e) { throwf("Unable to create packet socket out of file descriptor %d. %s", opt.value.fd, e.what()); } this->packetSocketP = packetSocketAP.get(); packetSocketAP.release(); } clientXmlTransport_pstream::~clientXmlTransport_pstream() { delete(this->packetSocketP); } void clientXmlTransport_pstream::call( carriageParm * const carriageParmP, string const& callXml, string * const responseXmlP) { carriageParm_pstream * const carriageParmPstreamP( dynamic_cast(carriageParmP)); if (carriageParmPstreamP == NULL) throwf("Pstream client XML transport called with carriage " "parameter object not of class carriageParm_pstream"); packetPtr const callPacketP(new packet(callXml.c_str(), callXml.length())); try { this->packetSocketP->writeWait(callPacketP); } catch (exception const& e) { throwf("Failed to write the call to the packet socket. %s", e.what()); } packetPtr responsePacketP; try { bool eof; this->packetSocketP->readWait(&eof, &responsePacketP); if (eof) throwf("The other end closed the socket before sending " "the response."); } catch (exception const& e) { throwf("We sent the call, but couldn't get the response. %s", e.what()); } *responseXmlP = string(reinterpret_cast(responsePacketP->getBytes()), responsePacketP->getLength()); } } // namespace