Menu

[r3316]: / advanced / src / cpp / pstream.cpp  Maximize  Restore  History

Download this file

265 lines (174 with data), 6.9 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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*=============================================================================
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 <memory>
using namespace std;
#include "xmlrpc-c/girerr.hpp"
using girerr::throwf;
#include "xmlrpc-c/packetsocket.hpp"
#include "xmlrpc-c/util_int.h"
#include "xmlrpc-c/client_transport.hpp"
typedef xmlrpc_c::clientXmlTransport_pstream::BrokenConnectionEx
BrokenConnectionEx;
namespace xmlrpc_c {
struct clientXmlTransport_pstream::constrOpt_impl {
constrOpt_impl();
struct {
int fd;
bool useBrokenConnEx;
} value;
struct {
bool fd;
bool useBrokenConnEx;
} present;
};
clientXmlTransport_pstream::constrOpt_impl::constrOpt_impl() {
this->present.fd = false;
this->present.useBrokenConnEx = 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);
DEFINE_OPTION_SETTER(useBrokenConnEx, bool);
#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);
}
class clientXmlTransport_pstream_impl {
public:
clientXmlTransport_pstream_impl(
clientXmlTransport_pstream::constrOpt_impl const& opt);
~clientXmlTransport_pstream_impl();
void
call(xmlrpc_c::carriageParm * const carriageParmP,
std::string const& callXml,
std::string * const responseXmlP);
private:
packetSocket * packetSocketP;
bool usingBrokenConnEx;
// We're throwing a Broken Connection object when something fails
// because the connection to the server is broken. When this is false,
// we throw an ordinary error when that happens.
void
sendCall(std::string const& callXml);
void
recvResp(std::string * const responseXmlP);
};
clientXmlTransport_pstream_impl::clientXmlTransport_pstream_impl(
clientXmlTransport_pstream::constrOpt_impl const& opt) {
if (!opt.present.fd)
throwf("You must provide a 'fd' constructor option.");
UNIQUE_PTR<packetSocket> packetSocketAP;
try {
packetSocketAP.reset(new packetSocket(opt.value.fd));
} catch (exception const& e) {
throwf("Unable to create packet socket out of file descriptor %d. %s",
opt.value.fd, e.what());
}
if (opt.present.useBrokenConnEx)
this->usingBrokenConnEx = opt.value.useBrokenConnEx;
else
this->usingBrokenConnEx = false;
this->packetSocketP = packetSocketAP.release();
}
clientXmlTransport_pstream::clientXmlTransport_pstream(
constrOpt const& optExt) :
implP(new clientXmlTransport_pstream_impl(*optExt.implP))
{}
clientXmlTransport_pstream_impl::~clientXmlTransport_pstream_impl() {
delete(this->packetSocketP);
}
clientXmlTransport_pstream::~clientXmlTransport_pstream() {
delete(this->implP);
}
void // private
clientXmlTransport_pstream_impl::sendCall(string const& callXml) {
/*----------------------------------------------------------------------------
Send the text 'callXml' down the pipe as a packet which is the RPC call.
-----------------------------------------------------------------------------*/
packetPtr const callPacketP(new packet(callXml.c_str(), callXml.length()));
try {
bool brokenConn;
this->packetSocketP->writeWait(callPacketP, &brokenConn);
if (brokenConn) {
if (this->usingBrokenConnEx)
throw BrokenConnectionEx();
else
throwf("Server hung up or connection broke");
}
} catch (exception const& e) {
throwf("Failed to write the call to the packet socket. %s", e.what());
}
}
void
clientXmlTransport_pstream_impl::recvResp(string * const responseXmlP) {
/*----------------------------------------------------------------------------
Receive a packet which is the RPC response and return its contents
as the text *responseXmlP.
-----------------------------------------------------------------------------*/
packetPtr responsePacketP;
try {
bool eof;
this->packetSocketP->readWait(&eof, &responsePacketP);
if (eof) {
if (this->usingBrokenConnEx)
throw BrokenConnectionEx();
else
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<char *>(responsePacketP->getBytes()),
responsePacketP->getLength());
}
void
clientXmlTransport_pstream_impl::call(
carriageParm * const carriageParmP,
string const& callXml,
string * const responseXmlP) {
carriageParm_pstream * const carriageParmPstreamP(
dynamic_cast<carriageParm_pstream *>(carriageParmP));
if (carriageParmPstreamP == NULL)
throwf("Pstream client XML transport called with carriage "
"parameter object not of class carriageParm_pstream");
this->sendCall(callXml);
this->recvResp(responseXmlP);
}
void
clientXmlTransport_pstream::call(
carriageParm * const carriageParmP,
string const& callXml,
string * const responseXmlP) {
this->implP->call(carriageParmP, callXml, responseXmlP);
}
} // 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.