262 lines
6.2 KiB
C++
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 );
|
|
}
|