Files
pcas/src/libCom/test/blockingSockTest.cpp
2004-05-13 19:55:25 +00:00

262 lines
6.2 KiB
C++

#include <string.h>
#include <assert.h>
#include "osiSock.h"
#include "osiWireFormat.h"
#include "epicsThread.h"
#include "epicsSignal.h"
static SOCKET joltTestServerSock;
static SOCKET joltTestServerCircuitSock;
static SOCKET joltTestClientCircuitSock;
static bool blockingClientWakeup = false;
static bool blockingServerWakeup = false;
union address {
struct sockaddr_in ia;
struct sockaddr sa;
};
class circuit {
public:
circuit ( SOCKET );
void recvTest ();
void shutdown ();
void signal ();
void close ();
bool recvWakeupDetected () const;
bool sendWakeupDetected () const;
virtual const char * pName () = 0;
protected:
SOCKET sock;
epicsThreadId id;
bool recvWakeup;
bool sendWakeup;
};
class serverCircuit : public circuit {
public:
serverCircuit ( SOCKET );
private:
const char * pName ();
};
class clientCircuit : public circuit {
public:
clientCircuit ( const address & );
private:
const char * pName ();
};
class server {
public:
server ( const address & );
void daemon ();
protected:
SOCKET sock;
epicsThreadId id;
bool exit;
};
circuit::circuit ( SOCKET sockIn ) :
sock ( sockIn ),
id ( 0 ),
recvWakeup ( false ),
sendWakeup ( false )
{
assert ( this->sock != INVALID_SOCKET );
}
bool circuit::recvWakeupDetected () const
{
return this->recvWakeup;
}
bool circuit::sendWakeupDetected () const
{
return this->sendWakeup;
}
void circuit::shutdown ()
{
int status = ::shutdown ( this->sock, SHUT_RDWR );
assert ( status == 0 );
}
void circuit::signal ()
{
epicsSignalRaiseSigAlarm ( this->id );
}
void circuit::close ()
{
epicsSocketDestroy ( this->sock );
}
void circuit::recvTest ()
{
epicsSignalInstallSigAlarmIgnore ();
char buf [1];
while ( true ) {
int status = recv ( this->sock,
buf, (int) sizeof ( buf ), 0 );
if ( status == 0 ) {
printf ( "%s: %s was disconnected\n",
__FILE__, this->pName () );
this->recvWakeup = true;
break;
}
else if ( status > 0 ) {
printf ( "%s: client received %i characters\n",
__FILE__, status );
}
else {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
printf ( "%s: %s socket recv() error was \"%s\"\n",
__FILE__, this->pName (), sockErrBuf );
this->recvWakeup = true;
break;
}
}
}
void socketRecvTest ( void * pParm )
{
circuit * pCir = reinterpret_cast < circuit * > ( pParm );
pCir->recvTest ();
}
clientCircuit::clientCircuit ( const address & addrIn ) :
circuit ( epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) )
{
int status = ::connect (
this->sock, & addrIn.sa, sizeof ( addrIn ) );
assert ( status == 0 );
circuit * pCir = this;
this->id = epicsThreadCreate (
"client circuit", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
socketRecvTest, pCir );
assert ( this->id );
}
const char * clientCircuit::pName ()
{
return "client circuit";
}
void serverDaemon ( void * pParam ) {
server * pSrv = reinterpret_cast < server * > ( pParam );
pSrv->daemon ();
}
server::server ( const address & addrIn ) :
sock ( epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ),
id ( 0 ), exit ( false )
{
assert ( this->sock != INVALID_SOCKET );
// setup server side
int status = bind ( this->sock,
& addrIn.sa, sizeof ( addrIn ) );
assert ( status == 0 );
status = listen ( this->sock, 10 );
assert ( status == 0 );
this->id = epicsThreadCreate (
"server daemon", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
serverDaemon, this );
assert ( this->id );
}
void server::daemon ()
{
while ( ! this->exit ) {
// accept client side
address addr;
int addressSize = sizeof ( addr );
SOCKET ns = accept ( this->sock,
& addr.sa, & addressSize );
assert ( ns != INVALID_SOCKET );
new serverCircuit ( ns );
}
}
serverCircuit::serverCircuit ( SOCKET sockIn ) :
circuit ( sockIn )
{
circuit * pCir = this;
epicsThreadId id = epicsThreadCreate (
"server circuit", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
socketRecvTest, pCir );
assert ( id );
}
const char * serverCircuit::pName ()
{
return "server circuit";
}
void blockingSockTest ()
{
address addr;
memset ( (char *) & addr, 0, sizeof ( addr ) );
addr.ia.sin_family = AF_INET;
addr.ia.sin_addr.s_addr = epicsHTON32 ( INADDR_LOOPBACK );
//addr.ia.sin_addr.s_addr = epicsHTON32 ( 0x80A5A07F );
addr.ia.sin_port = epicsHTON16 ( 5064 ); // CA
server srv ( addr );
clientCircuit client ( addr );
epicsThreadSleep ( 1.0 );
assert ( ! blockingClientWakeup );
client.shutdown ();
epicsThreadSleep ( 1.0 );
char * pStr = "esscimqi_?????";
if ( client.recvWakeupDetected () ) {
pStr = "esscimqi_socketBothShutdownRequired";
}
else {
client.signal ();
epicsThreadSleep ( 1.0 );
if ( client.recvWakeupDetected () ) {
pStr = "esscimqi_socketSigAlarmRequired";
}
else {
client.close ();
epicsThreadSleep ( 1.0 );
if ( client.recvWakeupDetected () ) {
pStr = "esscimqi_socketCloseRequired";
}
else {
pStr = "esscimqi_?????";
}
}
}
printf ( "The local OS behaves like \"%s\".\n", pStr );
pStr = "esscimqi_?????";
switch ( epicsSocketSystemCallInterruptMechanismQuery() ) {
case esscimqi_socketCloseRequired:
pStr = "esscimqi_socketCloseRequired";
break;
case esscimqi_socketBothShutdownRequired:
pStr = "esscimqi_socketBothShutdownRequired";
break;
case esscimqi_socketSigAlarmRequired:
pStr = "esscimqi_socketSigAlarmRequired";
break;
}
printf ( "The epicsSocketSystemCallInterruptMechanismQuery() function returns\n\"%s\".\n",
pStr );
}