mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-13 23:04:13 +00:00
FS-2746 --resolve large xmlrpc update thanks garmt
This commit is contained in:
1 parent
37ecad9903
commit
6b6c83a718
397 files changed
+41821
-33840
No files matched your search
@@ -4,16 +4,37 @@
|
||||
Test the pstream server C++ facilities of XML-RPC for C/C++.
|
||||
|
||||
=============================================================================*/
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#if MSVCRT
|
||||
#include <winsock2.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "xmlrpc-c/config.h"
|
||||
|
||||
#if MSVCRT
|
||||
int
|
||||
xmlrpc_win32_socketpair(int const domain,
|
||||
int const type,
|
||||
int const protocol,
|
||||
SOCKET socks[2]);
|
||||
#endif
|
||||
|
||||
#include "xmlrpc-c/girerr.hpp"
|
||||
using girerr::error;
|
||||
using girerr::throwf;
|
||||
#include "xmlrpc-c/sleep_int.h"
|
||||
#include "xmlrpc-c/base.hpp"
|
||||
#include "xmlrpc-c/registry.hpp"
|
||||
#include "xmlrpc-c/server_pstream.hpp"
|
||||
@@ -25,6 +46,41 @@ using namespace xmlrpc_c;
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
static void
|
||||
setNonBlocking(XMLRPC_SOCKET const socket) {
|
||||
|
||||
#if MSVCRT
|
||||
u_long iMode = 1;
|
||||
ioctlsocket(socket, FIONBIO, &iMode);
|
||||
#else
|
||||
fcntl(socket, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define ESC_STR "\x1B"
|
||||
|
||||
|
||||
static string const
|
||||
xmlPrologue("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
|
||||
|
||||
static string const
|
||||
packetStart(ESC_STR "PKT");
|
||||
|
||||
static string const
|
||||
packetEnd(ESC_STR "END");
|
||||
|
||||
|
||||
class callInfo_test : public callInfo {
|
||||
public:
|
||||
callInfo_test() : info("this is a test") {}
|
||||
string const info;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class sampleAddMethod : public method {
|
||||
public:
|
||||
@@ -45,51 +101,542 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
string const sampleAddCallXml(
|
||||
xmlPrologue +
|
||||
"<methodCall>\r\n"
|
||||
"<methodName>sample.add</methodName>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>5</i4></value></param>\r\n"
|
||||
"<param><value><i4>7</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodCall>\r\n"
|
||||
);
|
||||
|
||||
string const sampleAddResponseXml(
|
||||
xmlPrologue +
|
||||
"<methodResponse>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>12</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodResponse>\r\n"
|
||||
);
|
||||
|
||||
|
||||
class testCallInfoMethod : public method2 {
|
||||
|
||||
public:
|
||||
virtual void
|
||||
execute(paramList const& paramList,
|
||||
const callInfo * const callInfoPtr,
|
||||
value * const retvalP) {
|
||||
|
||||
const callInfo_test * const callInfoP(
|
||||
dynamic_cast<const callInfo_test *>(callInfoPtr));
|
||||
|
||||
TEST(callInfoP != NULL);
|
||||
|
||||
paramList.verifyEnd(0);
|
||||
|
||||
TEST(callInfoP->info == string("this is a test"));
|
||||
|
||||
*retvalP = value_nil();
|
||||
}
|
||||
};
|
||||
|
||||
string const testCallInfoCallXml(
|
||||
xmlPrologue +
|
||||
"<methodCall>\r\n"
|
||||
"<methodName>test.callinfo</methodName>\r\n"
|
||||
"<params>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodCall>\r\n"
|
||||
);
|
||||
|
||||
string const testCallInfoResponseXml(
|
||||
xmlPrologue +
|
||||
"<methodResponse>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><nil/></value>"
|
||||
"</param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodResponse>\r\n"
|
||||
);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
createTestFile(string const& contents,
|
||||
int * const fdP) {
|
||||
waitForNetworkTransport() {
|
||||
/*----------------------------------------------------------------------------
|
||||
Wait for a message to travel through the network.
|
||||
|
||||
string const filename("/tmp/xmlrpc_test_pstream");
|
||||
unlink(filename.c_str());
|
||||
This is part of our hack to allow us to test client/server communication
|
||||
without the bother of a separate thread for each. One party writes
|
||||
to a socket, causing the OS to buffer the message, then the other party
|
||||
reads from the socket, getting the buffered message. We never wait
|
||||
to send or receive, because with only one thread to do both, we would
|
||||
deadlock. Instead, we just count on the buffer being big enough.
|
||||
|
||||
But on some systems, the message doesn't immediately travel like this. It
|
||||
takes action by an independent thread (provided by the OS) to move the
|
||||
message. In particular, we've seen this behavior on Windows (2010.10).
|
||||
|
||||
So we just sleep for a small amount of time to let the message move.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// xmlrpc_millisecond_sleep() is allowed to return early, and on Windows
|
||||
// it does that in preference to returning late insofar as the clock
|
||||
// resolution doesn't allow returning at the exact time. It is rumored
|
||||
// that Windows clock period may be as long as 40 milliseconds.
|
||||
|
||||
xmlrpc_millisecond_sleep(50);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class client {
|
||||
/*----------------------------------------------------------------------------
|
||||
This is an object you can use as a client to test a packet stream
|
||||
server.
|
||||
|
||||
You attach the 'serverFd' member to your packet stream server, then
|
||||
call the 'sendCall' method to send a call to your server, then call
|
||||
the 'recvResp' method to get the response.
|
||||
|
||||
Destroying the object closes the connection.
|
||||
|
||||
We rely on typical, though unguaranteed socket function: we need to
|
||||
be able to write 'contents' to the socket in a single write()
|
||||
system call before the other side reads anything -- i.e. the socket
|
||||
has to have a buffer that big. We do this because we're lazy; doing
|
||||
it right would require forking a writer process.
|
||||
-----------------------------------------------------------------------------*/
|
||||
public:
|
||||
|
||||
client();
|
||||
|
||||
~client();
|
||||
|
||||
void
|
||||
sendCall(string const& callBytes) const;
|
||||
|
||||
void
|
||||
hangup();
|
||||
|
||||
void
|
||||
recvResp(string * const respBytesP) const;
|
||||
|
||||
int serverFd;
|
||||
|
||||
private:
|
||||
|
||||
int clientFd;
|
||||
};
|
||||
|
||||
|
||||
|
||||
client::client() {
|
||||
|
||||
enum {
|
||||
SERVER = 0,
|
||||
CLIENT = 1,
|
||||
};
|
||||
XMLRPC_SOCKET sockets[2];
|
||||
int rc;
|
||||
rc = open(filename.c_str(), O_RDWR | O_CREAT);
|
||||
unlink(filename.c_str());
|
||||
|
||||
|
||||
rc = XMLRPC_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sockets);
|
||||
|
||||
if (rc < 0)
|
||||
throwf("Failed to create file '%s' as a test tool. errno=%d (%s)",
|
||||
filename.c_str(), errno, strerror(errno));
|
||||
throwf("Failed to create UNIX domain stream socket pair "
|
||||
"as test tool. errno=%d (%s)",
|
||||
errno, strerror(errno));
|
||||
else {
|
||||
int const fd(rc);
|
||||
setNonBlocking(sockets[CLIENT]);
|
||||
|
||||
int rc;
|
||||
|
||||
rc = write(fd, contents.c_str(), contents.length());
|
||||
|
||||
if (rc < 0)
|
||||
throwf("write() of test file failed, errno=%d (%s)",
|
||||
errno, strerror(errno));
|
||||
else {
|
||||
unsigned int bytesWritten(rc);
|
||||
|
||||
if (bytesWritten != contents.length())
|
||||
throwf("Short write");
|
||||
else {
|
||||
int rc;
|
||||
rc = lseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (rc < 0)
|
||||
throwf("lseek(0) of test file failed, errno=%d (%s)",
|
||||
errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
*fdP = fd;
|
||||
this->serverFd = sockets[SERVER];
|
||||
this->clientFd = sockets[CLIENT];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
client::~client() {
|
||||
|
||||
XMLRPC_CLOSESOCKET(this->clientFd);
|
||||
XMLRPC_CLOSESOCKET(this->serverFd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
client::sendCall(string const& packetBytes) const {
|
||||
|
||||
int rc;
|
||||
|
||||
rc = send(this->clientFd, packetBytes.c_str(), packetBytes.length(), 0);
|
||||
|
||||
waitForNetworkTransport();
|
||||
|
||||
if (rc < 0)
|
||||
throwf("send() of test data to socket failed, errno=%d (%s)",
|
||||
errno, strerror(errno));
|
||||
else {
|
||||
unsigned int bytesWritten(rc);
|
||||
|
||||
if (bytesWritten != packetBytes.length())
|
||||
throwf("Short write to socket");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
client::hangup() {
|
||||
|
||||
// Closing the socket (close()) would be a better simulation of the
|
||||
// real world, and easier, but we shut down just the client->server
|
||||
// half of the socket and remain open to receive an RPC response.
|
||||
// That's because this test program is lazy and does the client and
|
||||
// server in the same thread, depending on socket buffering on the
|
||||
// receive side to provide parallelism. We need to be able to do the
|
||||
// following sequence:
|
||||
//
|
||||
// - Client sends call
|
||||
// - Client hangs up
|
||||
// - Server gets call
|
||||
// - Server sends response
|
||||
// - Client gets response
|
||||
// - Server notices hangup
|
||||
|
||||
shutdown(this->clientFd, 1); // Shutdown for transmission only
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
client::recvResp(string * const packetBytesP) const {
|
||||
|
||||
char buffer[4096];
|
||||
int rc;
|
||||
|
||||
waitForNetworkTransport();
|
||||
|
||||
rc = recv(this->clientFd, buffer, sizeof(buffer), 0);
|
||||
|
||||
if (rc < 0)
|
||||
throwf("recv() from socket failed, errno=%d (%s)",
|
||||
errno, strerror(errno));
|
||||
else {
|
||||
unsigned int bytesReceived(rc);
|
||||
|
||||
*packetBytesP = string(buffer, bytesReceived);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testEmptyStream(registry const& myRegistry) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Here we send the pstream server an empty stream; i.e. we close the
|
||||
socket from the client end without sending anything.
|
||||
|
||||
This should cause the server to recognize EOF.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
client.hangup();
|
||||
|
||||
bool eof;
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(eof);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testBrokenPacket(registry const& myRegistry) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Here we send a stream that is not a legal packetsocket stream: it
|
||||
doesn't have any control word.
|
||||
-----------------------------------------------------------------------------*/
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
client.sendCall("junk");
|
||||
client.hangup();
|
||||
|
||||
bool eof;
|
||||
|
||||
EXPECT_ERROR(
|
||||
server.runOnce(&eof);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testEmptyPacket(registry const& myRegistry) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Here we send the pstream server one empty packet. It should respond
|
||||
with one packet, being an XML-RPC fault response complaining that the
|
||||
call is not valid XML.
|
||||
-----------------------------------------------------------------------------*/
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
client.sendCall(packetStart + packetEnd);
|
||||
|
||||
bool eof;
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(!eof);
|
||||
|
||||
string response;
|
||||
client.recvResp(&response);
|
||||
|
||||
// We ought to validate that the response is a complaint about
|
||||
// the empty call
|
||||
|
||||
client.hangup();
|
||||
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(eof);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testCallInfo(client * const clientP,
|
||||
serverPstreamConn * const serverP) {
|
||||
|
||||
string const testCallInfoCallStream(
|
||||
packetStart + testCallInfoCallXml + packetEnd
|
||||
);
|
||||
|
||||
string const testCallInfoResponseStream(
|
||||
packetStart + testCallInfoResponseXml + packetEnd
|
||||
);
|
||||
|
||||
clientP->sendCall(testCallInfoCallStream);
|
||||
|
||||
callInfo_test callInfo;
|
||||
int nointerrupt(0);
|
||||
bool eof;
|
||||
serverP->runOnce(&callInfo, &nointerrupt, &eof);
|
||||
|
||||
TEST(!eof);
|
||||
|
||||
string response;
|
||||
clientP->recvResp(&response);
|
||||
|
||||
TEST(response == testCallInfoResponseStream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testNormalCall(registry const& myRegistry) {
|
||||
|
||||
string const sampleAddGoodCallStream(
|
||||
packetStart + sampleAddCallXml + packetEnd
|
||||
);
|
||||
|
||||
string const sampleAddGoodResponseStream(
|
||||
packetStart + sampleAddResponseXml + packetEnd
|
||||
);
|
||||
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
client.sendCall(sampleAddGoodCallStream);
|
||||
|
||||
bool eof;
|
||||
|
||||
int interrupt(1);
|
||||
server.runOnce(&interrupt, &eof); // returns without reading socket
|
||||
TEST(!eof);
|
||||
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(!eof);
|
||||
|
||||
string response;
|
||||
client.recvResp(&response);
|
||||
|
||||
TEST(response == sampleAddGoodResponseStream);
|
||||
|
||||
testCallInfo(&client, &server);
|
||||
|
||||
client.hangup();
|
||||
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(eof);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testNoWaitCall(registry const& myRegistry) {
|
||||
|
||||
string const sampleAddGoodCallStream(
|
||||
packetStart +
|
||||
xmlPrologue +
|
||||
"<methodCall>\r\n"
|
||||
"<methodName>sample.add</methodName>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>5</i4></value></param>\r\n"
|
||||
"<param><value><i4>7</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodCall>\r\n" +
|
||||
packetEnd
|
||||
);
|
||||
|
||||
|
||||
string const sampleAddGoodResponseStream(
|
||||
packetStart +
|
||||
xmlPrologue +
|
||||
"<methodResponse>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>12</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodResponse>\r\n" +
|
||||
packetEnd
|
||||
);
|
||||
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
bool eof;
|
||||
bool gotOne;
|
||||
string response;
|
||||
|
||||
server.runOnceNoWait(&eof, &gotOne);
|
||||
|
||||
TEST(!eof);
|
||||
TEST(!gotOne);
|
||||
|
||||
server.runOnceNoWait(&eof);
|
||||
|
||||
TEST(!eof);
|
||||
|
||||
client.sendCall(sampleAddGoodCallStream);
|
||||
|
||||
server.runOnceNoWait(&eof, &gotOne);
|
||||
|
||||
TEST(!eof);
|
||||
TEST(gotOne);
|
||||
|
||||
client.recvResp(&response);
|
||||
|
||||
TEST(response == sampleAddGoodResponseStream);
|
||||
|
||||
client.sendCall(sampleAddGoodCallStream);
|
||||
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(!eof);
|
||||
client.recvResp(&response);
|
||||
TEST(response == sampleAddGoodResponseStream);
|
||||
|
||||
client.hangup();
|
||||
|
||||
server.runOnce(&eof);
|
||||
|
||||
TEST(eof);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testMultiRpcRunNoRpc(registry const& myRegistry) {
|
||||
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
client.hangup();
|
||||
|
||||
server.run();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testMultiRpcRunOneRpc(registry const& myRegistry) {
|
||||
|
||||
string const sampleAddGoodCallStream(
|
||||
packetStart +
|
||||
xmlPrologue +
|
||||
"<methodCall>\r\n"
|
||||
"<methodName>sample.add</methodName>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>5</i4></value></param>\r\n"
|
||||
"<param><value><i4>7</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodCall>\r\n" +
|
||||
packetEnd
|
||||
);
|
||||
|
||||
|
||||
string const sampleAddGoodResponseStream(
|
||||
packetStart +
|
||||
xmlPrologue +
|
||||
"<methodResponse>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>12</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodResponse>\r\n" +
|
||||
packetEnd
|
||||
);
|
||||
|
||||
client client;
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(client.serverFd));
|
||||
|
||||
|
||||
client.sendCall(sampleAddGoodCallStream);
|
||||
client.hangup();
|
||||
|
||||
int interrupt;
|
||||
|
||||
interrupt = 1;
|
||||
server.run(&interrupt); // Returns without reading socket
|
||||
|
||||
interrupt = 0;
|
||||
server.run(&interrupt); // Does the buffered RPC
|
||||
|
||||
string response;
|
||||
client.recvResp(&response);
|
||||
|
||||
TEST(response == sampleAddGoodResponseStream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class serverPstreamConnTestSuite : public testSuite {
|
||||
|
||||
public:
|
||||
@@ -97,14 +644,12 @@ public:
|
||||
return "serverPstreamConnTestSuite";
|
||||
}
|
||||
virtual void runtests(unsigned int const) {
|
||||
int const devNullFd(open("/dev/null", 0));
|
||||
|
||||
if (devNullFd < 0)
|
||||
throwf("Failed to open /dev/null, needed for test.");
|
||||
|
||||
registry myRegistry;
|
||||
|
||||
myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
|
||||
myRegistry.addMethod("sample.add",
|
||||
methodPtr(new sampleAddMethod));
|
||||
myRegistry.addMethod("test.callinfo",
|
||||
methodPtr(new testCallInfoMethod));
|
||||
|
||||
registryPtr myRegistryP(new registry);
|
||||
|
||||
@@ -125,43 +670,140 @@ public:
|
||||
.registryP(&myRegistry));
|
||||
);
|
||||
|
||||
EXPECT_ERROR( // No such file descriptor
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(37));
|
||||
);
|
||||
|
||||
{
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(devNullFd));
|
||||
testEmptyStream(myRegistry);
|
||||
|
||||
bool eof;
|
||||
server.runOnce(&eof);
|
||||
TEST(eof);
|
||||
}
|
||||
{
|
||||
int fd;
|
||||
createTestFile("junk", &fd);
|
||||
testBrokenPacket(myRegistry);
|
||||
|
||||
serverPstreamConn server(serverPstreamConn::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(fd));
|
||||
testEmptyPacket(myRegistry);
|
||||
|
||||
bool eof;
|
||||
testNormalCall(myRegistry);
|
||||
|
||||
EXPECT_ERROR( // EOF in the middle of a packet
|
||||
server.runOnce(&eof);
|
||||
);
|
||||
close(fd);
|
||||
}
|
||||
testNoWaitCall(myRegistry);
|
||||
|
||||
close(devNullFd);
|
||||
testMultiRpcRunNoRpc(myRegistry);
|
||||
|
||||
testMultiRpcRunOneRpc(myRegistry);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void
|
||||
testMultiConnInterrupt(registry const& myRegistry) {
|
||||
|
||||
// We use a nonexistent file descriptor, but the server won't
|
||||
// ever access it, so it won't know.
|
||||
|
||||
serverPstream server(serverPstream::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(37));
|
||||
|
||||
int interrupt(1); // interrupt immediately
|
||||
|
||||
server.runSerial(&interrupt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class derivedServer : public xmlrpc_c::serverPstream {
|
||||
public:
|
||||
derivedServer(serverPstream::constrOpt const& constrOpt) :
|
||||
serverPstream(constrOpt),
|
||||
info("this is my derived server") {}
|
||||
|
||||
string const info;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class multiTestCallInfoMethod : public method2 {
|
||||
|
||||
// The test isn't sophisticated enough actually to do an RPC, so this
|
||||
// code never runs. We just want to see if it compiles.
|
||||
|
||||
public:
|
||||
virtual void
|
||||
execute(paramList const& paramList,
|
||||
const callInfo * const callInfoPtr,
|
||||
value * const retvalP) {
|
||||
|
||||
const callInfo_serverPstream * const callInfoP(
|
||||
dynamic_cast<const callInfo_serverPstream *>(callInfoPtr));
|
||||
|
||||
TEST(callInfoP != NULL);
|
||||
|
||||
paramList.verifyEnd(0);
|
||||
|
||||
derivedServer * const derivedServerP(
|
||||
dynamic_cast<derivedServer *>(callInfoP->serverP));
|
||||
|
||||
TEST(derivedServerP->info == string("this is my derived server"));
|
||||
|
||||
TEST(callInfoP->clientAddr.sa_family == AF_INET);
|
||||
TEST(callInfoP->clientAddrSize >= sizeof(struct sockaddr_in));
|
||||
|
||||
*retvalP = value_nil();
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
testMultiConnCallInfo() {
|
||||
|
||||
registry myRegistry;
|
||||
|
||||
myRegistry.addMethod("testCallInfo",
|
||||
methodPtr(new multiTestCallInfoMethod));
|
||||
|
||||
derivedServer server(serverPstream::constrOpt()
|
||||
.registryP(&myRegistry)
|
||||
.socketFd(37));
|
||||
}
|
||||
|
||||
|
||||
|
||||
class multiConnServerTestSuite : public testSuite {
|
||||
|
||||
public:
|
||||
virtual string suiteName() {
|
||||
return "multiConnServerTestSuite";
|
||||
}
|
||||
virtual void runtests(unsigned int const) {
|
||||
registry myRegistry;
|
||||
|
||||
myRegistry.addMethod("sample.add",
|
||||
methodPtr(new sampleAddMethod));
|
||||
|
||||
registryPtr myRegistryP(new registry);
|
||||
|
||||
myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod));
|
||||
|
||||
EXPECT_ERROR( // Empty options
|
||||
serverPstream::constrOpt opt;
|
||||
serverPstream server(opt);
|
||||
);
|
||||
|
||||
EXPECT_ERROR( // No registry
|
||||
serverPstream server(serverPstream::constrOpt()
|
||||
.socketFd(3));
|
||||
);
|
||||
|
||||
EXPECT_ERROR( // No socket fd
|
||||
serverPstream server(serverPstream::constrOpt()
|
||||
.registryP(&myRegistry));
|
||||
);
|
||||
|
||||
testMultiConnInterrupt(myRegistry);
|
||||
|
||||
testMultiConnCallInfo();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
|
||||
string
|
||||
serverPstreamTestSuite::suiteName() {
|
||||
return "serverPstreamTestSuite";
|
||||
@@ -173,5 +815,6 @@ serverPstreamTestSuite::runtests(unsigned int const indentation) {
|
||||
|
||||
serverPstreamConnTestSuite().run(indentation + 1);
|
||||
|
||||
multiConnServerTestSuite().run(indentation + 1);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user