Menu

[r1545]: / advanced / src / cpp / server_pstream.cpp  Maximize  Restore  History

Download this file

188 lines (130 with data), 5.4 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*=============================================================================
server_pstream
===============================================================================
RPC server based on a very simple byte stream and XML-RPC XML
(But this is not an XML-RPC server because it doesn't use HTTP).
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.
You can create a pstream server from any file descriptor from which
you can read and write a bidirectional character stream. Typically,
it's a TCP socket. Such a server talks to one client its entire life.
Some day, we'll also have a version that you create from a "listening"
socket, which can talk to multiple clients serially (a client connects,
does some RPCs, and disconnects).
By Bryan Henderson 07.05.12.
Contributed to the public domain by its author.
=============================================================================*/
#include <memory>
#include "xmlrpc-c/girerr.hpp"
using girerr::throwf;
#include "xmlrpc-c/packetsocket.hpp"
#include "xmlrpc-c/server_pstream.hpp"
using namespace std;
namespace xmlrpc_c {
serverPstreamConn::constrOpt::constrOpt() {
present.socketFd = false;
present.registryP = false;
present.registryPtr = false;
}
#define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \
serverPstreamConn::constrOpt & \
serverPstreamConn::constrOpt::OPTION_NAME(TYPE const& arg) { \
this->value.OPTION_NAME = arg; \
this->present.OPTION_NAME = true; \
return *this; \
}
DEFINE_OPTION_SETTER(socketFd, XMLRPC_SOCKET);
DEFINE_OPTION_SETTER(registryP, const registry *);
DEFINE_OPTION_SETTER(registryPtr, xmlrpc_c::registryPtr);
#undef DEFINE_OPTION_SETTER
void
serverPstreamConn::establishRegistry(constrOpt const& opt) {
if (!opt.present.registryP && !opt.present.registryPtr)
throwf("You must specify the 'registryP' or 'registryPtr' option");
else if (opt.present.registryP && opt.present.registryPtr)
throwf("You may not specify both the 'registryP' and "
"the 'registryPtr' options");
else {
if (opt.present.registryP)
this->registryP = opt.value.registryP;
else {
this->registryHolder = opt.value.registryPtr;
this->registryP = opt.value.registryPtr.get();
}
}
}
void
serverPstreamConn::establishPacketSocket(constrOpt const& opt) {
if (!opt.present.socketFd)
throwf("You must provide a 'socketFd' constructor option.");
auto_ptr<packetSocket> packetSocketAP;
try {
auto_ptr<packetSocket> p(new packetSocket(opt.value.socketFd));
packetSocketAP = p;
} catch (exception const& e) {
throwf("Unable to create packet socket out of file descriptor %d. %s",
opt.value.socketFd, e.what());
}
this->packetSocketP = packetSocketAP.get();
packetSocketAP.release();
}
serverPstreamConn::serverPstreamConn(constrOpt const& opt) {
this->establishRegistry(opt);
this->establishPacketSocket(opt);
}
serverPstreamConn::~serverPstreamConn() {
delete(this->packetSocketP);
}
void
processCall(const registry * const registryP,
packetPtr const& callPacketP,
packetPtr * const responsePacketPP) {
string const callXml(reinterpret_cast<char *>(callPacketP->getBytes()),
callPacketP->getLength());
string responseXml;
registryP->processCall(callXml, &responseXml);
*responsePacketPP = packetPtr(new packet(responseXml.c_str(),
responseXml.length()));
}
void
serverPstreamConn::runOnce(volatile const int * const interruptP,
bool * const eofP) {
/*----------------------------------------------------------------------------
Get and execute one RPC from the client.
Unless *interruptP gets set nonzero first.
-----------------------------------------------------------------------------*/
bool gotPacket;
packetPtr callPacketP;
try {
this->packetSocketP->readWait(interruptP, eofP, &gotPacket,
&callPacketP);
} catch (exception const& e) {
throwf("Error reading a packet from the packet socket. %s",
e.what());
}
if (gotPacket) {
packetPtr responsePacketP;
try {
processCall(this->registryP, callPacketP, &responsePacketP);
} catch (exception const& e) {
throwf("Error executing received packet as an XML-RPC RPC. %s",
e.what());
}
try {
this->packetSocketP->writeWait(responsePacketP);
} catch (exception const& e) {
throwf("Failed to write the response to the packet socket. %s",
e.what());
}
}
}
void
serverPstreamConn::runOnce(bool * const eofP) {
/*----------------------------------------------------------------------------
Get and execute one RPC from the client.
-----------------------------------------------------------------------------*/
int const interrupt(0); // Never interrupt
this->runOnce(&interrupt, eofP);
}
} // namespace
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.