many, many changes

This commit is contained in:
Jeff Hill
2000-08-25 01:52:33 +00:00
parent 0bf430d822
commit f830e99e58
58 changed files with 6266 additions and 4410 deletions
+7 -2
View File
@@ -20,7 +20,7 @@ LIBSRCS += cacNotify.cpp
LIBSRCS += cacNotifyIO.cpp
LIBSRCS += cacServiceList.cpp
LIBSRCS += access.cpp
LIBSRCS += processThread.cpp
LIBSRCS += recvProcessThread.cpp
LIBSRCS += iocinf.cpp
LIBSRCS += convert.cpp
LIBSRCS += test_event.cpp
@@ -38,7 +38,6 @@ LIBSRCS += netReadNotifyIO.cpp
LIBSRCS += netWriteNotifyIO.cpp
LIBSRCS += netSubscription.cpp
LIBSRCS += cac.cpp
LIBSRCS += conn.cpp
LIBSRCS += tcpSendWatchdog.cpp
LIBSRCS += tcpRecvWatchdog.cpp
LIBSRCS += bhe.cpp
@@ -50,6 +49,12 @@ LIBSRCS += syncgrp.cpp
LIBSRCS += CASG.cpp
LIBSRCS += syncGroupNotify.cpp
LIBSRCS += localHostName.cpp
LIBSRCS += claimsPendingIIU.cpp
LIBSRCS += claimMsgCache.cpp
LIBSRCS += comQueRecv.cpp
LIBSRCS += comQueSend.cpp
LIBSRCS += cacPrivate.cpp
LIBSRCS += hostNameCache.cpp
LIBRARY=ca
+22 -18
View File
@@ -25,6 +25,7 @@
#include "iocinf.h"
#include "oldAccess.h"
#include "cac_IL.h"
threadPrivateId caClientContextId;
@@ -229,7 +230,7 @@ int epicsShareAPI ca_search_and_connect (const char *name_str, chid *chanptr,
int caStatus;
cac *pcac;
caStatus = fetchClientContext (&pcac);
caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
@@ -238,16 +239,23 @@ int epicsShareAPI ca_search_and_connect (const char *name_str, chid *chanptr,
return ECA_EMPTYSTR;
}
pChan = new oldChannel (conn_func, puser);
pChan = new oldChannel ( conn_func, puser );
if ( ! pChan ) {
return ECA_ALLOCMEM;
}
// we must set *chanptr here before we are 100% certain that
// the channel can be created in case *chanptr is inside
// of their structure at address puser and they reference
// it in a connection handler that is called by createChannelIO()
chid tmp = *chanptr;
*chanptr = pChan;
if ( pcac->createChannelIO ( name_str, *pChan ) ) {
*chanptr = pChan;
return ECA_NORMAL;
}
else {
*chanptr = tmp;
pChan->destroy ();
return ECA_ALLOCMEM;
}
@@ -428,7 +436,7 @@ int epicsShareAPI ca_pend (ca_real timeout, int early)
cac *pcac;
int status;
status = fetchClientContext (&pcac);
status = fetchClientContext ( &pcac );
if ( status != ECA_NORMAL ) {
return status;
}
@@ -660,16 +668,16 @@ int epicsShareAPI ca_replace_printf_handler (caPrintfFunc *ca_printf_func)
/*
* ca_printf()
*/
int ca_printf (const char *pformat, ...)
int ca_printf ( const char *pformat, ... )
{
va_list theArgs;
int status;
va_start (theArgs, pformat);
va_start ( theArgs, pformat );
status = ca_vPrintf (pformat, theArgs);
status = ca_vPrintf ( pformat, theArgs );
va_end (theArgs);
va_end ( theArgs );
return status;
}
@@ -677,31 +685,27 @@ int ca_printf (const char *pformat, ...)
/*
* ca_vPrintf()
*/
int ca_vPrintf (const char *pformat, va_list args)
int ca_vPrintf ( const char *pformat, va_list args )
{
caPrintfFunc *ca_printf_func;
if ( caClientContextId ) {
cac *pcac = (cac *) threadPrivateGet ( caClientContextId );
if (pcac) {
ca_printf_func = pcac->ca_printf_func;
if ( pcac ) {
return pcac->vPrintf ( pformat, args );
}
else {
ca_printf_func = errlogVprintf;
return ( *errlogVprintf ) ( pformat, args );
}
}
else {
ca_printf_func = errlogVprintf;
return ( *errlogVprintf ) ( pformat, args );
}
return (*ca_printf_func) ( pformat, args );
}
/*
* ca_field_type()
*/
short epicsShareAPI ca_field_type (chid pChan)
short epicsShareAPI ca_field_type ( chid pChan )
{
return pChan->nativeType ();
}
+1189 -1163
View File
File diff suppressed because it is too large Load Diff
+23 -5
View File
@@ -1,15 +1,33 @@
#include <stdio.h>
#include <stdlib.h>
#include "caDiagnostics.h"
int main(int argc, char **argv)
int main ( int argc, char **argv )
{
if(argc == 2){
acctst(argv[1]);
unsigned channelCount;
unsigned repetitionCount;
if ( argc < 2 || argc > 4 ) {
printf ( "usage: %s <chan name> [channel count] [repetition count]\n", argv[0] );
}
else{
printf("usage: %s <chan name>\n", argv[0]);
if ( argc >= 3 ) {
channelCount = atoi ( argv[2] );
}
else {
channelCount = 20000;
}
if ( argc >= 4 ) {
repetitionCount = atoi ( argv[3] );
}
else {
repetitionCount = 1;
}
acctst ( argv[1], channelCount, repetitionCount );
return 0;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef baseIIU_ILh
#define baseIIU_ILh
#endif // baseIIU_ILh
+9 -8
View File
@@ -11,20 +11,21 @@
*/
#include "iocinf.h"
#include "nciu_IL.h"
baseNMIU::baseNMIU ( nciu &chanIn ) : chan (chanIn)
baseNMIU::baseNMIU ( nciu &chanIn ) : chan ( chanIn )
{
this->chan.installIO ( *this );
}
void baseNMIU::destroy ()
{
delete this;
chanIn.ioInstall ( *this );
}
baseNMIU::~baseNMIU ()
{
this->chan.uninstallIO ( *this );
// private NOOP forces pool allocation
}
void baseNMIU::destroy ()
{
this->chan.ioDestroy ( this->getId () );
}
int baseNMIU::subscriptionMsg ()
+2 -2
View File
@@ -1,9 +1,9 @@
enum appendNumberFlag {appendNumber, dontAppendNumber};
int catime (char *channelName, unsigned channelCount, enum appendNumberFlag appNF);
int catime ( char *channelName, unsigned channelCount, enum appendNumberFlag appNF );
int acctst (char *pname);
int acctst ( char *pname, unsigned channelCount, unsigned repititionCount );
#define CATIME_OK 0
#define CATIME_ERROR -1
+13 -9
View File
@@ -74,14 +74,18 @@
* environment variables "EPICS_CA_REPEATER_PORT" and
* "EPICS_CA_SERVER_PORT"
*/
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u)
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u+1u)
/* 1492(min of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP) joh 8-6-97 */
#define ETHERNET_MAX_UDP (1482u-20u-8u)
#define MAX_UDP 1024u /* original MAX_UDP */
#define MAX_TCP (MAX_UDP*16u) /* so waveforms fit */
#define MAX_MSG_SIZE (MAX_TCP) /* the larger of tcp and udp max */
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u)
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u+1u)
/*
* 1500 (max of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
* (the MTU of Ethernet is currently independent of speed varient)
*/
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
#define MAX_UDP_SEND 1024u /* original MAX_UDP */
#define MAX_TCP ( 1024 * 16u ) /* so waveforms fit */
#define MAX_MSG_SIZE ( MAX_TCP ) /* the larger of tcp and udp max */
/*
* architecture independent types
@@ -118,7 +122,7 @@ typedef ca_uint32_t caResId;
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
#define REPEATER_REGISTER 24u /* registr for repeater fan out */
#define REPEATER_REGISTER 24u /* register for repeater fan out */
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
#define CA_PROTO_CLAIM_CIU_FAILED 26u /* unable to create chan resource in server */
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
-75
View File
@@ -1,75 +0,0 @@
/*
* caExtraEventLabor ()
*/
LOCAL void caExtraEventLabor (void *pArg)
{
cac *pcac = (cac *) pArg;
dbcaPutNotify *ppnb;
struct event_handler_args args;
while (TRUE) {
semTakeStatus semStatus;
/*
* independent lock used here in order to
* avoid any possibility of blocking
* the database (or indirectly blocking
* one client on another client).
*/
semStatus = semMutexTakeTimeout (pcac->localIIU.putNotifyLock, 60.0 /* sec */);
if (semStatus!=semTakeOK) {
ca_printf ("cac: put notify deadlock condition detected\n");
(*pcac->localIIU.pdbAdapter->p_db_post_extra_labor) (pcac->localIIU.evctx);
break;
}
ppnb = (dbcaPutNotify *) ellGet (&pcac->localIIU.putNotifyQue);
semMutexGive (pcac->localIIU.putNotifyLock);
/*
* break to loop exit
*/
if (!ppnb) {
break;
}
/*
* setup arguments and call user's function
*/
args.usr = ppnb->caUserArg;
args.chid = ppnb->dbPutNotify.usrPvt;
#error type must be an external type
args.type = ppnb->dbPutNotify.dbrType;
args.count = ppnb->dbPutNotify.nRequest;
args.dbr = NULL;
if (ppnb->dbPutNotify.status) {
if (ppnb->dbPutNotify.status == S_db_Blocked) {
args.status = ECA_PUTCBINPROG;
}
else {
args.status = ECA_PUTFAIL;
}
}
else {
args.status = ECA_NORMAL;
}
pcac->lock ();
(*ppnb->caUserCallback) (args);
pcac->unlock ();
ppnb->busy = FALSE;
}
/*
* wakeup the TCP thread if it is waiting for a cb to complete
*/
semBinaryGive (pcac->ca_blockSem);
}
+380 -195
View File
@@ -39,11 +39,11 @@ static void cacInitRecursionLock ( void * dummy )
// cac::cac ()
//
cac::cac ( bool enablePreemptiveCallbackIn ) :
beaconTable ( 1024 ),
endOfBCastList ( 0 ),
ipToAEngine ( "caIPAddrToAsciiEngine" ),
ioTable ( 1024 ),
chanTable ( 1024 ),
sgTable ( 128 ),
beaconTable ( 1024 ),
fdRegFunc ( 0 ),
fdRegArg ( 0 ),
pudpiiu ( 0 ),
@@ -81,8 +81,7 @@ cac::cac ( bool enablePreemptiveCallbackIn ) :
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
ellInit (&this->putCvrtBuf);
this->ca_printf_func = errlogVprintf;
this->pVPrintfFunc = errlogVprintf;
this->ca_exception_func = ca_default_exception_handler;
this->ca_exception_arg = NULL;
this->readSeq = 0u;
@@ -103,44 +102,41 @@ cac::cac ( bool enablePreemptiveCallbackIn ) :
if ( gunRet != osiGetUserNameSuccess ) {
tmp[0] = '\0';
}
len = strlen (tmp) + 1;
this->ca_pUserName = (char *) malloc ( len );
if ( ! this->ca_pUserName ) {
len = strlen ( tmp ) + 1;
this->pUserName = new char [len];
if ( ! this->pUserName ) {
semBinaryDestroy (this->ca_blockSem);
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
strncpy (this->ca_pUserName, tmp, len);
strncpy ( this->pUserName, tmp, len );
}
this->programBeginTime = osiTime::getCurrent ();
status = envGetDoubleConfigParam (&EPICS_CA_CONN_TMO, &this->ca_connectTMO);
if (status) {
this->ca_connectTMO = CA_CONN_VERIFY_PERIOD;
status = envGetDoubleConfigParam ( &EPICS_CA_CONN_TMO, &this->connTMO );
if ( status ) {
this->connTMO = CA_CONN_VERIFY_PERIOD;
ca_printf (
"EPICS \"%s\" float fetch failed\n",
"EPICS \"%s\" double fetch failed\n",
EPICS_CA_CONN_TMO.name);
ca_printf (
"Setting \"%s\" = %f\n",
"Defaulting \"%s\" = %f\n",
EPICS_CA_CONN_TMO.name,
this->ca_connectTMO);
this->connTMO);
}
this->ca_server_port =
envGetInetPortConfigParam (&EPICS_CA_SERVER_PORT, CA_SERVER_PORT);
//
// unfortunately, this must be created her in the
// unfortunately, this must be created here in the
// constructor, and not on demand (only when it is needed)
// because the enable reference count must be
// maintained whenever this object exists.
//
this->pProcThread = new processThread ( this );
if ( ! this->pProcThread ) {
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
this->pRecvProcThread = new recvProcessThread ( this );
if ( ! this->pRecvProcThread ) {
throwWithLocation ( caErrorCode ( ECA_ALLOCMEM ) );
}
else if ( this->enablePreemptiveCallback ) {
// only after this->pProcThread is valid
// only after this->pRecvProcThread is valid
this->enableCallbackPreemption ();
}
}
@@ -170,19 +166,15 @@ cac::~cac ()
// make certain that process thread isnt deleting
// tcpiiu objects at the same that this thread is
//
delete this->pProcThread;
recvProcessThread *pTmp = this->pRecvProcThread;
this->pRecvProcThread = 0;
delete pTmp;
//
// shutdown all tcp connections and wait for threads to exit
//
this->iiuListMutex.lock ();
tsDLIterBD <tcpiiu> piiu ( this->iiuListIdle.first () );
while ( piiu.valid () ) {
tsDLIterBD <tcpiiu> pnext = piiu.itemAfter ();
piiu->suicide ();
piiu = pnext;
}
piiu = this->iiuListRecvPending.first ();
tsDLIterBD <tcpiiu> piiu ( this->iiuList.first () );
while ( piiu.valid () ) {
tsDLIterBD <tcpiiu> pnext = piiu.itemAfter ();
piiu->suicide ();
@@ -207,21 +199,17 @@ cac::~cac ()
delete this->pudpiiu;
}
/* remove put convert block free list */
ellFree ( &this->putCvrtBuf );
/* reclaim sync group resources */
this->sgTable.destroyAllEntries ();
/*
* free user name string
*/
if ( this->ca_pUserName ) {
free ( this->ca_pUserName );
if ( this->pUserName ) {
delete [] this->pUserName;
}
this->sgTable.destroyAllEntries ();
this->beaconTable.destroyAllEntries ();
this->chanTable.destroyAllEntries ();
this->ioTable.destroyAllEntries ();
semBinaryDestroy ( this->ca_blockSem );
osiSockRelease ();
@@ -229,59 +217,18 @@ cac::~cac ()
delete this->pTimerQueue;
}
void cac::safeDestroyNMIU (unsigned id)
{
this->defaultMutex.lock ();
baseNMIU *pIOBlock = this->ioTable.lookup (id);
if ( pIOBlock ) {
pIOBlock->destroy ();
}
this->defaultMutex.unlock ();
}
void cac::processRecvBacklog ()
{
tcpiiu *piiu;
this->iiuListMutex.lock ();
while ( 1 ) {
int status;
unsigned bytesToProcess;
tsDLIterBD <tcpiiu> piiu ( this->iiuList.first () );
while ( piiu.valid () ) {
tsDLIterBD <tcpiiu> pNext = piiu.itemAfter ();
piiu->processIncomingAndDestroySelfIfDisconnected ();
piiu = pNext;
}
this->iiuListMutex.lock ();
piiu = this->iiuListRecvPending.get ();
if ( ! piiu ) {
this->iiuListMutex.unlock ();
break;
}
piiu->recvPending = false;
this->iiuListIdle.add (*piiu);
this->iiuListMutex.unlock ();
if ( piiu->state == iiu_disconnected ) {
delete piiu;
continue;
}
char *pProto = (char *) cacRingBufferReadReserveNoBlock
(&piiu->recv, &bytesToProcess);
while ( pProto ) {
status = piiu->post_msg (pProto, bytesToProcess);
if ( status == ECA_NORMAL ) {
cacRingBufferReadCommit (&piiu->recv, bytesToProcess);
cacRingBufferReadFlush (&piiu->recv);
}
else {
delete piiu;
}
pProto = (char *) cacRingBufferReadReserveNoBlock
(&piiu->recv, &bytesToProcess);
}
}
this->iiuListMutex.unlock ();
}
/*
@@ -293,12 +240,7 @@ void cac::flush ()
* set the push pending flag on all virtual circuits
*/
this->iiuListMutex.lock ();
tsDLIterBD<tcpiiu> piiu ( this->iiuListIdle.first () );
while ( piiu.valid () ) {
piiu->flush ();
piiu++;
}
piiu = this->iiuListRecvPending.first ();
tsDLIterBD <tcpiiu> piiu ( this->iiuList.first () );
while ( piiu.valid () ) {
piiu->flush ();
piiu++;
@@ -317,69 +259,47 @@ void cac::flush ()
*/
void cac::cleanUpPendIO ()
{
nciu *pchan;
this->defaultMutex.lock ();
this->readSeq++;
this->pndrecvcnt = 0u;
if ( this->pudpiiu ) {
tsDLIter <nciu> iter ( this->pudpiiu->chidList );
while ( ( pchan = iter () ) ) {
pchan->connectTimeoutNotify ();
}
}
this->defaultMutex.unlock ();
if ( this->pudpiiu ) {
this->pudpiiu->connectTimeoutNotify ();
}
}
unsigned cac::connectionCount () const
{
unsigned count;
this->iiuListMutex.lock ();
count = this->iiuListIdle.count () + this->iiuListRecvPending.count ();
this->iiuListMutex.unlock ();
return count;
return this->iiuList.count ();
}
void cac::show (unsigned level) const
{
this->defaultMutex.lock ();
if ( this->pudpiiu ) {
this->pudpiiu->show (level);
}
this->iiuListMutex.lock ();
tsDLIterConstBD <tcpiiu> piiu ( this->iiuListIdle.first () );
while ( piiu.valid () ) {
piiu->show (level);
piiu++;
}
piiu = this->iiuListRecvPending.first ();
tsDLIterConstBD <tcpiiu> piiu ( this->iiuList.first () );
while ( piiu.valid () ) {
piiu->show (level);
piiu++;
}
this->iiuListMutex.unlock ();
this->defaultMutex.unlock ();
}
void cac::installIIU ( tcpiiu &iiu )
{
this->iiuListMutex.lock ();
iiu.recvPending = false;
this->iiuListIdle.add (iiu);
this->iiuList.add (iiu);
this->iiuListMutex.unlock ();
this->defaultMutex.lock ();
if ( ! this->enablePreemptiveCallback && this->fdRegFunc ) {
( * this->fdRegFunc )
( (void *) this->fdRegArg, iiu.getSock (), TRUE );
@@ -387,33 +307,14 @@ void cac::installIIU ( tcpiiu &iiu )
this->defaultMutex.unlock ();
}
void cac::signalRecvActivityIIU (tcpiiu &iiu)
void cac::signalRecvActivity ()
{
bool change;
this->iiuListMutex.lock ();
if ( iiu.recvPending ) {
change = false;
}
else {
this->iiuListIdle.remove (iiu);
this->iiuListRecvPending.add (iiu);
iiu.recvPending = true;
change = true;
}
this->iiuListMutex.unlock ();
//
// wakeup after unlock improves performance
//
if (change) {
this->recvActivity.signal ();
if ( this->pRecvProcThread ) {
this->pRecvProcThread->signalActivity ();
}
}
void cac::removeIIU (tcpiiu &iiu)
void cac::removeIIU ( tcpiiu &iiu )
{
this->defaultMutex.lock ();
osiSockAddr addr = iiu.address ();
@@ -430,12 +331,7 @@ void cac::removeIIU (tcpiiu &iiu)
this->iiuListMutex.lock ();
if ( iiu.recvPending ) {
this->iiuListRecvPending.remove (iiu);
}
else {
this->iiuListIdle.remove (iiu);
}
this->iiuList.remove (iiu);
if ( ! this->enablePreemptiveCallback ) {
if ( this->fdRegFunc ) {
@@ -543,6 +439,7 @@ void cac::beaconNotify ( const inetAddrID &addr )
status = getsockname ( this->pudpiiu->getSock (), (struct sockaddr *) &saddr, &saddr_length );
if ( status < 0 ) {
epicsPrintf ( "CAC: getsockname () error was \"%s\"\n", SOCKERRSTR (SOCKERRNO) );
this->defaultMutex.unlock ();
return;
}
port = ntohs ( saddr.sin_port );
@@ -560,22 +457,14 @@ void cac::beaconNotify ( const inetAddrID &addr )
}
}
/*
* set retry count of all disconnected channels
* to zero
*/
tsDLIterBD <nciu> iter ( this->pudpiiu->chidList.first () );
while ( iter.valid () ) {
iter->retry = 0u;
iter++;
}
this->defaultMutex.unlock ();
this->pudpiiu->resetChannelRetryCounts ();
# if DEBUG
{
char buf[64];
ipAddrToA (pnet_addr, buf, sizeof (buf) );
ipAddrToA (pnet_addr, buf, sizeof ( buf ) );
printf ("new server available: %s\n", buf);
}
# endif
@@ -596,28 +485,53 @@ void cac::removeBeaconInetAddr (const inetAddrID &ina)
assert (pBHE);
}
void cac::decrementOutstandingIO (unsigned seqNumber)
void cac::decrementOutstandingIO ( unsigned seqNumber )
{
bool signalNeeded;
this->defaultMutex.lock ();
if ( this->readSeq == seqNumber ) {
if ( this->pndrecvcnt > 0u ) {
this->pndrecvcnt--;
if ( this->pndrecvcnt == 0u ) {
signalNeeded = true;
}
else {
signalNeeded = false;
}
}
else {
signalNeeded = true;
}
}
else {
signalNeeded = true;
}
this->defaultMutex.unlock ();
if ( this->pndrecvcnt == 0u ) {
if ( signalNeeded ) {
this->ioDone.signal ();
}
}
void cac::decrementOutstandingIO ()
{
bool signalNeeded;
this->defaultMutex.lock ();
if ( this->pndrecvcnt > 0u ) {
this->pndrecvcnt--;
if ( this->pndrecvcnt == 0u ) {
signalNeeded = true;
}
else {
signalNeeded = false;
}
}
else {
signalNeeded = true;
}
this->defaultMutex.unlock ();
if ( this->pndrecvcnt == 0u ) {
if ( signalNeeded ) {
this->ioDone.signal ();
}
}
@@ -734,26 +648,150 @@ bool cac::ioComplete () const
}
}
void cac::installIO ( baseNMIU &io )
void cac::ioInstall ( nciu &chan, baseNMIU &io )
{
this->defaultMutex.lock ();
this->ioTable.add ( io );
chan.cacPrivate::eventq.add ( io );
this->defaultMutex.unlock ();
}
void cac::uninstallIO ( baseNMIU &io )
void cac::ioDestroy ( unsigned id )
{
this->defaultMutex.lock ();
this->ioTable.remove ( io );
baseNMIU * pmiu = this->ioTable.remove ( id );
if ( pmiu ) {
pmiu->chan.cacPrivate::eventq.remove ( *pmiu );
}
this->defaultMutex.unlock ();
// care is taken to not destroy with the cac lock
// applied because we could potentially hold the
// cac lock while sending and deadlock with the
// recv thread, but we must uninstall the IO
// before accessing it with the lock released
if ( pmiu ) {
pmiu->destroy ();
}
}
baseNMIU * cac::lookupIO (unsigned id)
void cac::ioCompletionNotify ( unsigned id )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.lookup ( id );
if ( pmiu ) {
pmiu->completionNotify ();
}
this->defaultMutex.unlock ();
return pmiu;
}
void cac::ioCompletionNotify ( unsigned id, unsigned type,
unsigned long count, const void *pData )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.lookup ( id );
if ( pmiu ) {
pmiu->completionNotify ( type, count, pData );
}
this->defaultMutex.unlock ();
}
void cac::ioExceptionNotify ( unsigned id, int status, const char *pContext )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.lookup ( id );
if ( pmiu ) {
pmiu->exceptionNotify ( status, pContext );
}
this->defaultMutex.unlock ();
}
void cac::ioExceptionNotify ( unsigned id, int status,
const char *pContext, unsigned type, unsigned long count )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.lookup ( id );
if ( pmiu ) {
pmiu->exceptionNotify ( status, pContext, type, count );
}
this->defaultMutex.unlock ();
}
void cac::ioCompletionNotifyAndDestroy ( unsigned id )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.remove ( id );
if ( pmiu ) {
pmiu->chan.cacPrivate::eventq.remove ( *pmiu );
}
this->defaultMutex.unlock ();
// care is taken to not destroy with the cac lock
// applied because we could potentially hold the
// cac lock while sending and deadlock with the
// recv thread, but we must uninstall the IO
// before accessing it with the lock released
if ( pmiu ) {
pmiu->completionNotify ();
pmiu->destroy ();
}
}
void cac::ioCompletionNotifyAndDestroy ( unsigned id,
unsigned type, unsigned long count, const void *pData )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.remove ( id );
if ( pmiu ) {
pmiu->chan.cacPrivate::eventq.remove ( *pmiu );
}
this->defaultMutex.unlock ();
// care is taken to not destroy with the cac lock
// applied because we could potentially hold the
// cac lock while sending and deadlock with the
// recv thread, but we must uninstall the IO
// before accessing it with the lock released
if ( pmiu ) {
pmiu->completionNotify ( type, count, pData );
pmiu->destroy ();
}
}
void cac::ioExceptionNotifyAndDestroy ( unsigned id, int status, const char *pContext )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.remove ( id );
if ( pmiu ) {
pmiu->chan.cacPrivate::eventq.remove ( *pmiu );
}
this->defaultMutex.unlock ();
// care is taken to not destroy with the cac lock
// applied because we could potentially hold the
// cac lock while sending and deadlock with the
// recv thread, but we must uninstall the IO
// before accessing it with the lock released
if ( pmiu ) {
pmiu->exceptionNotify ( status, pContext );
pmiu->destroy ();
}
}
void cac::ioExceptionNotifyAndDestroy ( unsigned id, int status,
const char *pContext, unsigned type, unsigned long count )
{
this->defaultMutex.lock ();
baseNMIU * pmiu = this->ioTable.remove ( id );
if ( pmiu ) {
pmiu->chan.cacPrivate::eventq.remove ( *pmiu );
}
this->defaultMutex.unlock ();
// care is taken to not destroy with the cac lock
// applied because we could potentially hold the
// cac lock while sending and deadlock with the
// recv thread, but we must uninstall the IO
// before accessing it with the lock released
if ( pmiu ) {
pmiu->exceptionNotify ( status, pContext, type, count );
pmiu->destroy ();
}
}
void cac::registerChannel (nciu &chan)
@@ -763,19 +801,59 @@ void cac::registerChannel (nciu &chan)
this->defaultMutex.unlock ();
}
void cac::unregisterChannel (nciu &chan)
void cac::unregisterChannel ( nciu &chan )
{
this->defaultMutex.lock ();
this->chanTable.remove ( chan );
this->defaultMutex.unlock ();
}
nciu * cac::lookupChan (unsigned id)
void cac::accessRightsNotify ( unsigned id, caar ar )
{
this->defaultMutex.lock ();
nciu * pchan = this->chanTable.lookup ( id );
nciu * pChan = this->chanTable.lookup ( id );
if ( pChan ) {
pChan->accessRightsStateChange ( ar );
}
this->defaultMutex.unlock ();
}
void cac::connectChannel ( unsigned id, class tcpiiu &iiu,
unsigned nativeType, unsigned long nativeCount, unsigned sid )
{
this->defaultMutex.lock ();
nciu * pChan = this->chanTable.lookup ( id );
if ( pChan ) {
unsigned sidTmp;
if ( iiu.ca_v44_ok () ) {
sidTmp = sid;
}
else {
sidTmp = pChan->getSID ();
}
pChan->connect ( iiu, nativeType, nativeCount, sidTmp );
}
this->defaultMutex.unlock ();
}
void cac::channelDestroy ( unsigned id )
{
this->defaultMutex.lock ();
nciu * pChan = this->chanTable.lookup ( id );
if ( pChan ) {
pChan->destroy ();
}
this->defaultMutex.unlock ();
}
void cac::disconnectChannel ( unsigned id )
{
this->defaultMutex.lock ();
nciu * pChan = this->chanTable.lookup ( id );
if ( pChan ) {
pChan->disconnect ();
}
this->defaultMutex.unlock ();
return pchan;
}
void cac::installCASG (CASG &sg)
@@ -837,7 +915,7 @@ bool cac::createChannelIO (const char *pName, cacChannel &chan)
return false;
}
}
nciu *pNetChan = new nciu ( this, chan, pName );
nciu *pNetChan = new nciu ( *this, chan, pName );
if ( pNetChan ) {
if ( ! pNetChan->fullyConstructed () ) {
pNetChan->destroy ();
@@ -867,7 +945,7 @@ bool cac::setupUDP ()
return true;
}
this->pudpiiu = new udpiiu ( this );
this->pudpiiu = new udpiiu ( *this );
if ( ! this->pudpiiu ) {
this->defaultMutex.unlock ();
return false;
@@ -877,6 +955,7 @@ bool cac::setupUDP ()
if ( ! this->pSearchTmr ) {
delete this->pudpiiu;
this->pudpiiu = 0;
this->defaultMutex.unlock ();
return false;
}
@@ -901,16 +980,6 @@ bool cac::setupUDP ()
return true;
}
void cac::lock () const
{
this->defaultMutex.lock ();
}
void cac::unlock () const
{
this->defaultMutex.unlock ();
}
void cac::registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg )
{
this->defaultMutex.lock ();
@@ -921,12 +990,16 @@ void cac::registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg )
void cac::enableCallbackPreemption ()
{
this->pProcThread->enable ();
if ( this->pRecvProcThread ) {
this->pRecvProcThread->enable ();
}
}
void cac::disableCallbackPreemption ()
{
this->pProcThread->disable ();
if ( this->pRecvProcThread ) {
this->pRecvProcThread->disable ();
}
}
void cac::changeExceptionEvent ( caExceptionHandler *pfunc, void *arg )
@@ -980,10 +1053,9 @@ void cac::installDisconnectedChannel ( nciu &chan )
assert ( this->pudpiiu && this->pSearchTmr );
this->defaultMutex.lock ();
this->pudpiiu->addToChanList ( chan );
chan.attachChanToIIU ( *this->pudpiiu );
chan.resetRetryCount ();
this->pSearchTmr->reset ( CA_RECAST_DELAY );
this->defaultMutex.unlock ();
}
void cac::notifySearchResponse ( unsigned short retrySeqNo )
@@ -1004,10 +1076,123 @@ void cac::replaceErrLogHandler ( caPrintfFunc *ca_printf_func )
{
this->defaultMutex.lock ();
if ( ca_printf_func ) {
this->ca_printf_func = ca_printf_func;
this->pVPrintfFunc = ca_printf_func;
}
else {
this->ca_printf_func = epicsVprintf;
this->pVPrintfFunc = epicsVprintf;
}
this->defaultMutex.unlock ();
}
}
/*
* constructTCPIIU ()
*/
tcpiiu * cac::constructTCPIIU ( const osiSockAddr &addr, unsigned minorVersion )
{
bhe *pBHE;
tcpiiu *piiu;
if ( addr.sa.sa_family != AF_INET ) {
return 0u;
}
/*
* look for an existing virtual circuit
*/
this->defaultMutex.lock ();
pBHE = this->lookupBeaconInetAddr ( addr.ia );
if ( ! pBHE ) {
pBHE = this->createBeaconHashEntry ( addr.ia, osiTime () );
if ( ! pBHE ) {
this->defaultMutex.unlock ();
return NULL;
}
}
piiu = pBHE->getIIU ();
if ( piiu ) {
if ( piiu->alive () ) {
this->defaultMutex.unlock ();
return piiu;
}
else {
this->defaultMutex.unlock ();
return NULL;
}
}
this->defaultMutex.unlock ();
piiu = new tcpiiu ( *this, addr, minorVersion,
*pBHE, this->connTMO, *this->pTimerQueue,
this->ipToAEngine );
if ( ! piiu ) {
return NULL;
}
if ( piiu->fullyConstructed () ) {
return piiu;
}
else {
delete piiu;
return NULL;
}
}
void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
unsigned typeCode, unsigned long count,
unsigned minorVersionNumber, const osiSockAddr &addr )
{
unsigned retrySeqNumber;
tcpiiu *allocpiiu;
{
this->defaultMutex.lock ();
nciu *chan;
/*
* ignore search replies for deleted channels
*/
chan = this->chanTable.lookup ( cid );
if ( ! chan ) {
this->defaultMutex.unlock ();
return;
}
retrySeqNumber = chan->getRetrySeqNo ();
/*
* Ignore duplicate search replies
*/
if ( chan->connectionInProgress ( addr ) ) {
this->defaultMutex.unlock ();
return;
}
allocpiiu = this->constructTCPIIU ( addr, minorVersionNumber );
if ( ! allocpiiu ) {
this->defaultMutex.unlock ();
return;
}
/*
* remove it from the broadcast niiu
*/
chan->searchReplySetUp ( sid, typeCode, count );
allocpiiu->installChannelPendingClaim ( *chan );
this->defaultMutex.unlock ();
}
this->notifySearchResponse ( retrySeqNumber );
return;
}
bool cac::currentThreadIsRecvProcessThread ()
{
if ( this->pRecvProcThread ) {
return this->pRecvProcThread->isCurrentThread ();
}
else {
return false;
}
}
+70 -47
View File
@@ -23,8 +23,9 @@ cacChannel::cacChannel () : pChannelIO (0)
cacChannel::~cacChannel ()
{
if ( this->pChannelIO ) {
this->pChannelIO->destroy ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
pIO->destroy ();
}
}
@@ -37,8 +38,9 @@ void cacChannel::attachIO (cacChannelIO &io)
int cacChannel::read ( unsigned type, unsigned long count, cacNotify & notify )
{
if ( this->pChannelIO ) {
return pChannelIO->read (type, count, notify);
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->read ( type, count, notify );
}
else {
return ECA_DISCONNCHID;
@@ -47,8 +49,9 @@ int cacChannel::read ( unsigned type, unsigned long count, cacNotify & notify )
int cacChannel::read ( unsigned type, unsigned long count, void *pValue )
{
if ( this->pChannelIO ) {
return pChannelIO->read (type, count, pValue);
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->read ( type, count, pValue );
}
else {
return ECA_DISCONNCHID;
@@ -57,8 +60,9 @@ int cacChannel::read ( unsigned type, unsigned long count, void *pValue )
int cacChannel::write (unsigned type, unsigned long count, const void *pvalue )
{
if ( this->pChannelIO ) {
return pChannelIO->write (type, count, pvalue);
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->write (type, count, pvalue);
}
else {
return ECA_DISCONNCHID;
@@ -68,8 +72,9 @@ int cacChannel::write (unsigned type, unsigned long count, const void *pvalue )
int cacChannel::write (unsigned type, unsigned long count,
const void *pvalue, cacNotify & notify )
{
if ( this->pChannelIO ) {
return pChannelIO->write (type, count, pvalue, notify);
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->write (type, count, pvalue, notify);
}
else {
return ECA_DISCONNCHID;
@@ -79,8 +84,9 @@ int cacChannel::write (unsigned type, unsigned long count,
int cacChannel::subscribe ( unsigned type, unsigned long count,
unsigned mask, cacNotify &notify )
{
if ( this->pChannelIO ) {
return pChannelIO->subscribe (type, count, mask, notify);
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->subscribe (type, count, mask, notify);
}
else {
return ECA_DISCONNCHID;
@@ -90,8 +96,9 @@ int cacChannel::subscribe ( unsigned type, unsigned long count,
void cacChannel::hostName ( char *pBuf, unsigned bufLength ) const
{
if ( bufLength ) {
if ( this->pChannelIO ) {
pChannelIO->hostName (pBuf, bufLength);
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
pIO->hostName (pBuf, bufLength);
}
else {
strncpy ( pBuf, "<not connected>", bufLength );
@@ -102,8 +109,9 @@ void cacChannel::hostName ( char *pBuf, unsigned bufLength ) const
const char * cacChannel::pHostName () const
{
if ( this->pChannelIO ) {
return pChannelIO->pHostName ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->pHostName ();
}
else {
return "<not connected>";
@@ -112,8 +120,9 @@ const char * cacChannel::pHostName () const
short cacChannel::nativeType () const
{
if ( this->pChannelIO ) {
return pChannelIO->nativeType ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->nativeType ();
}
else {
return TYPENOTCONN;
@@ -122,8 +131,9 @@ short cacChannel::nativeType () const
unsigned long cacChannel::nativeElementCount () const
{
if ( this->pChannelIO ) {
return pChannelIO->nativeElementCount ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->nativeElementCount ();
}
else {
return 0ul;
@@ -132,8 +142,9 @@ unsigned long cacChannel::nativeElementCount () const
channel_state cacChannel::state () const
{
if ( this->pChannelIO ) {
return pChannelIO->state ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->state ();
}
else {
return cs_never_conn;
@@ -142,8 +153,9 @@ channel_state cacChannel::state () const
bool cacChannel::readAccess () const
{
if ( this->pChannelIO ) {
caar ar = pChannelIO->accessRights ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
caar ar = pIO->accessRights ();
return ar.read_access;
}
else {
@@ -153,7 +165,8 @@ bool cacChannel::readAccess () const
bool cacChannel::writeAccess () const
{
if ( this->pChannelIO ) {
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
caar ar = pChannelIO->accessRights ();
return ar.write_access;
}
@@ -164,8 +177,9 @@ bool cacChannel::writeAccess () const
const char *cacChannel::pName () const
{
if ( this->pChannelIO ) {
return pChannelIO->pName ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->pName ();
}
else {
return "<disconnected>";
@@ -174,8 +188,9 @@ const char *cacChannel::pName () const
unsigned cacChannel::searchAttempts () const
{
if ( this->pChannelIO ) {
return pChannelIO->searchAttempts ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->searchAttempts ();
}
else {
return 0u;
@@ -184,8 +199,9 @@ unsigned cacChannel::searchAttempts () const
bool cacChannel::ca_v42_ok () const
{
if ( this->pChannelIO ) {
return pChannelIO->ca_v42_ok ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->ca_v42_ok ();
}
else {
return false;
@@ -194,8 +210,9 @@ bool cacChannel::ca_v42_ok () const
bool cacChannel::connected () const
{
if ( this->pChannelIO ) {
return pChannelIO->connected ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->connected ();
}
else {
return false;
@@ -204,8 +221,9 @@ bool cacChannel::connected () const
caar cacChannel::accessRights () const
{
if ( this->pChannelIO ) {
return pChannelIO->accessRights ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->accessRights ();
}
else {
caar ar;
@@ -246,8 +264,9 @@ void cacChannel::connectTimeoutNotify ()
unsigned cacChannel::readSequence () const
{
if ( this->pChannelIO ) {
return this->pChannelIO->readSequence ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
return pIO->readSequence ();
}
else {
return 0u;
@@ -256,28 +275,32 @@ unsigned cacChannel::readSequence () const
void cacChannel::decrementOutstandingIO ()
{
if ( this->pChannelIO ) {
this->pChannelIO->decrementOutstandingIO ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
pIO->decrementOutstandingIO ();
}
}
void cacChannel::incrementOutstandingIO ()
{
if ( this->pChannelIO ) {
this->pChannelIO->incrementOutstandingIO ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
pIO->incrementOutstandingIO ();
}
}
void cacChannel::lock () const
void cacChannel::lockOutstandingIO () const
{
if ( this->pChannelIO ) {
this->pChannelIO->lock ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
pIO->lockOutstandingIO ();
}
}
void cacChannel::unlock () const
void cacChannel::unlockOutstandingIO () const
{
if ( this->pChannelIO ) {
this->pChannelIO->unlock ();
cacChannelIO *pIO = this->pChannelIO;
if ( pIO ) {
pIO->unlockOutstandingIO ();
}
}
+8
View File
@@ -107,4 +107,12 @@ void cacChannelIO::decrementOutstandingIO ()
{
}
void cacChannelIO::lockOutstandingIO () const
{
}
void cacChannelIO::unlockOutstandingIO () const
{
}
+7 -7
View File
@@ -86,8 +86,8 @@ public:
protected:
class cacChannelIO *pChannelIO;
void lock () const;
void unlock () const;
void lockOutstandingIO () const;
void unlockOutstandingIO () const;
private:
virtual void ioAttachNotify ();
@@ -116,8 +116,8 @@ public:
virtual const char *pName () const = 0;
virtual void lock () const = 0;
virtual void unlock () const = 0;
virtual void lockOutstandingIO () const = 0;
virtual void unlockOutstandingIO () const = 0;
private:
virtual int read ( unsigned type, unsigned long count, void *pValue) = 0;
@@ -143,11 +143,11 @@ private:
friend class cacChannel;
};
class epicsShareClass cacLocalChannelIO :
class cacLocalChannelIO :
public cacChannelIO, public tsDLNode <cacLocalChannelIO> {
public:
cacLocalChannelIO ( cacChannel &chan );
virtual ~cacLocalChannelIO () = 0;
epicsShareFunc cacLocalChannelIO ( cacChannel &chan );
epicsShareFunc virtual ~cacLocalChannelIO () = 0;
};
struct cacServiceIO : public tsDLNode <cacServiceIO> {
+80
View File
@@ -0,0 +1,80 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include "iocinf.h"
cacPrivate::cacPrivate ( cac &cacIn ) :
cacCtx ( cacIn )
{
}
// Destroy all IO blocks attached.
// Care is taken here not to hold the lock while
// sending a subscription delete message (which
// would result in deadlocks)
void cacPrivate::destroyAllIO ()
{
while ( true ) {
unsigned id;
bool done;
this->cacCtx.defaultMutex.lock ();
{
baseNMIU *pNMIU = this->eventq.first ();
if ( pNMIU ) {
id = pNMIU->getId ();
done = false;
}
else {
done = true;
}
}
this->cacCtx.defaultMutex.unlock ();
if ( done ) {
break;
}
// care is taken to not hold a lock when
// executing this
this->cacCtx.ioDestroy ( id );
}
}
// resubscribe for monitors from this channel
void cacPrivate::subscribeAllIO ()
{
this->cacCtx.defaultMutex.lock ();
tsDLIterBD < baseNMIU > iter = this->eventq.first ();
while ( iter.valid () ) {
iter->subscriptionMsg ();
iter++;
}
this->cacCtx.defaultMutex.unlock ();
}
// cancel IO operations and monitor subscriptions
void cacPrivate::disconnectAllIO ( const char *pHostName )
{
this->cacCtx.defaultMutex.lock ();
tsDLIterBD < baseNMIU > iter = this->eventq.first ();
while ( iter.valid () ) {
tsDLIterBD < baseNMIU > next = iter.itemAfter ();
iter->disconnect ( pHostName );
iter = next;
}
this->cacCtx.defaultMutex.unlock ();
}
+55
View File
@@ -0,0 +1,55 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
inline int cac::vPrintf ( const char *pformat, va_list args )
{
return ( *this->pVPrintfFunc ) ( pformat, args );
}
inline int cac::printf ( const char *pformat, ... )
{
va_list theArgs;
int status;
va_start ( theArgs, pformat );
status = this->vPrintf ( pformat, theArgs );
va_end ( theArgs );
return status;
}
inline double cac::connectionTimeout () const
{
return this->connTMO;
}
inline const char * cac::userNamePointer ()
{
return this->pUserName;
}
inline void cac::lockOutstandingIO () const
{
this->defaultMutex.lock ();
}
inline void cac::unlockOutstandingIO () const
{
this->defaultMutex.unlock ();
}
+2 -1
View File
@@ -37,7 +37,6 @@
# endif
#endif
#include "ellLib.h"
#include "osiThread.h"
#include "shareLib.h"
#include "caerr.h"
@@ -719,6 +718,8 @@ epicsShareFunc void epicsShareAPI ca_signal_formated (long ca_status, const char
* ca_host_name_function()
*
* channel R channel identifier
*
* !!!! this function is _not_ thread safe !!!!
*/
epicsShareFunc const char * epicsShareAPI ca_host_name (chid channel);
/* thread safe version */
+38 -40
View File
@@ -28,7 +28,7 @@
#define CA_M_MSG_NO 0x0000FFF8
#define CA_M_SEVERITY 0x00000007
#define CA_M_LEVEL 0x00000003
#define CA_M_LEVEL 0x00000003
#define CA_M_SUCCESS 0x00000001
#define CA_M_ERROR 0x00000002
#define CA_M_SEVERE 0x00000004
@@ -62,42 +62,42 @@
#define ECA_NORMAL DEFMSG(CA_K_SUCCESS, 0)
#define ECA_MAXIOC DEFMSG(CA_K_ERROR, 1)
#define ECA_UKNHOST DEFMSG(CA_K_ERROR, 2)
#define ECA_UKNSERV DEFMSG(CA_K_ERROR, 3)
#define ECA_SOCK DEFMSG(CA_K_ERROR, 4)
#define ECA_MAXIOC DEFMSG(CA_K_ERROR, 1)
#define ECA_UKNHOST DEFMSG(CA_K_ERROR, 2)
#define ECA_UKNSERV DEFMSG(CA_K_ERROR, 3)
#define ECA_SOCK DEFMSG(CA_K_ERROR, 4)
#define ECA_CONN DEFMSG(CA_K_WARNING, 5)
#define ECA_ALLOCMEM DEFMSG(CA_K_WARNING, 6)
#define ECA_UKNCHAN DEFMSG(CA_K_WARNING, 7)
#define ECA_UKNFIELD DEFMSG(CA_K_WARNING, 8)
#define ECA_TOLARGE DEFMSG(CA_K_ERROR, 9)
#define ECA_TIMEOUT DEFMSG(CA_K_WARNING, 10)
#define ECA_NOSUPPORT DEFMSG(CA_K_WARNING, 11)
#define ECA_STRTOBIG DEFMSG(CA_K_WARNING, 12)
#define ECA_DISCONNCHID DEFMSG(CA_K_ERROR, 13)
#define ECA_BADTYPE DEFMSG(CA_K_ERROR, 14)
#define ECA_CHIDNOTFND DEFMSG(CA_K_INFO, 15)
#define ECA_CHIDRETRY DEFMSG(CA_K_INFO, 16)
#define ECA_INTERNAL DEFMSG(CA_K_FATAL, 17)
#define ECA_DBLCLFAIL DEFMSG(CA_K_WARNING, 18)
#define ECA_GETFAIL DEFMSG(CA_K_WARNING, 19)
#define ECA_PUTFAIL DEFMSG(CA_K_WARNING, 20)
#define ECA_ADDFAIL DEFMSG(CA_K_WARNING, 21)
#define ECA_BADCOUNT DEFMSG(CA_K_WARNING, 22)
#define ECA_BADSTR DEFMSG(CA_K_ERROR, 23)
#define ECA_DISCONN DEFMSG(CA_K_WARNING, 24)
#define ECA_DBLCHNL DEFMSG(CA_K_WARNING, 25)
#define ECA_EVDISALLOW DEFMSG(CA_K_ERROR, 26)
#define ECA_BUILDGET DEFMSG(CA_K_WARNING, 27)
#define ECA_NEEDSFP DEFMSG(CA_K_WARNING, 28)
#define ECA_OVEVFAIL DEFMSG(CA_K_WARNING, 29)
#define ECA_BADMONID DEFMSG(CA_K_ERROR, 30)
#define ECA_NEWADDR DEFMSG(CA_K_WARNING, 31)
#define ECA_NEWCONN DEFMSG(CA_K_INFO, 32)
#define ECA_NOCACTX DEFMSG(CA_K_WARNING, 33)
#define ECA_DEFUNCT DEFMSG(CA_K_FATAL, 34)
#define ECA_EMPTYSTR DEFMSG(CA_K_WARNING, 35)
#define ECA_NOREPEATER DEFMSG(CA_K_WARNING, 36)
#define ECA_TOLARGE DEFMSG(CA_K_ERROR, 9)
#define ECA_TIMEOUT DEFMSG(CA_K_WARNING, 10)
#define ECA_NOSUPPORT DEFMSG(CA_K_WARNING, 11)
#define ECA_STRTOBIG DEFMSG(CA_K_WARNING, 12)
#define ECA_DISCONNCHID DEFMSG(CA_K_ERROR, 13)
#define ECA_BADTYPE DEFMSG(CA_K_ERROR, 14)
#define ECA_CHIDNOTFND DEFMSG(CA_K_INFO, 15)
#define ECA_CHIDRETRY DEFMSG(CA_K_INFO, 16)
#define ECA_INTERNAL DEFMSG(CA_K_FATAL, 17)
#define ECA_DBLCLFAIL DEFMSG(CA_K_WARNING, 18)
#define ECA_GETFAIL DEFMSG(CA_K_WARNING, 19)
#define ECA_PUTFAIL DEFMSG(CA_K_WARNING, 20)
#define ECA_ADDFAIL DEFMSG(CA_K_WARNING, 21)
#define ECA_BADCOUNT DEFMSG(CA_K_WARNING, 22)
#define ECA_BADSTR DEFMSG(CA_K_ERROR, 23)
#define ECA_DISCONN DEFMSG(CA_K_WARNING, 24)
#define ECA_DBLCHNL DEFMSG(CA_K_WARNING, 25)
#define ECA_EVDISALLOW DEFMSG(CA_K_ERROR, 26)
#define ECA_BUILDGET DEFMSG(CA_K_WARNING, 27)
#define ECA_NEEDSFP DEFMSG(CA_K_WARNING, 28)
#define ECA_OVEVFAIL DEFMSG(CA_K_WARNING, 29)
#define ECA_BADMONID DEFMSG(CA_K_ERROR, 30)
#define ECA_NEWADDR DEFMSG(CA_K_WARNING, 31)
#define ECA_NEWCONN DEFMSG(CA_K_INFO, 32)
#define ECA_NOCACTX DEFMSG(CA_K_WARNING, 33)
#define ECA_DEFUNCT DEFMSG(CA_K_FATAL, 34)
#define ECA_EMPTYSTR DEFMSG(CA_K_WARNING, 35)
#define ECA_NOREPEATER DEFMSG(CA_K_WARNING, 36)
#define ECA_NOCHANMSG DEFMSG(CA_K_WARNING, 37)
#define ECA_DLCKREST DEFMSG(CA_K_WARNING, 38)
#define ECA_SERVBEHIND DEFMSG(CA_K_WARNING, 39)
@@ -109,13 +109,12 @@
#define ECA_PUTCBINPROG DEFMSG(CA_K_ERROR, 45)
#define ECA_NORDACCESS DEFMSG(CA_K_WARNING, 46)
#define ECA_NOWTACCESS DEFMSG(CA_K_WARNING, 47)
#define ECA_ANACHRONISM DEFMSG(CA_K_ERROR, 48)
#define ECA_ANACHRONISM DEFMSG(CA_K_ERROR, 48)
#define ECA_NOSEARCHADDR DEFMSG(CA_K_WARNING, 49)
#define ECA_NOCONVERT DEFMSG(CA_K_WARNING, 50)
#define ECA_BADCHID DEFMSG(CA_K_ERROR, 51)
#define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52)
#define ECA_OPWILLBLOCK DEFMSG(CA_K_WARNING, 53)
#define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 54)
#define ECA_BADCHID DEFMSG(CA_K_ERROR, 51)
#define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52)
#define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 53)
#ifndef CA_ERROR_GLBLSOURCE
epicsShareExtern READONLY char *ca_message_text[];
@@ -148,7 +147,7 @@ READONLY char *ca_message_text[]
"Count requested inappropriate for that channel",
"The supplied string has improper format",
"Network connection lost",
"Ambiguous channel host (multiple IOC's have a channel by that name)",
"Identical process variable name on multiple servers",
"The CA routine called is inappropriate for use within an event handler",
"Database value get for that channel failed during channel search",
"Unable to initialize without the vxWorks VX_FP_TASK task option set",
@@ -176,7 +175,6 @@ READONLY char *ca_message_text[]
"Data conversion between client's type and the server's type failed",
"Invalid channel identifier",
"Invalid function pointer",
"Operation will block (this code is not returned to user)",
"Thread is already attached to a client context"
};
#endif
+5 -5
View File
@@ -83,7 +83,7 @@ unsigned *pInlineIter
/*
* test_search ()
*/
LOCAL void test_search(
LOCAL void test_search (
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
@@ -92,12 +92,12 @@ unsigned *pInlineIter
unsigned i;
int status;
for (i=0u; i<iterations; i++) {
status = ca_search (pItems[i].name, &pItems[i].chix);
for ( i = 0u; i < iterations; i++ ) {
status = ca_search ( pItems[i].name, &pItems[i].chix );
SEVCHK (status, NULL);
}
status = ca_pend_io(0.0);
SEVCHK (status, NULL);
status = ca_pend_io ( 0.0 );
SEVCHK ( status, NULL );
*pInlineIter = 1;
}
+1 -1
View File
@@ -6,7 +6,7 @@
static const unsigned defaultIterations = 10000u;
int main(int argc, char **argv)
int main ( int argc, char **argv )
{
const char *pUsage = "<channel name> [<channel count> [<if 3rd arg present append number to pv name>]]";
+41
View File
@@ -0,0 +1,41 @@
/* $Id$
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include "iocinf.h"
bool claimMsgCache::set ( nciu & chan )
{
this->clientId = chan.id;
this->serverId = chan.sid;
if ( this->v44 ) {
unsigned len = strlen ( chan.pNameStr ) + 1u;
if ( this->bufLen < len ) {
unsigned newBufLen = 2 * len;
char *pNewStr = new char [ newBufLen ];
if ( pNewStr ) {
delete [] this->pStr;
this->pStr = pNewStr;
this->bufLen = newBufLen;
}
else {
return false;
}
}
strcpy ( this->pStr, chan.pNameStr );
this->currentStrLen = len;
}
else {
this->currentStrLen = 0u;
}
return true;
}
+39
View File
@@ -0,0 +1,39 @@
/* $Id$
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
inline claimMsgCache::claimMsgCache ( bool v44In ) :
pStr ( 0 ), clientId ( UINT_MAX ), serverId ( UINT_MAX ), currentStrLen ( 0u ),
bufLen ( 0u ), v44 ( v44In )
{
}
inline claimMsgCache::~claimMsgCache ()
{
if ( this->pStr ) {
delete this->pStr;
}
}
inline int claimMsgCache::deliverMsg ( tcpiiu &iiu )
{
if ( v44 ) {
return iiu.createChannelRequest ( this->clientId, this->pStr, this->currentStrLen );
}
else {
return iiu.createChannelRequest ( this->serverId, 0u, 0u );
}
}
inline bool claimMsgCache::channelMatches ( class nciu &chan )
{
return chan.id == this->clientId;
}
+38
View File
@@ -0,0 +1,38 @@
/* $Id$
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include "iocinf.h"
#include "netiiu_IL.h"
claimsPendingIIU::claimsPendingIIU ( tcpiiu &tcpIIUIn ) :
netiiu ( tcpIIUIn.clientCtx () ), tcpIIU ( tcpIIUIn )
{
}
claimsPendingIIU::~claimsPendingIIU ()
{
}
const char * claimsPendingIIU::pHostName () const
{
return this->tcpIIU.pHostName ();
}
void claimsPendingIIU::hostName ( char *pBuf, unsigned bufLength ) const
{
this->tcpIIU.hostName ( pBuf, bufLength );
}
bool claimsPendingIIU::connectionInProgress ( const char *pChannelName, const osiSockAddr &addr ) const
{
return this->tcpIIU.connectionInProgress ( pChannelName, addr );
}
+239
View File
@@ -0,0 +1,239 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#ifndef comBuf_ILh
#define comBuf_ILh
#include <assert.h>
#include "epicsTypes.h"
#include "osiWireFormat.h"
inline comBuf::comBuf () : nextWriteIndex ( 0u ), nextReadIndex ( 0u )
{
}
inline comBuf::~comBuf ()
{
}
inline void comBuf::destroy ()
{
delete this;
}
inline void * comBuf::operator new ( size_t size )
{
return comBuf::freeList.allocate ( size );
}
inline void comBuf::operator delete ( void *pCadaver, size_t size )
{
comBuf::freeList.release ( pCadaver, size );
}
inline unsigned comBuf::unoccupiedBytes () const
{
return sizeof ( this->buf ) - this->nextWriteIndex;
}
inline unsigned comBuf::occupiedBytes () const
{
return this->nextWriteIndex - this->nextReadIndex;
}
inline bool comBuf::copyInAllBytes ( const void *pBuf, unsigned nBytes )
{
if ( nBytes > this->unoccupiedBytes () ) {
return false;
}
memcpy ( &this->buf[this->nextWriteIndex], pBuf, nBytes);
this->nextWriteIndex += nBytes;
return true;
}
inline unsigned comBuf::copyInBytes ( const void *pBuf, unsigned nBytes )
{
unsigned available = this->unoccupiedBytes ();
if ( nBytes > available ) {
nBytes = available;
}
memcpy ( &this->buf[this->nextWriteIndex], pBuf, nBytes);
this->nextWriteIndex += nBytes;
return nBytes;
}
inline unsigned comBuf::copyIn ( comBuf &bufIn )
{
unsigned nBytes = this->copyInBytes ( &bufIn.buf[bufIn.nextReadIndex],
bufIn.nextWriteIndex - bufIn.nextReadIndex );
bufIn.nextReadIndex += nBytes;
return nBytes;
}
inline bool comBuf::copyOutAllBytes ( void *pBuf, unsigned nBytes )
{
if ( nBytes > this->occupiedBytes () ) {
return false;
}
memcpy ( pBuf, &this->buf[this->nextReadIndex], nBytes);
this->nextReadIndex += nBytes;
return true;
}
inline unsigned comBuf::copyOutBytes ( void *pBuf, unsigned nBytes )
{
unsigned occupied = this->occupiedBytes ();
if ( nBytes > occupied ) {
nBytes = occupied;
}
memcpy ( pBuf, &this->buf[this->nextReadIndex], nBytes);
this->nextReadIndex += nBytes;
return nBytes;
}
inline unsigned comBuf::removeBytes ( unsigned nBytes )
{
unsigned occupied = this->occupiedBytes ();
if ( nBytes > occupied ) {
nBytes = occupied;
}
this->nextReadIndex += nBytes;
return nBytes;
}
inline unsigned comBuf::maxBytes ()
{
return comBufSize;
}
inline bool comBuf::flushToWire ( class comQueSend &que )
{
unsigned occupied = this->occupiedBytes ();
unsigned nSent = 0u;
while ( occupied ) {
unsigned nBytes = que.sendBytes ( &this->buf[this->nextReadIndex], occupied );
if ( nBytes == 0u ) {
this->nextReadIndex = this->nextWriteIndex;
return false;
}
this->nextReadIndex += nBytes;
occupied = this->occupiedBytes ();
}
return true;
}
inline unsigned comBuf::fillFromWire ( class comQueRecv &que )
{
unsigned nNewBytes = que.recvBytes ( &this->buf[this->nextWriteIndex],
sizeof ( this->buf ) - this->nextWriteIndex );
this->nextWriteIndex += nNewBytes;
return nNewBytes;
}
inline unsigned comBuf::clipNElem ( unsigned elemSize, unsigned nElem )
{
unsigned avail = this->unoccupiedBytes ();
if ( elemSize * nElem > avail ) {
return avail / elemSize;
}
else {
return nElem;
}
}
inline unsigned comBuf::copyIn ( const epicsInt8 *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf::copyIn ( const epicsUInt8 *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf::copyIn ( const epicsOldString *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem * sizeof ( *pValue ) );
}
inline unsigned comBuf::copyIn ( const epicsInt16 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
this->buf[this->nextWriteIndex++] = pValue[i] >> 8u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 0u;
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsUInt16 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
this->buf[this->nextWriteIndex++] = pValue[i] >> 8u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 0u;
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsInt32 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
this->buf[this->nextWriteIndex++] = pValue[i] >> 24u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 16u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 8u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 0u;
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsUInt32 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
this->buf[this->nextWriteIndex++] = pValue[i] >> 24u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 16u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 8u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 0u;
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsFloat32 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
// allow native floating point formats to be converted to IEEE
osiConvertToWireFormat ( pValue[i], &this->buf[this->nextWriteIndex] );
this->nextWriteIndex += 4u;
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsFloat64 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
// allow native floating point formats to be converted to IEEE
osiConvertToWireFormat ( pValue[i], &this->buf[this->nextWriteIndex] );
this->nextWriteIndex += 8u;
}
return nElem;
}
#endif // comBuf_ILh
+113
View File
@@ -0,0 +1,113 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#include <iocinf.h>
#include <comBuf_IL.h>
comQueRecv::~comQueRecv ()
{
comBuf *pBuf;
this->mutex.lock ();
while ( ( pBuf = this->bufs.get () ) ) {
pBuf->destroy ();
}
this->mutex.unlock ();
}
unsigned comQueRecv::occupiedBytes () const
{
this->mutex.lock ();
unsigned count = this->bufs.count ();
unsigned nBytes;
if ( count >= 2u ) {
nBytes = this->bufs.first ()->occupiedBytes ();
nBytes += this->bufs.last ()->occupiedBytes ();
nBytes += ( count - 2u ) * comBuf::maxBytes ();
}
else if ( count == 1u ) {
nBytes = this->bufs.first ()->occupiedBytes ();
}
else {
nBytes = 0u;
}
this->mutex.unlock ();
return nBytes;
}
bool comQueRecv::copyOutBytes ( void *pBuf, unsigned nBytes )
{
char *pCharBuf = static_cast < char * > ( pBuf );
this->mutex.lock ();
// dont return partial message
if ( nBytes > this->occupiedBytes () ) {
this->mutex.unlock ();
return false;
}
unsigned bytesLeft = nBytes;
while ( bytesLeft ) {
comBuf * pComBuf = this->bufs.first ();
assert ( pComBuf );
bytesLeft -= pComBuf->copyOutBytes ( &pCharBuf[nBytes-bytesLeft], bytesLeft );
if ( pComBuf->occupiedBytes () == 0u ) {
this->bufs.remove ( *pComBuf );
pComBuf->destroy ();
}
}
this->mutex.unlock ();
return true;
}
unsigned comQueRecv::fillFromWire ()
{
// this approach requires that only one thread performs fill
// but its advantage is that the lock is not held while filling
comBuf *pComBuf = new comBuf;
if ( ! pComBuf ) {
// no way to be informed when memory is available
threadSleep ( 0.5 );
return 0u;
}
unsigned nNewBytes = pComBuf->fillFromWire ( *this );
this->mutex.lock ();
comBuf *pLastBuf = this->bufs.last ();
if ( pLastBuf ) {
pLastBuf->copyIn ( *pComBuf );
}
if ( pComBuf->occupiedBytes () ) {
this->bufs.add ( *pComBuf );
}
else {
pComBuf->destroy ();
}
this->mutex.unlock ();
return nNewBytes;
}
+814
View File
@@ -0,0 +1,814 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
//
// Requirements:
// 1) Allow sufficent headroom so that users will be able to perform
// a reasonable amount of IO within CA callbacks without experiencing
// a push/pull deadlock. If a potential push/pull deadlock situation
// occurs then detect and avoid it and provide diagnotic to the user
// via special status.
// 2) Return status to the user when there is insufficent memory to
// queue a complete message.
// 3) return status to the user when a message cant be flushed because
// a connection dropped.
// 4) Do not allocate too much memory in exception situatons (such as
// after a circuit disconnect).
// 5) Avoid allocating more memory than is absolutely necessary to meet
// the above requirements.
// 6) Message fragments must never be sent to the IOC when there isnt
// enough memory to queue part of a message (we also must not force
// a disconnect because the client is starved for memory).
// 7) avoid the need to check status for each byte pushed into the
// protocol stream.
//
// Implementation:
// 1) When queuing a complete message, first test to see if a flush is
// required. If it is a receive thread schedual the flush with the
// send thread, and otherwise directly execute the system call. The
// send thread must run at a higher priority than the receive thread
// if we are to minimize memory consumption.
// 2) Preallocate space for the entire message prior to copying in the
// message so that message fragments are not flushed out just prior
// to detecting that memory is unavailable.
// 3) Return a special error constant when the following situations
// are detected when the user is attempting to queue a request
// from within a user callback executed by a receive thread:
// a) A user is queuing more requests that demand a response from a
// callback than are removed by the response that initiated the
// callback, and this situation persists for many callbacks until
// all buffering in the system is exausted.
// b) A user is queuing many requests that demand a response from one
// callback until all buffering in the system is exausted.
// c) Some combination of both (a) nad (b).
//
//
#include <iocinf.h>
#include <comBuf_IL.h>
tsFreeList < class comBuf, 0x20, true > comBuf::freeList;
// nill message pad bytes
static const char nillBytes[] =
{
0, 0, 0, 0,
0, 0, 0, 0
};
inline bufferReservoir::~bufferReservoir ()
{
comBuf *pBuf;
while ( pBuf = this->reservedBufs.get () ) {
pBuf->destroy ();
}
}
inline comBuf *bufferReservoir::fetchOneBuffer ()
{
return this->reservedBufs.get ();
}
inline bool bufferReservoir::addOneBuffer ()
{
comBuf *pBuf = new comBuf;
if ( pBuf ) {
this->reservedBufs.add ( *pBuf );
return true;
}
else {
return false;
}
}
inline unsigned bufferReservoir::nBytes ()
{
return ( this->reservedBufs.count () * comBuf::maxBytes () );
}
// o lock the comQueSend
// o reserve sufficent space for entire message
// (this allows the recv thread to add a message
// to the que while some other thread is flushing
// and therefore prevents deadlocks, and it also
// allows proper status to be returned)
// o unlock comQueSend if status is not ECA_NORMAL
inline int comQueSend::lockAndReserveSpace ( unsigned msgSize, bufferReservoir &reservoir )
{
unsigned bytesReserved = reservoir.nBytes ();
unsigned unoccupied;
this->mutex.lock ();
comBuf *pComBuf = this->bufs.last ();
if ( pComBuf ) {
unoccupied = pComBuf->unoccupiedBytes ();
}
else {
unoccupied = 0u;
}
// flush if conditions indicate. second part of this guarantees
// that we will not flush out a buffer with almost nothing
// in it (this has a large impact on performance)
if ( this->bufs.count () <= 1u || unoccupied >= msgSize ) {
bytesReserved = unoccupied;
}
else {
this->mutex.unlock ();
if ( ! this->flushToWire () ) {
return ECA_DISCONNCHID;
}
if ( this->bufs.count () >= 32u ) {
return ECA_TOLARGE;
}
this->mutex.lock ();
}
while ( bytesReserved < msgSize ) {
if ( reservoir.addOneBuffer() ) {
bytesReserved += comBuf::maxBytes ();
}
else {
this->mutex.unlock ();
return ECA_ALLOCMEM;
}
}
return ECA_NORMAL;
}
// 1) This routine is private because it assumes that the lock
// is applied
//
// 2) This routine does not return status because of the following
// argument. The routine can fail because the wire disconnects or
// because their isnt memory to create a buffer. For the former we
// just discard the message, but do not fail. For the latter we
// shutdown() the connection and discard the rest of the message
// (this eliminates the possibility of message fragments getting
// onto the wire).
//
// 3) Arguments here are a bit verbose until compilers all implement
// member template functions.
//
template < class T >
inline void comQueSend_copyIn ( tsDLList < comBuf > &comBufList,
bufferReservoir &reservoir, const T *pVal, unsigned nElem )
{
unsigned nCopied;
comBuf *pComBuf = comBufList.last ();
if ( pComBuf ) {
nCopied = pComBuf->copyIn ( pVal, nElem );
}
else {
nCopied = 0u;
}
while ( nElem > nCopied ) {
pComBuf = reservoir.fetchOneBuffer ();
//
// This fails only if space was not preallocated.
// See comments at the top of this program on
// why space must always be preallocated.
//
assert ( pComBuf );
nCopied += pComBuf->copyIn ( &pVal[nCopied], nElem - nCopied );
comBufList.add ( *pComBuf );
}
}
template < class T >
inline void comQueSend_copyIn ( tsDLList < comBuf > &comBufList, bufferReservoir &reservoir, const T &val )
{
comBuf *pComBuf = comBufList.last ();
if ( pComBuf ) {
if ( pComBuf->copyIn ( &val, 1u ) >= 1u ) {
return;
}
}
pComBuf = reservoir.fetchOneBuffer ();
//
// This fails only if space was not preallocated.
// See comments at the top of this program on
// space must always be preallocated.
//
assert ( pComBuf );
pComBuf->copyIn ( &val, 1u );
comBufList.add ( *pComBuf );
}
void comQueSend::copy_dbr_string ( bufferReservoir &reservoir, const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const dbr_string_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_short ( bufferReservoir &reservoir, const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const dbr_short_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_float ( bufferReservoir &reservoir, const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const dbr_float_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_char ( bufferReservoir &reservoir, const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const dbr_char_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_long ( bufferReservoir &reservoir, const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const dbr_long_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_double ( bufferReservoir &reservoir, const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const dbr_double_t *> ( pValue ), nElem );
}
const comQueSend::copyFunc_t comQueSend::dbrCopyVector [] = {
comQueSend::copy_dbr_string,
comQueSend::copy_dbr_short,
comQueSend::copy_dbr_float,
comQueSend::copy_dbr_short, // DBR_ENUM
comQueSend::copy_dbr_char,
comQueSend::copy_dbr_long,
comQueSend::copy_dbr_double,
0, // DBR_STS_SHORT
0, // DBR_STS_FLOAT
0, // DBR_STS_ENUM
0, // DBR_STS_CHAR
0, // DBR_STS_LONG
0, // DBR_STS_DOUBLE
0, // DBR_TIME_STRING
0, // DBR_TIME_INT
0, // DBR_TIME_SHORT
0, // DBR_TIME_FLOAT
0, // DBR_TIME_ENUM
0, // DBR_TIME_CHAR
0, // DBR_TIME_LONG
0, // DBR_TIME_DOUBLE
0, // DBR_GR_STRING
0, // DBR_GR_SHORT
0, // DBR_GR_FLOAT
0, // DBR_GR_ENUM
0, // DBR_GR_CHAR
0, // DBR_GR_LONG
0, // DBR_GR_DOUBLE
0, // DBR_CTRL_STRING
0, // DBR_CTRL_SHORT
0, // DBR_CTRL_FLOAT
0, // DBR_CTRL_ENUM
0, // DBR_CTRL_CHAR
0, // DBR_CTRL_LONG
0, // DBR_CTRL_DOUBLE
comQueSend::copy_dbr_short, // DBR_PUT_ACKT
comQueSend::copy_dbr_short, // DBR_PUT_ACKS
0, // DBR_STSACK_STRING
0 // DBR_CLASS_NAME
};
comQueSend::~comQueSend ()
{
comBuf *pBuf;
this->mutex.lock ();
while ( ( pBuf = this->bufs.get () ) ) {
pBuf->destroy ();
}
this->mutex.unlock ();
}
unsigned comQueSend::occupiedBytes () const
{
this->mutex.lock ();
unsigned count = this->bufs.count ();
unsigned nBytes;
if ( count >= 2u ) {
nBytes = this->bufs.first ()->occupiedBytes ();
nBytes += this->bufs.last ()->occupiedBytes ();
nBytes += ( count - 2u ) * comBuf::maxBytes ();
}
else if ( count == 1u ) {
nBytes = this->bufs.first ()->occupiedBytes ();
}
else {
nBytes = 0u;
}
this->mutex.unlock ();
return nBytes;
}
bool comQueSend::flushToWire ()
{
bool success;
// the recv thread is not permitted to flush as this
// can result in a push / pull deadlock on the TCP pipe,
// but in that case this does schedual the flush through
// the higher priority send thread
if ( ! this->flushToWirePermit () ) {
return true;
}
// this approach requires that only one thread at a time
// performs flushes but its advantage is that the primary
// lock is not held while sending and this prevents deadlocks
this->flushMutex.lock ();
while ( true ) {
this->mutex.lock ();
comBuf * pBuf = this->bufs.get ();
this->mutex.unlock ();
if ( ! pBuf ) {
success = true;
break;
}
bool success = pBuf->flushToWire ( *this );
pBuf->destroy ();
if ( ! success ) {
comBuf *pBuf;
this->mutex.lock ();
while ( ( pBuf = this->bufs.get () ) ) {
pBuf->destroy ();
}
this->mutex.unlock ();
break;
}
}
this->flushMutex.unlock ();
return success;
}
int comQueSend::writeRequest ( unsigned serverId, unsigned type, unsigned nElem, const void *pValue )
{
bufferReservoir reservoir;
unsigned size, postcnt;
bool stringOptim;
if ( ! this->dbrCopyVector [type] ) {
return ECA_BADTYPE;
}
if ( nElem > 0xffff) {
return ECA_BADCOUNT;
}
if ( type == DBR_STRING && nElem == 1 ) {
char *pstr = (char *) pValue;
size = strlen ( pstr ) +1;
stringOptim = true;
}
else {
size = dbr_size_n ( type, nElem );
stringOptim = false;
}
postcnt = CA_MESSAGE_ALIGN ( size );
if ( postcnt > 0xffff ) {
return ECA_BADCOUNT;
}
assert ( serverId <= 0xffffffff );
int status = this->lockAndReserveSpace ( postcnt + 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_WRITE ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( postcnt ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( type ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( nElem ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( ~0UL ) ); // available
if ( stringOptim ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <const unsigned char *> ( pValue ), size );
}
else {
( this->*dbrCopyVector [type] ) ( reservoir, pValue, nElem );
}
comQueSend_copyIn ( this->bufs, reservoir, nillBytes, postcnt - size );
this->mutex.unlock ();
}
return status;
}
int comQueSend::writeNotifyRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem, const void *pValue )
{
bufferReservoir reservoir;
ca_uint32_t size, postcnt;
if ( ! this->dbrCopyVector [type] ) {
return ECA_BADTYPE;
}
if ( nElem > 0xffff) {
return ECA_BADCOUNT;
}
if ( type == DBR_STRING && nElem == 1 ) {
char *pstr = (char *) pValue;
size = strlen ( pstr ) +1;
}
else {
size = dbr_size_n ( type, nElem );
}
postcnt = CA_MESSAGE_ALIGN ( size );
if ( postcnt > 0xffff ) {
return ECA_BADCOUNT;
}
assert ( serverId <= 0xffffffff );
int status = this->lockAndReserveSpace ( postcnt + 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_WRITE_NOTIFY ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( postcnt ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( type ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( nElem ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( ioId ) ); // available
( this->*dbrCopyVector [type] ) ( reservoir, pValue, nElem );
comQueSend_copyIn ( this->bufs, reservoir, nillBytes, postcnt - size );
this->mutex.unlock ();
}
return status;
}
int comQueSend::readCopyRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem )
{
bufferReservoir reservoir;
if ( nElem > 0xffff) {
return ECA_BADCOUNT;
}
if ( type > 0xffff) {
return ECA_BADTYPE;
}
assert ( serverId <= 0xffffffff );
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_READ ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( type ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( nElem ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( ioId ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::readNotifyRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem )
{
bufferReservoir reservoir;
if ( nElem > 0xffff) {
return ECA_BADCOUNT;
}
if ( type > 0xffff) {
return ECA_BADTYPE;
}
assert ( serverId <= 0xffffffff );
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_READ_NOTIFY ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( type ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( nElem ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( ioId ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::createChannelRequest ( unsigned id, const char *pName, unsigned nameLength )
{
bufferReservoir reservoir;
unsigned postCnt = CA_MESSAGE_ALIGN ( nameLength );
assert ( id <= 0xffffffff );
assert ( postCnt <= 0xffff );
int status = this->lockAndReserveSpace ( postCnt + 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_CLAIM_CIU ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( postCnt ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( id ) ); // cid
//
// The available field is used (abused)
// here to communicate the minor version number
// starting with CA 4.1.
//
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( CA_MINOR_VERSION ) ); // available
if ( nameLength ) {
comQueSend_copyIn ( this->bufs, reservoir, pName, nameLength );
}
if ( postCnt > nameLength ) {
comQueSend_copyIn ( this->bufs, reservoir, nillBytes, postCnt - nameLength );
}
this->mutex.unlock ();
}
return status;
}
int comQueSend::clearChannelRequest ( unsigned clientId, unsigned serverId )
{
bufferReservoir reservoir;
assert ( serverId <= 0xffffffff );
assert ( clientId <= 0xffffffff );
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_CLEAR_CHANNEL ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( clientId ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::subscriptionRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem, unsigned mask )
{
bufferReservoir reservoir;
if ( nElem > 0xffff) {
return ECA_BADCOUNT;
}
if ( type > 0xffff) {
return ECA_BADTYPE;
}
assert ( serverId <= 0xffffffff );
assert ( ioId <= 0xffffffff );
int status = this->lockAndReserveSpace ( 32u, reservoir );
if ( status == ECA_NORMAL ) {
// header
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_EVENT_ADD ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 16u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( type ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( nElem ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( ioId ) ); // available
// extension
comQueSend_copyIn ( this->bufs, reservoir, static_cast < ca_float32_t > ( 0.0 ) ); // m_lval
comQueSend_copyIn ( this->bufs, reservoir, static_cast < ca_float32_t > ( 0.0 ) ); // m_hval
comQueSend_copyIn ( this->bufs, reservoir, static_cast < ca_float32_t > ( 0.0 ) ); // m_toval
comQueSend_copyIn ( this->bufs, reservoir, static_cast < ca_uint16_t > ( mask ) ); // m_mask
comQueSend_copyIn ( this->bufs, reservoir, static_cast < ca_uint16_t > ( 0u ) ); // m_pad
this->mutex.unlock ();
}
return status;
}
int comQueSend::subscriptionCancelRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem )
{
bufferReservoir reservoir;
assert ( type <= 0xffff );
assert ( nElem <= 0xffff );
assert ( serverId <= 0xffffffff );
assert ( ioId <= 0xffffffff );
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_EVENT_CANCEL ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( type ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( nElem ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( serverId ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( ioId ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::disableFlowControlRequest ()
{
bufferReservoir reservoir;
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_EVENTS_ON ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::enableFlowControlRequest ()
{
bufferReservoir reservoir;
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_EVENTS_OFF ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::noopRequest ()
{
bufferReservoir reservoir;
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_NOOP ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::echoRequest ()
{
bufferReservoir reservoir;
int status = this->lockAndReserveSpace ( 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_ECHO ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // available
this->mutex.unlock ();
}
return status;
}
int comQueSend::hostNameSetRequest ( const char *pName )
{
bufferReservoir reservoir;
unsigned size = strlen ( pName ) + 1u;
unsigned postSize = CA_MESSAGE_ALIGN ( size );
assert ( postSize < 0xffff );
int status = this->lockAndReserveSpace ( postSize + 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_HOST_NAME ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( postSize ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // available
comQueSend_copyIn ( this->bufs, reservoir, pName, size );
comQueSend_copyIn ( this->bufs, reservoir, nillBytes, postSize - size );
this->mutex.unlock ();
}
return status;
}
int comQueSend::userNameSetRequest ( const char *pName )
{
bufferReservoir reservoir;
unsigned size = strlen ( pName ) + 1u;
unsigned postSize = CA_MESSAGE_ALIGN ( size );
assert ( postSize < 0xffff );
int status = this->lockAndReserveSpace ( postSize + 16u, reservoir );
if ( status == ECA_NORMAL ) {
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( CA_PROTO_CLIENT_NAME ) ); // cmd
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( postSize ) ); // postsize
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // dataType
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint16_t> ( 0u ) ); // count
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // cid
comQueSend_copyIn ( this->bufs, reservoir, static_cast <ca_uint32_t> ( 0u ) ); // available
comQueSend_copyIn ( this->bufs, reservoir, pName, size );
comQueSend_copyIn ( this->bufs, reservoir, nillBytes, postSize - size );
this->mutex.unlock ();
}
return status;
}
#if 0
/*
* tcpiiu::pushStreamMsg ()
*/
int tcpiiu::pushStreamMsg ( const caHdr &hdr, const void *pext, unsigned extsize )
{
unsigned alignedExtSize;
bool status;
msgDescriptor msgs[3];
caHdr msgHdr = hdr;
if ( extsize > 0xffff - 7 ) {
return ECA_TOLARGE;
}
alignedExtSize = CA_MESSAGE_ALIGN ( extsize );
msgHdr.m_postsize = htons ( alignedExtSize );
debugPrintf ( (
"CAC: Request => cmmd=%x cid=0x%x type=%x count=%x postsize=%x\n",
hdr.m_cmmd, hdr.m_cid, hdr.m_dataType,
hdr.m_count, hdr.m_postsize ) );
msgs[0].pBuf = &msgHdr;
msgs[0].nBytes = sizeof ( msgHdr );
msgs[1].pBuf = pext;
msgs[1].nBytes = extsize;
if ( alignedExtSize > extsize ) {
unsigned diff = alignedExtSize - extsize;
assert ( diff <= sizeof ( nullBuff ) );
msgs[2].pBuf = nullBuff;
msgs[2].nBytes = diff;
status = this->copyInBytes ( msgs, 3u );
}
else {
status = this->copyInBytes ( msgs, 2u );
}
if ( status ) {
return ECA_NORMAL;
}
else {
this->shutdown ();
return ECA_ALLOCMEM;
}
}
/*
* tcpiiu::pushStreamMsg ()
*/
int tcpiiu::pushStreamMsg ( const caHdr &hdr )
{
caHdr msgHdr = hdr;
msgHdr.m_postsize = htons ( 0 );
debugPrintf ( (
"CAC: Request => cmmd=%x cid=0x%x type=%x count=%x postsize=%x\n",
hdr.m_cmmd, hdr.m_cid, hdr.m_dataType,
hdr.m_count, hdr.m_postsize ) );
bool status = this->copyIn ( msgHdr );
if ( status ) {
return ECA_NORMAL;
}
else {
this->shutdown ();
return ECA_ALLOCMEM;
}
}
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 2000, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef comQueSend_ILh
#define comQueSend_ILh
#endif // comQueSend_ILh
-21
View File
@@ -1,21 +0,0 @@
/* $Id$ */
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include "iocinf.h"
#ifdef DEBUG
#define LOGRETRYINTERVAL logRetryInterval(__FILE__, __LINE__);
LOCAL void logRetryInterval (pcac, char *pFN, unsigned lineno);
#else
#define LOGRETRYINTERVAL
#endif
-1
View File
@@ -1 +0,0 @@
+57
View File
@@ -0,0 +1,57 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#include "iocinf.h"
hostNameCache::hostNameCache ( const osiSockAddr &addr, ipAddrToAsciiEngine &engine ) :
ipAddrToAsciiAsynchronous ( addr ),
pHostName ( 0u )
{
this->ioInitiate ( engine );
}
hostNameCache::~hostNameCache ()
{
if ( this->pHostName ) {
delete [] this->pHostName;
}
}
void hostNameCache::ioCompletionNotify ( const char *pHostNameIn )
{
if ( ! this->pHostName ) {
unsigned size = strlen ( pHostNameIn ) + 1u;
char *pTmp = new char [size];
if ( ! pTmp ) {
// we fail over to using the IP address for the name
return;
}
strcpy ( pTmp, pHostNameIn );
this->pHostName = pTmp;
}
}
void hostNameCache::hostName ( char *pBuf, unsigned bufSize ) const
{
if ( this->pHostName ) {
strncpy ( pBuf, this->pHostName, bufSize);
}
else {
osiSockAddr addr = this->address();
sockAddrToDottedA ( &addr.sa, pBuf, bufSize );
}
pBuf [ bufSize - 1u ] = '\0';
}
+10 -10
View File
@@ -116,8 +116,8 @@ epicsShareFunc void epicsShareAPI setPortAndRemoveDuplicates
if (pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr &&
pNode->addr.ia.sin_port == pTmpNode->addr.ia.sin_port) {
char buf[64];
ipAddrToA (&pNode->addr.ia, buf, sizeof(buf));
ca_printf ("Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", buf);
ipAddrToA ( &pNode->addr.ia, buf, sizeof (buf) );
ca_printf ( "Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", buf );
free (pNode);
pNode = NULL;
break;
@@ -139,7 +139,7 @@ epicsShareFunc void epicsShareAPI setPortAndRemoveDuplicates
* configureChannelAccessAddressList ()
*/
epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
(ELLLIST *pList, SOCKET sock, unsigned short port)
( ELLLIST *pList, SOCKET sock, unsigned short port )
{
ELLLIST tmpList;
char *pstr;
@@ -149,7 +149,7 @@ epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
/*
* dont load the list twice
*/
assert ( ellCount(pList) == 0 );
assert ( ellCount (pList) == 0 );
ellInit ( &tmpList );
@@ -202,16 +202,16 @@ epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
/*
* printChannelAccessAddressList ()
*/
epicsShareFunc void epicsShareAPI printChannelAccessAddressList (const ELLLIST *pList)
epicsShareFunc void epicsShareAPI printChannelAccessAddressList ( const ELLLIST *pList )
{
osiSockAddrNode *pNode;
printf ("Channel Access Address List\n");
pNode = (osiSockAddrNode *) ellFirst (pList);
printf ( "Channel Access Address List\n" );
pNode = (osiSockAddrNode *) ellFirst ( pList );
while (pNode) {
char buf[64];
ipAddrToA (&pNode->addr.ia, buf, sizeof(buf));
printf ("%s\n", buf);
pNode = (osiSockAddrNode *) ellNext (&pNode->node);
ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) );
printf ( "%s\n", buf );
pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
}
}
+550 -231
View File
File diff suppressed because it is too large Load Diff
+19 -4
View File
@@ -20,10 +20,25 @@ localHostName localHostNameAtLoadTime;
localHostName::localHostName ()
{
int status = gethostname ( this->cache, sizeof ( this->cache ) );
int status = osiSockAttach ();
if ( status ) {
strncpy ( this->cache, "<unknown host>", sizeof ( this->cache ) );
localHostName::cache [ sizeof ( this->cache ) - 1u ] = '\0';
this->attachedToSockLib = true;
int status = gethostname ( this->cache, sizeof ( this->cache ) );
if ( status ) {
strncpy ( this->cache, "<unknown host>", sizeof ( this->cache ) );
localHostName::cache [ sizeof ( this->cache ) - 1u ] = '\0';
}
this->length = strlen ( this->cache );
}
else {
this->attachedToSockLib = false;
strncpy ( this->cache, "<unknown host>", sizeof ( this->cache ) );
}
}
localHostName::~localHostName ()
{
if ( this->attachedToSockLib ) {
osiSockRelease ();
}
this->length = strlen ( this->cache );
}
+2
View File
@@ -13,10 +13,12 @@
class localHostName {
public:
localHostName ();
~localHostName ();
const char * pointer () const;
void copy ( char *pBuf, unsigned bufLength ) const;
unsigned stringLength () const;
private:
bool attachedToSockLib;
unsigned length;
char cache [128];
};
+442 -558
View File
File diff suppressed because it is too large Load Diff
+129
View File
@@ -30,7 +30,136 @@ inline void nciu::operator delete ( void *pCadaver, size_t size )
nciu::freeList.release ( pCadaver, size );
}
inline void nciu::lock () const
{
this->cacCtx.nciuPrivate::mutex.lock ();
}
inline void nciu::unlock () const
{
this->cacCtx.nciuPrivate::mutex.unlock ();
}
inline bool nciu::fullyConstructed () const
{
return this->f_fullyConstructed;
}
inline bool nciu::identifierEquivelence ( unsigned idToMatch )
{
return idToMatch == this->id;
}
inline void nciu::resetRetryCount ()
{
this->retry = 0u;
}
inline void nciu::accessRightsStateChange ( const caar &arIn )
{
this->ar = ar;
this->accessRightsNotify ( this->ar );
}
inline unsigned nciu::getSID () const
{
return this->sid;
}
inline unsigned nciu::getRetrySeqNo () const
{
return this->retrySeqNo;
}
inline void nciu::lockPIIU () const
{
this->lock ();
assert ( this->ptrLockCount < USHRT_MAX );
this->ptrLockCount++;
this->unlock ();
}
inline void nciu::unlockPIIU () const
{
bool signalNeeded;
this->lock ();
assert ( this->ptrLockCount > 0 );
this->ptrLockCount--;
if ( this->ptrLockCount == 0u && this->ptrUnlockWaitCount > 0u ) {
this->ptrUnlockWaitCount--;
signalNeeded = true;
}
else {
signalNeeded = false;
}
this->unlock ();
if ( signalNeeded ) {
this->cacCtx.nciuPrivate::ptrLockReleaseWakeup.signal ();
}
}
inline void nciu::subscriptionCancelMsg ( ca_uint32_t clientId )
{
this->lockPIIU ();
if ( this->piiu ) {
this->piiu->subscriptionCancelRequest ( clientId, this->sid, this->typeCode, this->count );
}
this->unlockPIIU ();
}
inline void nciu::connect ( tcpiiu &iiu )
{
this->connect ( iiu, this->typeCode, this->count, this->sid );
}
inline void nciu::searchReplySetUp ( unsigned sidIn,
unsigned typeIn, unsigned long countIn )
{
this->lock ();
this->typeCode = typeIn;
this->count = countIn;
this->sid = sidIn;
this->ar.read_access = true;
this->ar.write_access = true;
this->unlock ();
}
inline bool nciu::connected () const
{
return this->f_connected;
}
inline bool nciu::connectionInProgress ( const osiSockAddr &addrIn )
{
bool status;
this->lockPIIU ();
if ( this->piiu ) {
status = this->piiu->connectionInProgress ( this->pNameStr, addrIn );
}
else {
status = false;
}
this->unlockPIIU ();
return status;
}
inline void nciu::ioInstall ( class baseNMIU &nmiu )
{
this->cacCtx.ioInstall ( *this, nmiu );
}
inline void nciu::ioDestroy ( unsigned id )
{
this->cacCtx.ioDestroy ( id );
}
+5 -12
View File
@@ -11,6 +11,8 @@
*/
#include "iocinf.h"
#include "netReadCopyIO_IL.h"
#include "nciu_IL.h"
tsFreeList < class netReadCopyIO, 1024 > netReadCopyIO::freeList;
@@ -24,12 +26,13 @@ netReadCopyIO::netReadCopyIO ( nciu &chanIn, unsigned typeIn, unsigned long coun
netReadCopyIO::~netReadCopyIO ()
{
}
void netReadCopyIO::disconnect ( const char *pHostName )
{
this->exceptionNotify ( ECA_DISCONN, pHostName );
delete this;
this->baseNMIU::destroy ();
}
void netReadCopyIO::completionNotify ()
@@ -48,7 +51,7 @@ void netReadCopyIO::completionNotify ( unsigned typeIn,
memcpy ( this->pValue, pDataIn,
dbr_size_n ( typeIn, countIn ) );
# endif
chan.decrementOutstandingIO (this->seqNumber);
this->chan.decrementOutstandingIO (this->seqNumber);
}
else {
this->exceptionNotify ( ECA_INTERNAL, "bad data type in message" );
@@ -67,13 +70,3 @@ void netReadCopyIO::exceptionNotify ( int status,
"%s type=%d count=%ld\n",
pContextIn, typeIn, countIn);
}
void * netReadCopyIO::operator new ( size_t size )
{
return netReadCopyIO::freeList.allocate ( size );
}
void netReadCopyIO::operator delete ( void *pCadaver, size_t size )
{
netReadCopyIO::freeList.release ( pCadaver, size );
}
+52
View File
@@ -0,0 +1,52 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef netReadCopyIO_ILh
#define netReadCopyIO_ILh
//
// we need to be careful about exporting a raw IO
// pointer because the IO object may be deleted
// at any time when the channel disconnects or the
// IO completes
//
inline bool netReadCopyIO::factory ( nciu &chan, unsigned type,
unsigned long count, void *pValue, unsigned seqNumber, unsigned &id )
{
netReadCopyIO *pIO = new netReadCopyIO ( chan,
type, count, pValue, seqNumber );
if ( pIO ) {
id = pIO->getId ();
return true;
}
else {
return false;
}
}
inline void * netReadCopyIO::operator new ( size_t size )
{
return netReadCopyIO::freeList.allocate ( size );
}
inline void netReadCopyIO::operator delete ( void *pCadaver, size_t size )
{
netReadCopyIO::freeList.release ( pCadaver, size );
}
#endif // netReadCopyIO_ILh
+3 -2
View File
@@ -22,17 +22,18 @@ netReadNotifyIO::netReadNotifyIO ( nciu &chan, cacNotify &notifyIn ) :
netReadNotifyIO::~netReadNotifyIO ()
{
// private NOOP forces pool allocation
}
void netReadNotifyIO::destroy ()
{
delete this;
this->baseNMIU::destroy ();
}
void netReadNotifyIO::disconnect ( const char *pHostName )
{
this->cacNotifyIO::exceptionNotify ( ECA_DISCONN, pHostName );
delete this;
this->baseNMIU::destroy ();
}
void netReadNotifyIO::completionNotify ()
+26 -4
View File
@@ -15,13 +15,35 @@
* 505 665 1831
*/
inline void * netReadNotifyIO::operator new (size_t size)
#ifndef netReadNotifyIO_ILh
#define netReadNotifyIO_ILh
inline void * netReadNotifyIO::operator new ( size_t size )
{
return netReadNotifyIO::freeList.allocate (size);
return netReadNotifyIO::freeList.allocate ( size );
}
inline void netReadNotifyIO::operator delete (void *pCadaver, size_t size)
inline void netReadNotifyIO::operator delete ( void *pCadaver, size_t size )
{
netReadNotifyIO::freeList.release (pCadaver,size);
netReadNotifyIO::freeList.release ( pCadaver, size );
}
//
// we need to be careful about exporting a raw IO
// pointer because the IO object may be deleted
// at any time when the channel disconnects or the
// IO completes
//
inline bool netReadNotifyIO::factory ( nciu &chan, cacNotify &notify, ca_uint32_t &id )
{
netReadNotifyIO *pIO = new netReadNotifyIO ( chan, notify );
if ( pIO ) {
id = pIO->getId ();
return true;
}
else {
return false;
}
}
#endif // netReadNotifyIO_ILh
+5 -23
View File
@@ -12,6 +12,7 @@
#include "iocinf.h"
#include "netSubscription_IL.h"
#include "nciu_IL.h"
tsFreeList < class netSubscription, 1024 > netSubscription::freeList;
@@ -20,41 +21,22 @@ netSubscription::netSubscription ( nciu &chan, chtype typeIn, unsigned long coun
cacNotifyIO (notifyIn), baseNMIU (chan),
type (typeIn), count (countIn), mask (maskIn)
{
this->subscriptionMsg ();
}
netSubscription::~netSubscription ()
{
if ( this->chan.connected () ) {
caHdr hdr;
ca_uint16_t type_16, count_16;
type_16 = (ca_uint16_t) this->chan.nativeType ();
if ( this->chan.nativeElementCount () > 0xffff ) {
count_16 = 0xffff;
}
else {
count_16 = (ca_uint16_t) this->chan.nativeElementCount ();
}
hdr.m_cmmd = htons (CA_PROTO_EVENT_CANCEL);
hdr.m_available = this->id;
hdr.m_dataType = htons ( type_16 );
hdr.m_count = htons ( count_16 );
hdr.m_cid = this->chan.sid;
hdr.m_postsize = 0;
this->chan.piiu->pushStreamMsg (&hdr, NULL, true);
}
this->chan.subscriptionCancelMsg ( this->getId () );
}
void netSubscription::destroy()
{
delete this;
this->baseNMIU::destroy ();
}
int netSubscription::subscriptionMsg ()
{
return this->chan.subscriptionMsg ( this->id, this->type,
return this->chan.subscriptionMsg ( this->getId (), this->type,
this->count, this->mask );
}
+26
View File
@@ -15,6 +15,9 @@
* 505 665 1831
*/
#ifndef netSubscription_ILh
#define netSubscription_ILh
inline void * netSubscription::operator new (size_t size)
{
@@ -25,3 +28,26 @@ inline void netSubscription::operator delete (void *pCadaver, size_t size)
{
netSubscription::freeList.release (pCadaver,size);
}
//
// we need to be careful about exporting a raw IO
// pointer because the IO object may be deleted
// at any time when the channel disconnects or the
// IO completes
//
inline bool netSubscription::factory ( nciu &chan, chtype type, unsigned long count,
unsigned short mask, cacNotify &notify, unsigned &id )
{
netSubscription *pIO = new netSubscription ( chan, type, count, mask, notify );
if ( pIO ) {
id = pIO->getId ();
return true;
}
else {
return false;
}
}
#endif // netSubscription_ILh
+3 -2
View File
@@ -22,17 +22,18 @@ netWriteNotifyIO::netWriteNotifyIO (nciu &chan, cacNotify &notifyIn) :
netWriteNotifyIO::~netWriteNotifyIO ()
{
// private NOOP forces pool allocation
}
void netWriteNotifyIO::destroy ()
{
delete this;
this->baseNMIU::destroy ();
}
void netWriteNotifyIO::disconnect ( const char *pHostName )
{
this->exceptionNotify (ECA_DISCONN, pHostName);
delete this;
this->baseNMIU::destroy ();
}
void netWriteNotifyIO::completionNotify ()
+19
View File
@@ -28,3 +28,22 @@ inline void netWriteNotifyIO::operator delete ( void *pCadaver, size_t size )
netWriteNotifyIO::freeList.release ( pCadaver, size );
}
//
// we need to be careful about exporting a raw IO
// pointer because the IO object may be deleted
// at any time when the channel disconnects or the
// IO completes
//
inline bool netWriteNotifyIO::factory ( nciu &chan, cacNotify &notify, ca_uint32_t &id )
{
netWriteNotifyIO *pIO = new netWriteNotifyIO ( chan, notify );
if ( pIO ) {
id = pIO->getId ();
return true;
}
else {
return false;
}
}
+201 -21
View File
@@ -11,25 +11,13 @@
*/
#include "iocinf.h"
#include "nciu_IL.h"
#include "claimMsgCache_IL.h"
/*
* constructNIIU ()
*/
netiiu::netiiu (cac *pcac) : baseIIU (pcac)
{
ellInit (&this->chidList);
}
/*
* netiiu::~netiiu ()
*/
netiiu::~netiiu ()
{
}
void netiiu::show ( unsigned /* level */ ) const
{
this->pcas->lock ();
this->lock ();
tsDLIterConstBD <nciu> pChan ( this->chidList.first () );
while ( pChan.valid () ) {
@@ -41,25 +29,217 @@ void netiiu::show ( unsigned /* level */ ) const
pChan->nativeElementCount (), hostName );
switch ( pChan->state () ) {
case cs_never_conn:
printf ("never connected to an IOC");
printf ( "never connected to an IOC" );
break;
case cs_prev_conn:
printf ("disconnected from IOC");
printf ( "disconnected from IOC" );
break;
case cs_conn:
printf ("connected to an IOC");
printf ( "connected to an IOC" );
break;
case cs_closed:
printf ("invalid channel");
printf ( "invalid channel" );
break;
default:
break;
}
printf("\n");
printf ( "\n" );
}
this->pcas->unlock ();
this->unlock ();
}
unsigned netiiu::channelCount () const
{
return this->chidList.count ();
}
void netiiu::lock () const
{
this->mutex.lock ();
}
void netiiu::unlock () const
{
this->mutex.unlock ();
}
void netiiu::detachAllChan ()
{
this->lock ();
tsDLIterBD <nciu> chan ( this->chidList.first () );
while ( chan.valid () ) {
tsDLIterBD <nciu> next = chan.itemAfter ();
chan->detachChanFromIIU ();
chan = next;
}
this->unlock ();
}
void netiiu::disconnectAllChan ()
{
this->lock ();
tsDLIterBD <nciu> chan ( this->chidList.first () );
while ( chan.valid () ) {
tsDLIterBD <nciu> next = chan.itemAfter ();
chan->disconnect ();
chan = next;
}
this->unlock ();
}
void netiiu::connectTimeoutNotify ()
{
this->lock ();
tsDLIterBD <nciu> chan ( this->chidList.first () );
while ( chan.valid () ) {
chan->connectTimeoutNotify ();
chan++;
}
this->unlock ();
}
void netiiu::resetChannelRetryCounts ()
{
this->lock ();
tsDLIterBD <nciu> chan ( this->chidList.first () );
while ( chan.valid () ) {
chan->resetRetryCount ();
chan++;
}
this->unlock ();
}
bool netiiu::searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisChannel )
{
bool status;
this->lock ();
tsDLIterBD <nciu> chan = this->chidList.first ();
if ( chan.valid () ) {
status = chan->searchMsg ( retrySeqNumber, retryNoForThisChannel );
if ( status ) {
this->chidList.remove ( *chan );
this->chidList.add ( *chan );
}
}
else {
status = false;
}
this->unlock ();
return status;
}
//
// considerable extra effort is taken in this routine to
// guarantee that the lock is not held while blocking
// in ::send () for buffer space.
//
void netiiu::sendPendingClaims ( tcpiiu &iiu, bool v42Ok, claimMsgCache &cache )
{
while ( 1 ) {
while (1) {
this->lock ();
tsDLIterBD < nciu > chan ( this->chidList.last () );
if ( ! chan.valid () ) {
this->unlock ();
return;
}
bool status = cache.set ( *chan );
if ( status ) {
this->unlock ();
break;
}
this->unlock ();
threadSleep ( 1.0 );
}
int status = cache.deliverMsg ( iiu );
if ( status != ECA_NORMAL ) {
break;
}
this->lock ();
// if the channel was not deleted while the lock was off
tsDLIterBD < nciu > chan ( this->chidList.last () );
if ( chan.valid () ) {
if ( cache.channelMatches ( *chan ) ) {
if ( ! v42Ok ) {
chan->connect ( iiu );
}
chan->attachChanToIIU ( iiu );
}
}
this->unlock ();
}
}
bool netiiu::ca_v42_ok () const
{
return false;
}
bool netiiu::ca_v41_ok () const
{
return false;
}
bool netiiu::pushDatagramMsg ( const caHdr &, const void *, ca_uint16_t )
{
return false;
}
bool netiiu::connectionInProgress ( const char *pChannelName, const osiSockAddr &addr ) const
{
return false;
}
void netiiu::lastChannelDetachNotify ()
{
}
int netiiu::writeRequest ( unsigned, unsigned, unsigned, const void * )
{
return ECA_DISCONNCHID;
}
int netiiu::writeNotifyRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem, const void *pValue )
{
return ECA_DISCONNCHID;
}
int netiiu::readCopyRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem )
{
return ECA_DISCONNCHID;
}
int netiiu::readNotifyRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem )
{
return ECA_DISCONNCHID;
}
int netiiu::createChannelRequest ( unsigned clientId, const char *pName, unsigned nameLength )
{
return ECA_DISCONNCHID;
}
int netiiu::clearChannelRequest ( unsigned clientId, unsigned serverId )
{
return ECA_DISCONNCHID;
}
int netiiu::subscriptionRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem, unsigned mask )
{
return ECA_DISCONNCHID;
}
int netiiu::subscriptionCancelRequest ( unsigned ioId, unsigned serverId, unsigned type, unsigned nElem )
{
return ECA_DISCONNCHID;
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef netiiuPtr_ILh
#define netiiuPtr_ILh
inline netiiuPtr::netiiuPtr () : piiu ( 0 )
{
}
inline netiiuPtr::~netiiuPtr ()
{
}
inline netiiu *netiiuPtr::pIIU () const
{
return this->piiu;
}
inline void netiiuPtr::setPointer ( netiiu *p )
{
this->piiu = p;
}
#endif // netiiuPtr_ILh
+35
View File
@@ -0,0 +1,35 @@
/*
* $Id$
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef netiiu_ILh
#define netiiu_ILh
inline netiiu::netiiu ( cac &cacIn ) :
cacRef ( cacIn )
{
}
inline netiiu::~netiiu ()
{
}
inline cac & netiiu::clientCtx () const
{
return this->cacRef;
}
#endif // netiiu_ILh
+3
View File
@@ -15,6 +15,8 @@
* 505 665 1831
*/
extern "C" void cacNoConnHandler ( struct connection_handler_args args );
struct oldChannel : public cacChannel {
public:
oldChannel (caCh *pConnCallBack, void *pPrivate);
@@ -42,6 +44,7 @@ private:
static tsFreeList < struct oldChannel, 1024 > freeList;
friend int epicsShareAPI ca_array_get (chtype type, unsigned long count, chid pChan, void *pValue);
friend void cacNoConnHandler ( struct connection_handler_args args );
};
class getCallback : public cacNotify {
+115 -95
View File
@@ -20,53 +20,6 @@
tsFreeList < struct oldChannel, 1024 > oldChannel::freeList;
oldChannel::oldChannel (caCh *pConnCallBackIn, void *pPrivateIn) :
pConnCallBack (pConnCallBackIn), pPrivate (pPrivateIn), pAccessRightsFunc (0)
{
}
oldChannel::~oldChannel ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->decrementOutstandingIO ();
}
this->unlock ();
}
void oldChannel::destroy ()
{
delete this;
}
void oldChannel::ioAttachNotify ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->incrementOutstandingIO ();
}
this->unlock ();
}
void oldChannel::ioReleaseNotify ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->decrementOutstandingIO ();
}
this->unlock ();
}
void oldChannel::setPrivatePointer (void *pPrivateIn)
{
this->pPrivate = pPrivateIn;
}
void * oldChannel::privatePointer () const
{
return this->pPrivate;
}
/*
* cacAlreadyConnHandler ()
* This is installed into channels which dont have
@@ -78,89 +31,156 @@ extern "C" void cacAlreadyConnHandler (struct connection_handler_args)
{
}
/*
* cacNoConnHandler ()
* This is installed into channels which dont have
* a connection handler before ca_pend_io() times
* out so that we will properly decrement the pending
* recv count in the future.
*/
extern "C" void cacNoConnHandler ( struct connection_handler_args args )
{
args.chid->lockOutstandingIO ();
if ( args.chid->pConnCallBack == cacNoConnHandler ) {
args.chid->pConnCallBack = cacAlreadyConnHandler;
if ( args.op == CA_OP_CONN_UP ) {
args.chid->decrementOutstandingIO ();
}
}
args.chid->unlockOutstandingIO ();
}
extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args )
{
}
oldChannel::oldChannel (caCh *pConnCallBackIn, void *pPrivateIn) :
pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler )
{
if ( ! pConnCallBackIn ) {
this->pConnCallBack = cacNoConnHandler;
}
else {
this->pConnCallBack = pConnCallBackIn;
}
}
oldChannel::~oldChannel ()
{
if ( this->pConnCallBack == cacNoConnHandler ) {
this->decrementOutstandingIO ();
}
}
void oldChannel::destroy ()
{
delete this;
}
void oldChannel::ioAttachNotify ()
{
this->lockOutstandingIO ();
if ( this->pConnCallBack == cacNoConnHandler ) {
this->incrementOutstandingIO ();
}
this->unlockOutstandingIO ();
}
void oldChannel::ioReleaseNotify ()
{
this->lockOutstandingIO ();
if ( this->pConnCallBack == cacNoConnHandler ) {
this->decrementOutstandingIO ();
}
this->unlockOutstandingIO ();
}
void oldChannel::setPrivatePointer ( void *pPrivateIn )
{
this->pPrivate = pPrivateIn;
}
void * oldChannel::privatePointer () const
{
return this->pPrivate;
}
void oldChannel::connectTimeoutNotify ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->lockOutstandingIO ();
if ( this->pConnCallBack == cacNoConnHandler ) {
this->pConnCallBack = cacAlreadyConnHandler;
}
this->unlock ();
this->unlockOutstandingIO ();
}
void oldChannel::connectNotify ()
{
this->lock ();
if ( this->pConnCallBack ) {
caCh *pCCB = this->pConnCallBack;
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_UP;
(*pCCB) (args);
}
else {
this->pConnCallBack = cacAlreadyConnHandler;
this->decrementOutstandingIO ();
}
this->unlock ();
this->lockOutstandingIO ();
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_UP;
(*this->pConnCallBack) (args);
this->unlockOutstandingIO ();
}
void oldChannel::disconnectNotify ()
{
this->lock ();
if ( this->pConnCallBack ) {
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_DOWN;
(*this->pConnCallBack) (args);
}
this->unlock ();
this->lockOutstandingIO ();
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_DOWN;
(*this->pConnCallBack) ( args );
this->unlockOutstandingIO ();
}
void oldChannel::accessRightsNotify (caar ar)
int oldChannel::changeConnCallBack ( caCh *pfunc )
{
this->lock ();
if ( this->pAccessRightsFunc ) {
struct access_rights_handler_args args;
args.chid = this;
args.ar = ar;
( *this->pAccessRightsFunc ) ( args );
}
this->unlock ();
}
int oldChannel::changeConnCallBack (caCh *pfunc)
{
this->lock ();
if ( pfunc == 0) {
if ( this->pConnCallBack != 0 ) {
if ( this->pConnCallBack != cacAlreadyConnHandler ) {
this->lockOutstandingIO ();
if ( ! pfunc ) {
if ( this->pConnCallBack != cacNoConnHandler &&
this->pConnCallBack != cacAlreadyConnHandler ) {
if ( this->state () == cs_never_conn ) {
this->incrementOutstandingIO ();
this->pConnCallBack = 0;
this->pConnCallBack = cacNoConnHandler;
}
else {
this->pConnCallBack = cacAlreadyConnHandler;
}
}
}
else {
if ( this->pConnCallBack == 0 ) {
if ( this->pConnCallBack == cacNoConnHandler ) {
this->decrementOutstandingIO ();
}
this->pConnCallBack = pfunc;
}
this->unlock ();
this->unlockOutstandingIO ();
return ECA_NORMAL;
}
int oldChannel::replaceAccessRightsEvent (caArh *pfunc)
void oldChannel::accessRightsNotify ( caar ar )
{
this->lock ();
struct access_rights_handler_args args;
args.chid = this;
args.ar = ar;
( *this->pAccessRightsFunc ) ( args );
}
int oldChannel::replaceAccessRightsEvent ( caArh *pfunc )
{
if ( ! pfunc ) {
pfunc = cacNoopAccesRightsHandler;
}
this->pAccessRightsFunc = pfunc;
if ( pfunc && this->connected () ) {
if ( this->connected () ) {
struct access_rights_handler_args args;
args.chid = this;
args.ar = this->accessRights ();
(*pfunc) (args);
}
this->unlock ();
return ECA_NORMAL;
}
@@ -18,8 +18,8 @@
#include <iocinf.h>
processThread::processThread (cac *pcacIn) :
osiThread ( "CAC-process", threadGetStackSize (threadStackSmall), threadPriorityMedium ),
recvProcessThread::recvProcessThread (cac *pcacIn) :
osiThread ( "CAC-recv-process", threadGetStackSize (threadStackSmall), threadPriorityMedium ),
pcac ( pcacIn ),
enableRefCount ( 0u ),
blockingForCompletion ( 0u ),
@@ -29,18 +29,18 @@ processThread::processThread (cac *pcacIn) :
this->start ();
}
processThread::~processThread ()
recvProcessThread::~recvProcessThread ()
{
this->signalShutDown ();
while ( ! this->exit.wait ( 10.0 ) ) {
printf ("processThread::~processThread (): Warning, thread object destroyed before thread exit \n");
errlogPrintf ("recvProcessThread::~recvProcessThread (): Warning, thread object destroyed before thread exit \n");
}
}
void processThread::entryPoint ()
void recvProcessThread::entryPoint ()
{
int status = ca_attach_context ( this->pcac );
SEVCHK ( status, "attaching to client context in process thread" );
SEVCHK ( status, "attaching to client context in recv process thread" );
while ( ! this->shutDown ) {
this->mutex.lock ();
@@ -58,18 +58,18 @@ void processThread::entryPoint ()
this->processingDone.signal ();
}
this->pcac->recvActivity.wait ();
this->recvActivity.wait ();
}
this->exit.signal ();
}
void processThread::signalShutDown ()
void recvProcessThread::signalShutDown ()
{
this->shutDown = true;
this->pcac->recvActivity.signal ();
this->recvActivity.signal ();
}
void processThread::enable ()
void recvProcessThread::enable ()
{
unsigned copy;
@@ -80,11 +80,11 @@ void processThread::enable ()
this->mutex.unlock ();
if ( copy == 0u ) {
this->pcac->recvActivity.signal ();
this->recvActivity.signal ();
}
}
void processThread::disable ()
void recvProcessThread::disable ()
{
bool waitNeeded;
@@ -111,4 +111,9 @@ void processThread::disable ()
this->processingDone.signal ();
}
}
}
void recvProcessThread::signalActivity ()
{
this->recvActivity.signal ();
}
+252 -170
View File
@@ -57,23 +57,44 @@
#include "iocinf.h"
#include "taskwd.h"
#ifdef DEBUG
# define debugPrintf(argsInParen) printf argsInParen
#else
# define debugPrintf(argsInParen)
#endif
/*
* one socket per client so we will get the ECONNREFUSED
* error code (and then delete the client)
*/
struct one_client {
ELLNODE node;
struct sockaddr_in from;
SOCKET sock;
class repeaterClient : public tsDLNode < repeaterClient > {
public:
repeaterClient ( const osiSockAddr &from );
bool connect ();
bool sendConfirm ();
bool sendMessage ( const void *pBuf, unsigned bufSize );
void destroy ();
bool verify ();
bool identicalAddress ( const osiSockAddr &from );
bool identicalPort ( const osiSockAddr &from );
void * operator new ( size_t size );
void operator delete ( void *pCadaver, size_t size );
private:
osiSockAddr from;
SOCKET sock;
static tsFreeList < class repeaterClient, 0x20 > freeList;
~repeaterClient ();
unsigned port () const;
};
/*
* these can be external since there is only one instance
* per machine so we dont care about reentrancy
*/
static ELLLIST client_list;
static tsDLList < repeaterClient > client_list;
tsFreeList < repeaterClient, 0x20 > repeaterClient::freeList;
static char buf[ETHERNET_MAX_UDP];
static char buf [MAX_UDP_RECV];
static const unsigned short PORT_ANY = 0u;
@@ -86,14 +107,14 @@ typedef struct {
/*
* makeSocket()
*/
LOCAL makeSocketReturn makeSocket (unsigned short port, int reuseAddr)
LOCAL makeSocketReturn makeSocket ( unsigned short port, bool reuseAddr )
{
int status;
struct sockaddr_in bd;
makeSocketReturn msr;
int flag;
msr.sock = socket (AF_INET, SOCK_DGRAM, 0);
msr.sock = socket ( AF_INET, SOCK_DGRAM, 0 );
if ( msr.sock == INVALID_SOCKET ) {
msr.errNumber = SOCKERRNO;
msr.pErrStr = SOCKERRSTR (msr.errNumber);
@@ -110,18 +131,18 @@ LOCAL makeSocketReturn makeSocket (unsigned short port, int reuseAddr)
bd.sin_addr.s_addr = htonl (INADDR_ANY);
bd.sin_port = htons (port);
status = bind (msr.sock, (struct sockaddr *)&bd, (int)sizeof(bd));
if (status<0) {
if ( status < 0 ) {
msr.errNumber = SOCKERRNO;
msr.pErrStr = SOCKERRSTR (msr.errNumber);
msr.pErrStr = SOCKERRSTR ( msr.errNumber );
socket_close (msr.sock);
msr.sock = INVALID_SOCKET;
return msr;
}
if (reuseAddr) {
flag = TRUE;
flag = true;
status = setsockopt ( msr.sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&flag, sizeof (flag) );
if (status<0) {
(char *) &flag, sizeof (flag) );
if ( status < 0 ) {
int errnoCpy = SOCKERRNO;
ca_printf (
"%s: set socket option failed because \"%s\"\n",
@@ -135,131 +156,233 @@ LOCAL makeSocketReturn makeSocket (unsigned short port, int reuseAddr)
return msr;
}
repeaterClient::repeaterClient ( const osiSockAddr &fromIn ) :
from ( fromIn ), sock ( INVALID_SOCKET )
{
debugPrintf ( ( "new client %u\n", ntohs ( from.ia.sin_port ) ) );
}
bool repeaterClient::connect ()
{
int status;
makeSocketReturn msr;
msr = makeSocket ( PORT_ANY, false );
if ( msr.sock == INVALID_SOCKET ) {
ca_printf ( "%s: no client sock because %d=\"%s\"\n",
__FILE__, msr.errNumber, msr.pErrStr );
return false;
}
this->sock = msr.sock;
status = ::connect ( this->sock, &this->from.sa, sizeof ( this->from.sa ) );
if ( status < 0 ) {
int errnoCpy = SOCKERRNO;
ca_printf (
"%s: unable to connect client sock because \"%s\"\n",
__FILE__, SOCKERRSTR ( errnoCpy ) );
return false;
}
return true;
}
bool repeaterClient::sendConfirm ()
{
int status;
caHdr confirm;
memset ( (char *) &confirm, '\0', sizeof (confirm) );
confirm.m_cmmd = htons ( REPEATER_CONFIRM );
confirm.m_available = this->from.ia.sin_addr.s_addr;
status = send ( this->sock, (char *) &confirm,
sizeof (confirm), 0 );
if ( status >= 0 ) {
assert ( status == sizeof ( confirm ) );
return true;
}
else if ( SOCKERRNO == SOCK_ECONNREFUSED ) {
return false;
}
else {
ca_printf ( "CA Repeater: confirm err was \"%s\"\n",
SOCKERRSTR (SOCKERRNO) );
return false;
}
}
bool repeaterClient::sendMessage ( const void *pBuf, unsigned bufSize )
{
int status;
status = send ( this->sock, (char *) pBuf, bufSize, 0 );
if ( status >= 0 ) {
assert ( status == bufSize );
debugPrintf ( ("Sent to %u\n", ntohs ( this->from.ia.sin_port ) ) );
return true;
}
else {
int errnoCpy = SOCKERRNO;
if ( errnoCpy == SOCK_ECONNREFUSED ) {
debugPrintf ( ("Client refused message %u\n", ntohs ( this->from.ia.sin_port ) ) );
}
else {
debugPrintf ( ( "CA Repeater: UDP send err was \"%s\"\n", SOCKERRSTR (errnoCpy) ) );
}
return false;
}
}
repeaterClient::~repeaterClient ()
{
if ( this->sock != INVALID_SOCKET ) {
socket_close ( this->sock );
}
debugPrintf ( ( "Deleted client %u\n", ntohs ( this->from.ia.sin_port ) ) );
}
inline void * repeaterClient::operator new ( size_t size )
{
return repeaterClient::freeList.allocate ( size );
}
inline void repeaterClient::operator delete ( void *pCadaver, size_t size )
{
repeaterClient::freeList.release ( pCadaver, size );
}
inline void repeaterClient::destroy ()
{
delete this;
}
inline unsigned repeaterClient::port () const
{
return ntohs ( this->from.ia.sin_port );
}
inline bool repeaterClient::identicalAddress ( const osiSockAddr &from )
{
if ( from.sa.sa_family == this->from.sa.sa_family ) {
if ( from.ia.sin_port == this->from.ia.sin_port) {
if ( from.ia.sin_addr.s_addr == this->from.ia.sin_addr.s_addr ) {
return true;
}
}
}
return false;
}
inline bool repeaterClient::identicalPort ( const osiSockAddr &from )
{
if ( from.sa.sa_family == this->from.sa.sa_family ) {
if ( from.ia.sin_port == this->from.ia.sin_port) {
return true;
}
}
return false;
}
bool repeaterClient::verify ()
{
makeSocketReturn msr;
msr = makeSocket ( this->port (), false );
if ( msr.sock != INVALID_SOCKET ) {
socket_close ( msr.sock );
return false;
}
else {
/*
* win sock does not set SOCKERRNO when this fails
*/
if ( msr.errNumber != SOCK_EADDRINUSE ) {
ca_printf (
"CA Repeater: bind test err was %d=\"%s\"\n",
msr.errNumber, msr.pErrStr );
}
return true;
}
}
/*
* verifyClients()
* (this is required because solaris has a half baked version of sockets)
*/
LOCAL void verifyClients()
{
ELLLIST theClients;
struct one_client *pclient;
makeSocketReturn msr;
static tsDLList < repeaterClient > theClients;
repeaterClient *pclient;
ellInit(&theClients);
while ( (pclient=(struct one_client *)ellGet(&client_list)) ) {
ellAdd (&theClients, &pclient->node);
msr = makeSocket ( ntohs (pclient->from.sin_port), FALSE );
if ( msr.sock != INVALID_SOCKET ) {
#ifdef DEBUG
ca_printf ("Deleted client %d\n",
ntohs (pclient->from.sin_port) );
#endif
ellDelete (&theClients, &pclient->node);
socket_close (msr.sock);
socket_close (pclient->sock);
free (pclient);
while ( pclient = client_list.get () ) {
if ( pclient->verify () ) {
theClients.add ( *pclient );
}
else {
/*
* win sock does not set SOCKERRNO when this fails
*/
if ( msr.errNumber != SOCK_EADDRINUSE ) {
ca_printf (
"CA Repeater: bind test err was %d=\"%s\"\n",
msr.errNumber, msr.pErrStr);
}
pclient->destroy ();
}
}
ellConcat (&client_list, &theClients);
client_list.add ( theClients );
}
/*
* fanOut()
*/
LOCAL void fanOut (struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize)
LOCAL void fanOut ( const osiSockAddr &from, const void *pMsg, unsigned msgSize )
{
ELLLIST theClients;
struct one_client *pclient;
int status;
int verify = FALSE;
static tsDLList < repeaterClient > theClients;
repeaterClient *pclient;
ellInit(&theClients);
while ( ( pclient = (struct one_client *) ellGet (&client_list) ) ) {
ellAdd(&theClients, &pclient->node);
/*
* Dont reflect back to sender
*/
if(pFrom->sin_port == pclient->from.sin_port &&
pFrom->sin_addr.s_addr == pclient->from.sin_addr.s_addr){
while ( pclient = client_list.get () ) {
theClients.add ( *pclient );
/* Dont reflect back to sender */
if ( pclient->identicalAddress ( from ) ) {
continue;
}
status = send ( pclient->sock, (char *)pMsg, msgSize, 0 );
if ( status >= 0 ) {
#ifdef DEBUG
ca_printf ("Sent to %d\n",
ntohs (pclient->from.sin_port));
#endif
}
if ( status < 0 ) {
int errnoCpy = SOCKERRNO;
if ( errnoCpy == SOCK_ECONNREFUSED ) {
#ifdef DEBUG
ca_printf ("Deleted client %d\n",
ntohs (pclient->from.sin_port));
#endif
verify = TRUE;
}
else {
ca_printf (
"CA Repeater: UDP fan out err was \"%s\"\n",
SOCKERRSTR(errnoCpy));
if ( ! pclient->sendMessage ( pMsg, msgSize ) ) {
if ( ! pclient->verify () ) {
theClients.remove ( *pclient );
pclient->destroy ();
}
}
}
ellConcat(&client_list, &theClients);
if (verify) {
verifyClients ();
}
client_list.add ( theClients );
}
/*
* register_new_client()
*/
LOCAL void register_new_client (struct sockaddr_in *pFrom)
LOCAL void register_new_client ( osiSockAddr &from )
{
int status;
struct one_client *pclient;
caHdr confirm;
caHdr noop;
int newClient = FALSE;
bool newClient = false;
makeSocketReturn msr;
if (pFrom->sin_family != AF_INET) {
if ( from.sa.sa_family != AF_INET ) {
return;
}
/*
* the repeater and its clients must be on the same host
*/
if ( htonl(INADDR_LOOPBACK) != pFrom->sin_addr.s_addr ) {
if ( htonl ( INADDR_LOOPBACK ) != from.ia.sin_addr.s_addr ) {
static SOCKET testSock = INVALID_SOCKET;
static int init;
struct sockaddr_in ina;
static bool init = false;
if ( ! init ) {
msr = makeSocket (PORT_ANY, TRUE);
msr = makeSocket ( PORT_ANY, true );
if ( msr.sock == INVALID_SOCKET ) {
ca_printf("%s: Unable to create repeater bind test socket because %d=\"%s\"\n",
__FILE__, msr.errNumber, msr.pErrStr);
ca_printf ( "%s: Unable to create repeater bind test socket because %d=\"%s\"\n",
__FILE__, msr.errNumber, msr.pErrStr );
}
else {
testSock = msr.sock;
}
init = TRUE;
init = true;
}
/*
@@ -272,12 +395,14 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
* to current code.
*/
if ( testSock != INVALID_SOCKET ) {
ina = *pFrom;
ina.sin_port = PORT_ANY;
osiSockAddr addr;
addr = from;
addr.ia.sin_port = PORT_ANY;
/* we can only bind to a local address */
status = bind ( testSock, (struct sockaddr *) &ina, (int) sizeof (ina) );
if (status) {
status = bind ( testSock, &addr.sa, sizeof ( addr ) );
if ( status ) {
return;
}
}
@@ -286,84 +411,45 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
}
}
for ( pclient = (struct one_client *) ellFirst (&client_list);
pclient; pclient = (struct one_client *) ellNext (&pclient->node) ){
if ( pFrom->sin_port == pclient->from.sin_port ) {
tsDLIterBD < repeaterClient > pclient = client_list.first ();
while ( pclient.valid () ) {
if ( pclient->identicalPort ( from ) ) {
break;
}
pclient = pclient.itemAfter ();
}
if ( ! pclient ) {
pclient = (struct one_client *) calloc ( 1, sizeof (*pclient) );
if ( ! pclient ) {
if ( ! pclient.valid () ) {
pclient = new repeaterClient ( from );
if ( ! pclient.valid () ) {
ca_printf ( "%s: no memory for new client\n", __FILE__ );
return;
}
msr = makeSocket (PORT_ANY, FALSE);
if ( msr.sock==INVALID_SOCKET ) {
free ( pclient );
ca_printf ( "%s: no client sock because %d=\"%s\"\n",
__FILE__, msr.errNumber, msr.pErrStr );
if ( ! pclient->connect () ) {
pclient->destroy ();
return;
}
pclient->sock = msr.sock;
status = connect ( pclient->sock,
(struct sockaddr *) pFrom,
sizeof ( *pFrom ) );
if ( status < 0 ) {
int errnoCpy = SOCKERRNO;
ca_printf (
"%s: unable to connect client sock because \"%s\"\n",
__FILE__, SOCKERRSTR (errnoCpy) );
socket_close ( pclient->sock );
free ( pclient );
return;
}
pclient->from = *pFrom;
ellAdd ( &client_list, &pclient->node );
newClient = TRUE;
#ifdef DEBUG
ca_printf ( "Added %d\n", ntohs (pFrom->sin_port) );
#endif
client_list.add ( *pclient );
newClient = true;
}
memset ( (char *) &confirm, '\0', sizeof (confirm) );
confirm.m_cmmd = htons (REPEATER_CONFIRM);
confirm.m_available = pFrom->sin_addr.s_addr;
status = send ( pclient->sock, (char *) &confirm,
sizeof (confirm), 0 );
if ( status >= 0 ) {
assert ( status == sizeof (confirm) );
}
else if ( SOCKERRNO == SOCK_ECONNREFUSED ){
#ifdef DEBUG
ca_printf ( "Deleted repeater client=%d sending ack\n",
ntohs (pFrom->sin_port) );
#endif
ellDelete ( &client_list, &pclient->node );
socket_close ( pclient->sock );
free ( pclient );
}
else {
ca_printf ( "CA Repeater: confirm err was \"%s\"\n",
SOCKERRSTR (SOCKERRNO) );
if ( ! pclient->sendConfirm () ) {
client_list.remove (*pclient );
pclient->destroy ();
debugPrintf ( ( "Deleted repeater client=%u (error while sending ack)\n",
ntohs (from.ia.sin_port) ) );
}
/*
* send a noop message to all other clients so that we dont
* accumulate sockets when there are no beacons
*/
memset ( (char *) &noop, '\0', sizeof (noop) );
confirm.m_cmmd = htons (CA_PROTO_NOOP);
fanOut ( pFrom, (char *)&noop, sizeof (noop) );
caHdr noop;
memset ( (char *) &noop, '\0', sizeof ( noop ) );
noop.m_cmmd = htons ( CA_PROTO_NOOP );
fanOut ( from, &noop, sizeof ( noop ) );
if ( newClient ) {
/*
@@ -389,8 +475,8 @@ void epicsShareAPI ca_repeater ()
{
int size;
SOCKET sock;
struct sockaddr_in from;
int from_size = sizeof from;
osiSockAddr from;
int from_size = sizeof ( from );
unsigned short port;
makeSocketReturn msr;
@@ -398,9 +484,7 @@ void epicsShareAPI ca_repeater ()
port = envGetInetPortConfigParam ( &EPICS_CA_REPEATER_PORT, CA_REPEATER_PORT );
ellInit(&client_list);
msr = makeSocket (port, TRUE);
msr = makeSocket ( port, true );
if ( msr.sock == INVALID_SOCKET ) {
/*
* test for server was already started
@@ -417,15 +501,13 @@ void epicsShareAPI ca_repeater ()
sock = msr.sock;
#ifdef DEBUG
ca_printf ("CA Repeater: Attached and initialized\n");
#endif
debugPrintf ( ( "CA Repeater: Attached and initialized\n" ) );
while (TRUE) {
while ( true ) {
caHdr *pMsg;
size = recvfrom ( sock, buf, sizeof (buf), 0,
(struct sockaddr *)&from, &from_size );
&from.sa, &from_size );
if ( size < 0 ) {
int errnoCpy = SOCKERRNO;
# ifdef linux
@@ -449,8 +531,8 @@ void epicsShareAPI ca_repeater ()
* will register a new client
*/
if ( ( (size_t) size) >= sizeof (*pMsg) ) {
if ( ntohs(pMsg->m_cmmd) == REPEATER_REGISTER ) {
register_new_client (&from);
if ( ntohs ( pMsg->m_cmmd ) == REPEATER_REGISTER ) {
register_new_client ( from );
/*
* strip register client message
@@ -463,21 +545,21 @@ void epicsShareAPI ca_repeater ()
}
}
else if (size == 0) {
register_new_client (&from);
register_new_client ( from );
continue;
}
fanOut (&from, (char *) pMsg, size);
fanOut ( from, pMsg, size );
}
}
/*
* caRepeaterThread ()
*/
void caRepeaterThread (void * /* pDummy */ )
void caRepeaterThread ( void * /* pDummy */ )
{
taskwdInsert (threadGetIdSelf(), NULL, NULL);
ca_repeater();
taskwdInsert ( threadGetIdSelf(), NULL, NULL );
ca_repeater ();
}
+133 -209
View File
@@ -13,50 +13,40 @@
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Notes:
* 1) when rdix is equal to wtix it indicates that the entire buffer is
* available to be read, and therefore nothing can be written.
* 2) the byte at index rdix + 1 is the next byte to read.
* 3) the byte at index wtix is the next byte to write.
*/
#include <string.h>
#include "ringBuffer.h"
static const unsigned ringIndexMask = nElementsInRing-1;
static const unsigned ringIndexMask = nElementsInRing - 1;
/*
* cacRingBufferConstruct ()
*/
int cacRingBufferConstruct (ringBuffer *pBuf)
bool cacRingBufferConstruct ( ringBuffer *pBuf )
{
pBuf->shutDown = 0u;
pBuf->rdix = 0u;
pBuf->wtix = 1u;
pBuf->readSignal = semBinaryCreate (semEmpty);
if (!pBuf->readSignal) {
return -1;
}
pBuf->writeSignal = semBinaryCreate (semEmpty);
if (!pBuf->writeSignal) {
semBinaryDestroy (pBuf->readSignal);
return -1;
}
pBuf->readLock = semMutexCreate ();
if (!pBuf->readLock) {
semBinaryDestroy (pBuf->readSignal);
semBinaryDestroy (pBuf->writeSignal);
return -1;
if ( ! pBuf->readLock ) {
return false;
}
pBuf->writeLock = semMutexCreate ();
if (!pBuf->writeLock) {
semBinaryDestroy (pBuf->readSignal);
semBinaryDestroy (pBuf->writeSignal);
semMutexDestroy (pBuf->readLock);
return -1;
if ( ! pBuf->writeLock ) {
semMutexDestroy ( pBuf->readLock );
return false;
}
return 0;
return true;
}
/*
@@ -64,35 +54,23 @@ int cacRingBufferConstruct (ringBuffer *pBuf)
*/
void cacRingBufferDestroy (ringBuffer *pBuf)
{
semBinaryDestroy (pBuf->readSignal);
semBinaryDestroy (pBuf->writeSignal);
semMutexDestroy (pBuf->readLock);
semMutexDestroy (pBuf->writeLock);
}
/*
* cacRingBufferShutDown ();
*/
void cacRingBufferShutDown (ringBuffer *pBuf)
{
pBuf->shutDown = 1u;
semBinaryGive (pBuf->readSignal);
semBinaryGive (pBuf->writeSignal);
semMutexDestroy ( pBuf->readLock );
semMutexDestroy ( pBuf->writeLock );
}
/*
* cacRingBufferReadSize ()
*/
static inline unsigned cacRingBufferReadSize (ringBuffer *pBuf)
static inline unsigned cacRingBufferReadSize ( ringBuffer *pBuf )
{
unsigned long count;
if ( pBuf->wtix <= pBuf->rdix ) {
static const unsigned bufSizeM1 = sizeof (pBuf->buf) - 1u;
static const unsigned bufSizeM1 = sizeof ( pBuf->buf ) - 1u;
count = ( bufSizeM1 - pBuf->rdix ) + pBuf->wtix;
}
else {
count = (pBuf->wtix - pBuf->rdix) - 1u;
count = ( pBuf->wtix - pBuf->rdix ) - 1u;
}
return count;
}
@@ -102,11 +80,11 @@ static inline unsigned cacRingBufferReadSize (ringBuffer *pBuf)
*/
static inline unsigned cacRingBufferContiguousReadSize (ringBuffer *pBuf)
{
static const unsigned bufSizeM1 = sizeof (pBuf->buf) - 1u;
unsigned long count;
static const unsigned bufSizeM1 = sizeof ( pBuf->buf ) - 1u;
unsigned long count;
if ( pBuf->wtix <= pBuf->rdix ) {
if (pBuf->rdix==bufSizeM1) {
if ( pBuf->rdix == bufSizeM1 ) {
count = pBuf->wtix;
}
else {
@@ -114,7 +92,7 @@ static inline unsigned cacRingBufferContiguousReadSize (ringBuffer *pBuf)
}
}
else {
count = (pBuf->wtix - pBuf->rdix) - 1u;
count = ( pBuf->wtix - pBuf->rdix ) - 1u;
}
return count;
}
@@ -122,11 +100,11 @@ static inline unsigned cacRingBufferContiguousReadSize (ringBuffer *pBuf)
/*
* cacRingBufferWriteSize ()
*/
static inline unsigned cacRingBufferWriteSize (ringBuffer *pBuf)
static inline unsigned cacRingBufferWriteSize ( ringBuffer *pBuf )
{
unsigned long count;
if (pBuf->wtix <= pBuf->rdix) {
if ( pBuf->wtix <= pBuf->rdix ) {
count = pBuf->rdix - pBuf->wtix;
}
else {
@@ -138,15 +116,15 @@ static inline unsigned cacRingBufferWriteSize (ringBuffer *pBuf)
/*
* cacRingBufferContiguousWriteSize ()
*/
static inline unsigned cacRingBufferContiguousWriteSize (ringBuffer *pBuf)
static inline unsigned cacRingBufferContiguousWriteSize ( ringBuffer *pBuf )
{
unsigned long count;
if (pBuf->wtix <= pBuf->rdix) {
if ( pBuf->wtix <= pBuf->rdix ) {
count = pBuf->rdix - pBuf->wtix;
}
else {
count = sizeof (pBuf->buf) - pBuf->wtix;
count = sizeof ( pBuf->buf ) - pBuf->wtix;
}
return count;
}
@@ -158,17 +136,23 @@ static inline unsigned cacRingBufferContiguousWriteSize (ringBuffer *pBuf)
* returns the number of bytes read which may be less than
* the number requested.
*/
static unsigned cacRingBufferReadPartial (ringBuffer *pRing, void *pBuf,
unsigned nBytes)
static unsigned cacRingBufferReadPartial ( ringBuffer *pRing, void *pBuf,
unsigned nBytes )
{
unsigned totalBytes;
if ( pRing->wtix < pRing->rdix ) {
static const unsigned bufSizeM1 = sizeof (pRing->buf) - 1u;
if ( pRing->wtix <= pRing->rdix ) {
static const unsigned bufSizeM1 = sizeof ( pRing->buf ) - 1u;
unsigned nBytesAvail1stBlock, nBytesAvail2ndBlock;
nBytesAvail1stBlock = bufSizeM1 - pRing->rdix;
nBytesAvail2ndBlock = pRing->wtix;
if ( pRing->rdix == bufSizeM1 ) {
nBytesAvail1stBlock = pRing->wtix;
nBytesAvail2ndBlock = 0u;
}
else {
nBytesAvail1stBlock = bufSizeM1 - pRing->rdix;
nBytesAvail2ndBlock = pRing->wtix;
}
if ( nBytesAvail1stBlock >= nBytes ) {
totalBytes = nBytes;
memcpy ( pBuf, pRing->buf + pRing->rdix + 1u, totalBytes );
@@ -186,53 +170,15 @@ static unsigned cacRingBufferReadPartial (ringBuffer *pRing, void *pBuf,
pRing->rdix += totalBytes;
pRing->rdix &= ringIndexMask;
}
else if ( pRing->wtix > pRing->rdix ) {
totalBytes = (pRing->wtix - pRing->rdix) - 1;
else {
totalBytes = ( pRing->wtix - pRing->rdix ) - 1;
if ( totalBytes > nBytes ) {
totalBytes = nBytes;
}
memcpy (pBuf, pRing->buf+pRing->rdix+1, totalBytes);
memcpy ( pBuf, pRing->buf+pRing->rdix+1, totalBytes );
pRing->rdix += totalBytes;
pRing->rdix &= ringIndexMask;
}
else {
totalBytes = 0;
}
return totalBytes;
}
/*
* cacRingBufferRead ()
*
* returns the number of bytes read which may be less than
* the number requested.
*/
unsigned cacRingBufferRead (ringBuffer *pRing, void *pBuf,
unsigned nBytes)
{
unsigned char *pBufTmp = (unsigned char *) pBuf;
unsigned totalBytes = 0;
unsigned curBytes;
semMutexMustTake (pRing->readLock);
while (totalBytes<nBytes) {
curBytes = cacRingBufferReadPartial (pRing,
pBufTmp+totalBytes, nBytes-totalBytes);
if (curBytes==0) {
semBinaryMustTake (pRing->readSignal);
if (pRing->shutDown) {
semMutexGive (pRing->readLock);
return totalBytes;
}
}
else {
totalBytes += curBytes;
}
}
semMutexGive (pRing->readLock);
return totalBytes;
}
@@ -243,8 +189,8 @@ unsigned cacRingBufferRead (ringBuffer *pRing, void *pBuf,
* returns the number of bytes written which may be less than
* the number requested.
*/
static unsigned cacRingBufferWritePartial (ringBuffer *pRing,
const void *pBuf, unsigned nBytes)
static unsigned cacRingBufferWritePartial ( ringBuffer *pRing,
const void *pBuf, unsigned nBytes )
{
unsigned totalBytes;
@@ -287,96 +233,37 @@ static unsigned cacRingBufferWritePartial (ringBuffer *pRing,
return totalBytes;
}
/*
* cacRingBufferWrite ()
*
* returns the number of bytes written which may be less than
* the number requested.
*/
unsigned cacRingBufferWrite (ringBuffer *pRing, const void *pBuf,
unsigned nBytes)
void cacRingBufferWriteLock ( ringBuffer *pBuf )
{
unsigned char *pBufTmp = (unsigned char *) pBuf;
unsigned totalBytes = 0;
unsigned curBytes;
semMutexMustTake ( pRing->writeLock );
while ( totalBytes < nBytes ) {
curBytes = cacRingBufferWritePartial ( pRing,
pBufTmp+totalBytes, nBytes-totalBytes );
if ( curBytes == 0 ) {
semBinaryGive ( pRing->readSignal );
semBinaryMustTake ( pRing->writeSignal );
if ( pRing->shutDown ) {
semMutexGive ( pRing->writeLock );
return totalBytes;
}
}
else {
totalBytes += curBytes;
}
}
semMutexGive ( pRing->writeLock );
return totalBytes;
semMutexMustTake ( pBuf->writeLock );
}
void cacRingBufferWriteLock (ringBuffer *pBuf)
bool cacRingBufferWriteLockIfBytesAvailable ( ringBuffer *pBuf, unsigned bytesRequired )
{
semMutexMustTake (pBuf->writeLock);
}
bool cacRingBufferWriteLockNoBlock (ringBuffer *pBuf, unsigned bytesRequired)
{
semMutexMustTake (pBuf->writeLock);
semMutexMustTake ( pBuf->writeLock );
if ( cacRingBufferWriteSize (pBuf) < bytesRequired ) {
semMutexGive (pBuf->writeLock);
semMutexGive ( pBuf->writeLock );
return false;
}
return true;
}
void cacRingBufferWriteUnlock (ringBuffer *pBuf)
void cacRingBufferWriteUnlock ( ringBuffer *pBuf )
{
semMutexGive (pBuf->writeLock);
semMutexGive ( pBuf->writeLock );
}
void *cacRingBufferWriteReserve (ringBuffer *pRing, unsigned *pBytesAvail)
void *cacRingBufferWriteReserve ( ringBuffer *pRing, unsigned *pBytesAvail )
{
unsigned avail;
semMutexMustTake (pRing->writeLock);
semMutexMustTake ( pRing->writeLock );
avail = cacRingBufferContiguousWriteSize (pRing);
while (avail==0) {
semBinaryGive (pRing->readSignal);
semBinaryMustTake (pRing->writeSignal);
if (pRing->shutDown) {
semMutexGive (pRing->writeLock);
*pBytesAvail = 0u;
return 0;
}
avail = cacRingBufferContiguousWriteSize (pRing);
}
avail = cacRingBufferContiguousWriteSize ( pRing );
*pBytesAvail = avail;
return (void *) &pRing->buf[pRing->wtix];
}
void *cacRingBufferWriteReserveNoBlock (ringBuffer *pRing, unsigned *pBytesAvail)
{
unsigned avail;
semMutexMustTake (pRing->writeLock);
avail = cacRingBufferContiguousWriteSize (pRing);
if ( avail==0 || pRing->shutDown ) {
if ( avail == 0 ) {
*pBytesAvail = 0u;
semMutexGive (pRing->writeLock);
semMutexGive ( pRing->writeLock );
return NULL;
}
@@ -385,76 +272,113 @@ void *cacRingBufferWriteReserveNoBlock (ringBuffer *pRing, unsigned *pBytesAvail
return (void *) &pRing->buf[pRing->wtix];
}
void cacRingBufferWriteCommit (ringBuffer *pRing, unsigned delta)
void cacRingBufferWriteCommit ( ringBuffer *pRing, unsigned delta )
{
pRing->wtix += delta;
pRing->wtix &= ringIndexMask;
semMutexGive (pRing->writeLock);
semMutexGive ( pRing->writeLock );
}
void *cacRingBufferReadReserve (ringBuffer *pRing, unsigned *pBytesAvail)
bool cacRingBufferWriteNoBlock ( ringBuffer *pBuf, const void *pMsg, unsigned bytesRequired )
{
unsigned avail;
unsigned nBytesWritten;
semMutexMustTake (pRing->readLock);
avail = cacRingBufferContiguousReadSize (pRing);
while (avail==0) {
semBinaryMustTake (pRing->readSignal);
if (pRing->shutDown) {
semMutexGive (pRing->readLock);
*pBytesAvail = 0u;
return NULL;
}
avail = cacRingBufferContiguousReadSize (pRing);
semMutexMustTake ( pBuf->writeLock );
if ( cacRingBufferWriteSize ( pBuf ) < bytesRequired ) {
semMutexGive ( pBuf->writeLock );
return false;
}
*pBytesAvail = avail;
return (void *) &pRing->buf[(pRing->rdix+1) & ringIndexMask];
nBytesWritten = cacRingBufferWritePartial ( pBuf, pMsg, bytesRequired );
semMutexGive ( pBuf->writeLock );
return nBytesWritten == bytesRequired;
}
void *cacRingBufferReadReserveNoBlock (ringBuffer *pRing, unsigned *pBytesAvail)
bool cacRingBufferWriteMultipartMessageNoBlock ( ringBuffer *pBuf,
const msgDescriptor *pMsgs, unsigned nMsgs )
{
unsigned i;
unsigned totalBytes = 0u;
unsigned nBytesWritten;
for ( i = 0u; i < nMsgs; i++ ) {
totalBytes += pMsgs[i].length;
}
semMutexMustTake ( pBuf->writeLock );
if ( cacRingBufferWriteSize ( pBuf ) < totalBytes ) {
semMutexGive ( pBuf->writeLock );
return false;
}
for ( i = 0u; i < nMsgs; i++ ) {
nBytesWritten = cacRingBufferWritePartial ( pBuf,
pMsgs[i].pMsg, pMsgs[i].length );
if ( nBytesWritten != pMsgs[i].length ) {
semMutexGive ( pBuf->writeLock );
return false;
}
}
semMutexGive ( pBuf->writeLock );
return true;
}
unsigned cacRingBufferWrite ( ringBuffer *pBuf, const void *pMsg, unsigned nBytes )
{
unsigned nBytesWritten;
semMutexMustTake ( pBuf->writeLock );
nBytesWritten = cacRingBufferWritePartial ( pBuf, pMsg, nBytes );
semMutexGive ( pBuf->writeLock );
return nBytesWritten;
}
void *cacRingBufferReadReserve ( ringBuffer *pRing, unsigned *pBytesAvail )
{
unsigned avail;
semMutexMustTake (pRing->readLock);
semMutexMustTake ( pRing->readLock );
avail = cacRingBufferContiguousReadSize (pRing);
avail = cacRingBufferContiguousReadSize ( pRing );
if ( avail==0 || pRing->shutDown ) {
if ( avail == 0 ) {
*pBytesAvail = 0u;
semMutexGive (pRing->readLock);
semMutexGive ( pRing->readLock );
return NULL;
}
*pBytesAvail = avail;
return (void *) &pRing->buf[(pRing->rdix+1) & ringIndexMask];
return (void *) &pRing->buf[ ( pRing->rdix + 1 ) & ringIndexMask ];
}
void cacRingBufferReadCommit (ringBuffer *pRing, unsigned delta)
void cacRingBufferReadCommit ( ringBuffer *pRing, unsigned delta )
{
pRing->rdix += delta;
pRing->rdix &= ringIndexMask;
semMutexGive (pRing->readLock);
semMutexGive ( pRing->readLock );
}
bool cacRingBufferWriteFlush (ringBuffer *pRing)
bool cacRingBufferReadNoBlock ( ringBuffer *pBuf, void *pDest, unsigned nBytesRequired )
{
if ( cacRingBufferReadSize (pRing) ) {
semBinaryGive (pRing->readSignal);
return true;
semMutexMustTake ( pBuf->readLock );
unsigned available = cacRingBufferReadSize ( pBuf );
if ( available < nBytesRequired) {
semMutexGive ( pBuf->readLock );
return false;
}
return false;
char *pCurrent = static_cast <char *> ( pDest );
unsigned totalBytes = cacRingBufferReadPartial ( pBuf, pCurrent, nBytesRequired );
unsigned diff = nBytesRequired - totalBytes;
if ( diff ) {
totalBytes += cacRingBufferReadPartial ( pBuf, &pCurrent[totalBytes], diff );
assert ( totalBytes == nBytesRequired );
}
semMutexGive ( pBuf->readLock );
return true;
}
bool cacRingBufferReadFlush (ringBuffer *pRing)
{
if ( cacRingBufferWriteSize (pRing) ) {
semBinaryGive (pRing->writeSignal);
return true;
}
return false;
}
+19 -21
View File
@@ -25,45 +25,43 @@
#define nElementsInRing (1<<nBitsRingIndex)
typedef struct ringBuffer {
semBinaryId readSignal;
semBinaryId writeSignal;
semMutexId readLock;
semMutexId writeLock;
unsigned rdix; /* index of last char read */
unsigned wtix; /* index of next char to write */
unsigned shutDown;
char buf[nElementsInRing];
} ringBuffer;
int cacRingBufferConstruct (ringBuffer *pBuf);
void cacRingBufferDestroy (ringBuffer *pBuf);
bool cacRingBufferConstruct ( ringBuffer *pBuf );
unsigned cacRingBufferWrite (ringBuffer *pRing,
const void *pBuf, unsigned nBytes);
void cacRingBufferDestroy ( ringBuffer *pBuf );
unsigned cacRingBufferRead (ringBuffer *pRing,
void *pBuf, unsigned nBytes);
void cacRingBufferWriteLock ( ringBuffer *pBuf );
void cacRingBufferWriteLock (ringBuffer *pBuf);
bool cacRingBufferWriteLockIfBytesAvailable ( ringBuffer *pBuf, unsigned bytesRequired );
bool cacRingBufferWriteLockNoBlock (ringBuffer *pBuf, unsigned bytesRequired);
void cacRingBufferWriteUnlock ( ringBuffer *pBuf );
void cacRingBufferWriteUnlock (ringBuffer *pBuf);
unsigned cacRingBufferWrite ( ringBuffer *pBuf, const void *pMsg, unsigned nBytes );
void *cacRingBufferWriteReserve (ringBuffer *pBuf, unsigned *pAvailBytes);
bool cacRingBufferWriteNoBlock ( ringBuffer *pBuf, const void *pMsg, unsigned nBytes );
void cacRingBufferWriteCommit (ringBuffer *pBuf, unsigned delta);
struct msgDescriptor {
const void *pMsg;
unsigned length;
};
void *cacRingBufferReadReserve (ringBuffer *pBuf, unsigned *pBytesAvail);
bool cacRingBufferWriteMultipartMessageNoBlock ( ringBuffer *pBuf,
const msgDescriptor *pMsgs, unsigned nMsgs );
void *cacRingBufferReadReserveNoBlock (ringBuffer *pBuf, unsigned *pBytesAvail);
void *cacRingBufferWriteReserve ( ringBuffer *pBuf, unsigned *pBytesAvail );
void cacRingBufferReadCommit (ringBuffer *pBuf, unsigned delta);
void cacRingBufferWriteCommit ( ringBuffer *pBuf, unsigned delta );
// return true if there was something to flush and otherwise false
bool cacRingBufferReadFlush (ringBuffer *pBuf);
bool cacRingBufferWriteFlush (ringBuffer *pBuf);
void *cacRingBufferReadReserve ( ringBuffer *pBuf, unsigned *pBytesAvail );
void cacRingBufferShutDown (ringBuffer *pBuf);
bool cacRingBufferReadNoBlock ( ringBuffer *pBuf, void *pDest, unsigned nBytesRequired );
void cacRingBufferReadCommit ( ringBuffer *pBuf, unsigned delta );
#endif /* ringBufferh */
+58 -79
View File
@@ -28,10 +28,10 @@ searchTimer::searchTimer (udpiiu &iiuIn, osiTimerQueue &queueIn) :
framesPerTryCongestThresh (UINT_MAX),
minRetry (UINT_MAX),
retry (0u),
searchTries (0u),
searchResponses (0u),
searchTriesWithinThisPass (0u),
searchResponsesWithinThisPass (0u),
retrySeqNo (0u),
retrySeqNoAtListBegin (0u),
retrySeqAtPassBegin (0u),
period (CA_RECAST_DELAY)
{
}
@@ -47,7 +47,7 @@ void searchTimer::reset ( double delayToNextTry )
delayToNextTry = CA_RECAST_DELAY;
}
this->iiu.pcas->lock ();
this->lock ();
this->retry = 0;
if ( this->period > delayToNextTry ) {
reschedule = true;
@@ -56,7 +56,7 @@ void searchTimer::reset ( double delayToNextTry )
reschedule = false;
}
this->period = CA_RECAST_DELAY;
this->iiu.pcas->unlock ();
this->unlock ();
if ( reschedule ) {
this->reschedule ( delayToNextTry );
@@ -76,7 +76,7 @@ void searchTimer::setRetryInterval (unsigned retryNo)
unsigned idelay;
double delay;
this->iiu.pcas->lock ();
this->lock ();
/*
* set the retry number
@@ -93,7 +93,7 @@ void searchTimer::setRetryInterval (unsigned retryNo)
*/
this->period = min (CA_RECAST_PERIOD, delay);
this->iiu.pcas->unlock ();
this->unlock ();
debugPrintf ( ("new CA search period is %f sec\n", this->period) );
}
@@ -107,17 +107,21 @@ void searchTimer::setRetryInterval (unsigned retryNo)
//
void searchTimer::notifySearchResponse ( unsigned short retrySeqNo )
{
this->iiu.pcas->lock ();
bool reschedualNeeded;
if ( this->retrySeqNoAtListBegin <= retrySeqNo ) {
if ( this->searchResponses < ULONG_MAX ) {
this->searchResponses++;
this->lock ();
if ( this->retrySeqAtPassBegin <= retrySeqNo ) {
if ( this->searchResponsesWithinThisPass < UINT_MAX ) {
this->searchResponsesWithinThisPass++;
}
}
this->iiu.pcas->unlock ();
if ( retrySeqNo == this->retrySeqNo ) {
reschedualNeeded = ( retrySeqNo == this->retrySeqNo );
this->unlock ();
if ( reschedualNeeded ) {
this->reschedule (0.0);
}
}
@@ -127,19 +131,17 @@ void searchTimer::notifySearchResponse ( unsigned short retrySeqNo )
//
void searchTimer::expire ()
{
tsDLIterBD <nciu> chan(0);
tsDLIterBD <nciu> firstChan(0);
int status;
unsigned nSent=0u;
unsigned nFrameSent = 0u;
unsigned nChanSent = 0u;
/*
* check to see if there is nothing to do here
*/
if ( ellCount (&this->iiu.chidList) ==0 ) {
if ( this->iiu.channelCount () == 0 ) {
return;
}
this->iiu.pcas->lock ();
this->lock ();
/*
* increment the retry sequence number
@@ -173,8 +175,8 @@ void searchTimer::expire ()
* increase frames per try only if we see better than
* a 93.75% success rate for one pass through the list
*/
if (this->searchResponses >
(this->searchTries-(this->searchTries/16u)) ) {
if (this->searchResponsesWithinThisPass >
(this->searchTriesWithinThisPass-(this->searchTriesWithinThisPass/16u)) ) {
/*
* increase UDP frames per try if we have a good score
*/
@@ -189,33 +191,26 @@ void searchTimer::expire ()
this->framesPerTry += (this->framesPerTry/8) + 1;
}
debugPrintf ( ("Increasing frame count to %u t=%u r=%u\n",
this->framesPerTry, this->searchTries, this->searchResponses) );
this->framesPerTry, this->searchTriesWithinThisPass, this->searchResponsesWithinThisPass) );
}
}
/*
* if we detect congestion because we have less than a 87.5% success
* rate then gradually reduce the frames per try
*/
else if ( this->searchResponses <
(this->searchTries-(this->searchTries/8u)) ) {
else if ( this->searchResponsesWithinThisPass <
(this->searchTriesWithinThisPass-(this->searchTriesWithinThisPass/8u)) ) {
if (this->framesPerTry>1) {
this->framesPerTry--;
}
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
debugPrintf ( ("Congestion detected - set frames per try to %u t=%u r=%u\n",
this->framesPerTry, this->searchTries,
this->searchResponses) );
this->framesPerTry, this->searchTriesWithinThisPass,
this->searchResponsesWithinThisPass) );
}
/*
* a successful chan->searchMsg() sends channel to
* the end of the list
*/
firstChan = chan = this->iiu.chidList.first ();
while ( chan.valid () ) {
this->minRetry = min (this->minRetry, chan->retry);
while ( 1 ) {
/*
* clear counter when we reach the end of the list
*
@@ -223,10 +218,10 @@ void searchTimer::expire ()
* dont increase the delay between search
* requests
*/
if ( this->iiu.pcas->endOfBCastList == chan ) {
if ( this->searchResponses == 0u ) {
if ( this->searchTriesWithinThisPass >= this->iiu.channelCount () ) {
if ( this->searchResponsesWithinThisPass == 0u ) {
debugPrintf ( ("increasing search try interval\n") );
this->setRetryInterval (this->minRetry + 1u);
this->setRetryInterval ( this->minRetry + 1u );
}
this->minRetry = UINT_MAX;
@@ -243,83 +238,67 @@ void searchTimer::expire ()
/*
* so that old search tries will not update the counters
*/
this->retrySeqNoAtListBegin = this->retrySeqNo;
this->retrySeqAtPassBegin = this->retrySeqNo;
/*
* reset the search try/response counters at the end of the list
* (sequence number) so that we dont overflow, but dont subtract
* out tries that dont have a matching response yet in case they
* are delayed
*/
if ( this->searchTries > this->searchResponses ) {
this->searchTries -= this->searchResponses;
}
else {
this->searchTries = 0;
}
this->searchResponses = 0;
this->searchTriesWithinThisPass = 0;
this->searchResponsesWithinThisPass = 0;
debugPrintf ( ("saw end of list\n") );
}
/*
* this moves the channel to the end of the
* list (if successful)
*/
status = chan->searchMsg ();
if ( status != ECA_NORMAL ) {
nSent++;
unsigned retryNoForThisChannel;
if ( ! this->iiu.searchMsg ( this->retrySeqNo, retryNoForThisChannel ) ) {
nFrameSent++;
if ( nSent >= this->framesPerTry ) {
if ( nFrameSent >= this->framesPerTry ) {
break;
}
// flush out the search request buffer
this->iiu.flush ();
// try again
status = chan->searchMsg ();
if (status != ECA_NORMAL) {
if ( ! this->iiu.searchMsg ( this->retrySeqNo, retryNoForThisChannel ) ) {
break;
}
}
if ( this->searchTries < ULONG_MAX ) {
this->searchTries++;
}
this->minRetry = min ( this->minRetry, retryNoForThisChannel );
chan->retrySeqNo = this->retrySeqNo;
chan = this->iiu.chidList.first ();
if ( this->searchTriesWithinThisPass < UINT_MAX ) {
this->searchTriesWithinThisPass++;
}
if ( nChanSent < UINT_MAX ) {
nChanSent++;
}
/*
* dont send any of the channels twice within one try
*/
if ( chan == firstChan ) {
if ( nChanSent >= this->iiu.channelCount () ) {
/*
* add one to nSent because there may be
* add one to nFrameSent because there may be
* one more partial frame to be sent
*/
nSent++;
nFrameSent++;
/*
* cap this->framesPerTry to
* the number of frames required for all of
* the unresolved channels
*/
if (this->framesPerTry>nSent) {
this->framesPerTry = nSent;
if ( this->framesPerTry > nFrameSent ) {
this->framesPerTry = nFrameSent;
}
break;
}
}
this->iiu.pcas->unlock ();
this->unlock ();
// flush out the search request buffer
this->iiu.flush ();
debugPrintf ( ("sent %u delay sec=%f\n", nSent, this->period) );
debugPrintf ( ("sent %u delay sec=%f\n", nFrameSent, this->period) );
}
void searchTimer::destroy ()
@@ -328,7 +307,7 @@ void searchTimer::destroy ()
bool searchTimer::again () const
{
if ( ellCount (&this->iiu.chidList) == 0 ) {
if ( this->iiu.channelCount () == 0 ) {
return false;
}
else {
View File
+5 -10
View File
@@ -29,14 +29,7 @@ tcpRecvWatchdog::~tcpRecvWatchdog ()
void tcpRecvWatchdog::expire ()
{
/*
* remain backwards compatible with old servers
* ( this isnt an echo request )
*/
if ( ! this->echoProtocolAccepted ) {
this->noopRequestMsg ();
}
else if ( this->responsePending ) {
if ( this->responsePending ) {
char hostName[128];
this->hostName ( hostName, sizeof (hostName) );
ca_printf ( "CA server %s unresponsive for %g sec. Disconnecting.\n",
@@ -44,8 +37,10 @@ void tcpRecvWatchdog::expire ()
this->shutdown ();
}
else {
this->echoRequestMsg ();
this->responsePending = true;
this->echoRequest ();
if ( this->echoProtocolAccepted ) {
this->responsePending = true;
}
}
}
+573 -979
View File
File diff suppressed because it is too large Load Diff
+38 -24
View File
@@ -18,7 +18,7 @@
inline osiSockAddr tcpiiu::address () const
{
return this->dest;
return this->ipToA.address ();
}
inline void * tcpiiu::operator new (size_t size)
@@ -33,41 +33,55 @@ inline void tcpiiu::operator delete (void *pCadaver, size_t size)
inline bool tcpiiu::fullyConstructed () const
{
return this->fc;
}
inline void tcpiiu::flush ()
{
if ( cacRingBufferWriteFlush ( &this->send ) ) {
this->armSendWatchdog ();
}
return this->fullyConstructedFlag;
}
inline void tcpiiu::hostName ( char *pBuf, unsigned bufLength ) const
{
if ( bufLength ) {
strncpy ( pBuf, this->host_name_str, bufLength );
pBuf[bufLength - 1u] = '\0';
}
this->ipToA.hostName ( pBuf, bufLength );
}
// deprecated - please dont use
inline const char * tcpiiu::pHostName () const
{
return this->host_name_str;
}
inline bool tcpiiu::ca_v42_ok () const
{
return CA_V42 (CA_PROTOCOL_VERSION, this->minor_version_number);
}
inline bool tcpiiu::ca_v41_ok () const
{
return CA_V41 (CA_PROTOCOL_VERSION, this->minor_version_number);
static char nameBuf [128];
this->ipToA.hostName ( nameBuf, sizeof ( nameBuf ) );
return nameBuf; // ouch !!
}
inline SOCKET tcpiiu::getSock () const
{
return this->sock;
}
inline void tcpiiu::flush ()
{
this->flushPending = true;
semBinaryGive ( this->sendThreadFlushSignal );
}
inline bool tcpiiu::ca_v44_ok () const
{
return CA_V44 ( CA_PROTOCOL_VERSION, this->minor_version_number );
}
inline bool tcpiiu::ca_v42_ok () const
{
return CA_V42 ( CA_PROTOCOL_VERSION, this->minor_version_number );
}
inline bool tcpiiu::ca_v41_ok () const
{
return CA_V41 ( CA_PROTOCOL_VERSION, this->minor_version_number );
}
inline bool tcpiiu::alive () const
{
if ( this->state == iiu_connecting ||
this->state == iiu_connected ) {
return true;
}
else {
return false;
}
}
+203 -344
View File
@@ -15,9 +15,43 @@
#include "iocinf.h"
#include "addrList.h"
#include "inetAddrID_IL.h"
#include "netiiu_IL.h"
typedef void (*pProtoStubUDP) (udpiiu *piiu, caHdr *pMsg, const struct sockaddr_in *pnet_addr);
// UDP protocol dispatch table
const udpiiu::pProtoStubUDP udpiiu::udpJumpTableCAC[] =
{
udpiiu::noopAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::searchRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::exceptionRespAction,
udpiiu::badUDPRespAction,
udpiiu::beaconAction,
udpiiu::notHereRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::repeaterAckAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction,
udpiiu::badUDPRespAction
};
//
// udpiiu::recvMsg ()
//
@@ -62,12 +96,12 @@ void udpiiu::recvMsg ()
SOCKERRSTR (errnoCpy) );
}
else if (status > 0) {
status = this->post_msg ( &src.ia,
status = this->postMsg ( src,
this->recvBuf, (unsigned long) status );
if ( status != ECA_NORMAL ) {
char buf[64];
ipAddrToA (&src.ia, buf, sizeof(buf));
sockAddrToA ( &src.sa, buf, sizeof (buf) );
ca_printf (
"%s: bad UDP msg from %s because \"%s\"\n", __FILE__,
@@ -210,27 +244,27 @@ void udpiiu::repeaterRegistrationMessage ( unsigned attemptNumber )
*
* 072392 - problem solved by using SO_REUSEADDR
*/
int repeater_installed (udpiiu *piiu)
bool udpiiu::repeaterInstalled ()
{
int installed = FALSE;
bool installed = false;
int status;
SOCKET sock;
struct sockaddr_in bd;
int flag;
sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
sock = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( sock == INVALID_SOCKET ) {
return installed;
}
memset ( (char *) &bd, 0, sizeof (bd) );
memset ( (char *) &bd, 0, sizeof ( bd ) );
bd.sin_family = AF_INET;
bd.sin_addr.s_addr = htonl (INADDR_ANY);
bd.sin_port = htons (piiu->repeaterPort);
status = bind (sock, (struct sockaddr *) &bd, sizeof(bd) );
if (status<0) {
if (SOCKERRNO == SOCK_EADDRINUSE) {
installed = TRUE;
bd.sin_addr.s_addr = htonl ( INADDR_ANY );
bd.sin_port = htons ( this->repeaterPort );
status = bind ( sock, (struct sockaddr *) &bd, sizeof ( bd ) );
if ( status < 0 ) {
if ( SOCKERRNO == SOCK_EADDRINUSE ) {
installed = true;
}
}
@@ -240,12 +274,12 @@ int repeater_installed (udpiiu *piiu)
*/
flag = TRUE;
status = setsockopt ( sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&flag, sizeof (flag) );
(char *)&flag, sizeof ( flag ) );
if (status<0) {
ca_printf ( "CAC: set socket option reuseaddr set failed\n");
}
socket_close (sock);
socket_close ( sock );
return installed;
}
@@ -253,9 +287,8 @@ int repeater_installed (udpiiu *piiu)
//
// udpiiu::udpiiu ()
//
udpiiu::udpiiu ( cac *pcac ) :
netiiu ( pcac ),
shutdownCmd ( false )
udpiiu::udpiiu ( cac &cac ) :
netiiu ( cac ), shutdownCmd ( false )
{
static const unsigned short PORT_ANY = 0u;
osiSockAddr addr;
@@ -265,8 +298,11 @@ udpiiu::udpiiu ( cac *pcac ) :
this->repeaterPort =
envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, CA_REPEATER_PORT);
this->sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (this->sock == INVALID_SOCKET) {
this->serverPort =
envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, CA_SERVER_PORT );
this->sock = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( this->sock == INVALID_SOCKET ) {
ca_printf ("CAC: unable to create datagram socket because = \"%s\"\n",
SOCKERRSTR (SOCKERRNO));
throwWithLocation ( noSocket () );
@@ -306,7 +342,7 @@ udpiiu::udpiiu ( cac *pcac ) :
addr.ia.sin_addr.s_addr = htonl (INADDR_ANY);
addr.ia.sin_port = htons (PORT_ANY);
status = bind (this->sock, &addr.sa, sizeof (addr) );
if (status<0) {
if ( status < 0 ) {
socket_close (this->sock);
ca_printf ("CAC: unable to bind to an unconstrained address because = \"%s\"\n",
SOCKERRSTR (SOCKERRNO));
@@ -315,16 +351,9 @@ udpiiu::udpiiu ( cac *pcac ) :
this->nBytesInXmitBuf = 0u;
this->xmitBufLock = semMutexCreate ();
if (!this->xmitBufLock) {
socket_close (this->sock);
throwWithLocation ( noMemory () );
}
this->recvThreadExitSignal = semBinaryCreate (semEmpty);
this->recvThreadExitSignal = semBinaryCreate ( semEmpty );
if ( ! this->recvThreadExitSignal ) {
semMutexDestroy (this->xmitBufLock);
socket_close (this->sock);
socket_close ( this->sock );
throwWithLocation ( noMemory () );
}
@@ -333,9 +362,9 @@ udpiiu::udpiiu ( cac *pcac ) :
* broadcast address list
*/
ellInit ( &this->dest );
configureChannelAccessAddressList (&this->dest, this->sock, pcac->ca_server_port);
configureChannelAccessAddressList ( &this->dest, this->sock, this->serverPort );
if ( ellCount ( &this->dest ) == 0 ) {
genLocalExcep ( this->pcas, ECA_NOSEARCHADDR, NULL );
genLocalExcep ( this->clientCtx (), ECA_NOSEARCHADDR, NULL );
}
{
@@ -349,18 +378,17 @@ udpiiu::udpiiu ( cac *pcac ) :
priorityOfRecv = priorityOfSelf;
}
tid = threadCreate ("CAC-UDP", priorityOfRecv,
threadGetStackSize (threadStackMedium), cacRecvThreadUDP, this);
tid = threadCreate ( "CAC-UDP", priorityOfRecv,
threadGetStackSize (threadStackMedium), cacRecvThreadUDP, this );
if (tid==0) {
ca_printf ("CA: unable to create UDP receive thread\n");
semBinaryDestroy (this->recvThreadExitSignal);
semMutexDestroy (this->xmitBufLock);
socket_close (this->sock);
throwWithLocation ( noMemory () );
}
}
if ( ! repeater_installed (this) ) {
if ( ! this->repeaterInstalled () ) {
osiSpawnDetachedProcessReturn osptr;
/*
@@ -369,7 +397,7 @@ udpiiu::udpiiu ( cac *pcac ) :
* the 2nd repeater exits when unable to attach to the
* repeater's port)
*/
osptr = osiSpawnDetachedProcess ("CA Repeater", "caRepeater");
osptr = osiSpawnDetachedProcess ( "CA Repeater", "caRepeater" );
if ( osptr == osiSpawnDetachedProcessNoSupport ) {
threadId tid;
@@ -390,28 +418,22 @@ udpiiu::udpiiu ( cac *pcac ) :
*/
udpiiu::~udpiiu ()
{
nciu *pChan, *pNext;
// closes the udp socket
this->shutdown ();
this->pcas->lock ();
tsDLIter <nciu> iter (this->chidList);
pChan = iter ();
while (pChan) {
pNext = iter ();
pChan->destroy ();
pChan = pNext;
}
this->pcas->unlock ();
this->detachAllChan ();
// wait for recv threads to exit
semBinaryMustTake (this->recvThreadExitSignal);
semBinaryMustTake ( this->recvThreadExitSignal );
semMutexDestroy (this->xmitBufLock);
semBinaryDestroy (this->recvThreadExitSignal);
semBinaryDestroy ( this->recvThreadExitSignal );
ellFree (&this->dest);
ellFree ( &this->dest );
if ( this->sock != INVALID_SOCKET ) {
socket_close ( this->sock );
}
}
/*
@@ -419,62 +441,72 @@ udpiiu::~udpiiu ()
*/
void udpiiu::shutdown ()
{
this->pcas->lock ();
if ( ! this->shutdownCmd ) {
int status;
bool laborRequired;
// this knocks the UDP input thread out of recv ()
this->lock ();
if ( ! this->shutdownCmd ) {
this->shutdownCmd = true;
status = socket_close ( this->sock );
if ( status ) {
errlogPrintf ( "CAC UDP socket close error was \"%s\"\n",
SOCKERRSTR (SOCKERRNO) );
laborRequired = true;
}
else {
laborRequired = false;
}
this->unlock ();
if ( laborRequired ) {
int status;
osiSockAddr addr;
int size = sizeof ( addr.sa );
status = getsockname ( this->sock, &addr.sa, &size );
if ( status < 0 ) {
// this knocks the UDP input thread out of recv ()
// on all os except linux
socket_close ( this->sock );
this->sock = INVALID_SOCKET;
}
else {
caHdr msg;
msg.m_cmmd = htons ( CA_PROTO_NOOP );
msg.m_available = htonl ( 0u );
msg.m_dataType = htons ( 0u );
msg.m_count = htons ( 0u );
msg.m_cid = htonl ( 0u );
msg.m_postsize = htons ( 0u );
// send a wakeup msg so the UDP recv thread will exit
status = sendto ( this->sock, reinterpret_cast < const char * > ( &msg ), sizeof (msg), 0,
&addr.sa, sizeof ( addr.sa ) );
if ( status < 0 ) {
// this knocks the UDP input thread out of recv ()
// on all os except linux
socket_close ( this->sock );
this->sock = INVALID_SOCKET;
}
}
}
this->pcas->unlock ();
}
/*
* bad_udp_resp_action ()
*/
LOCAL void bad_udp_resp_action (udpiiu * /* piiu */,
caHdr *pMsg, const struct sockaddr_in *pnet_addr)
void udpiiu::badUDPRespAction ( const caHdr &msg, const osiSockAddr &netAddr )
{
char buf[256];
ipAddrToA ( pnet_addr, buf, sizeof (buf) );
sockAddrToA ( &netAddr.sa, buf, sizeof ( buf ) );
ca_printf ( "CAC: Bad response code in UDP message from %s was %u\n",
buf, pMsg->m_cmmd);
buf, msg.m_cmmd);
}
/*
* udp_noop_action ()
*/
LOCAL void udp_noop_action (udpiiu * /* piiu */, caHdr * /* pMsg */,
const struct sockaddr_in * /* pnet_addr */)
void udpiiu::noopAction ( const caHdr &, const osiSockAddr & )
{
return;
}
/*
* search_resp_action ()
*/
LOCAL void search_resp_action (udpiiu *piiu, caHdr *pMsg, const struct sockaddr_in *pnet_addr)
void udpiiu::searchRespAction ( const caHdr &msg, const osiSockAddr &addr )
{
struct sockaddr_in ina;
nciu *chan;
tcpiiu *allocpiiu;
unsigned short *pMinorVersion;
unsigned minorVersion;
osiSockAddr serverAddr;
unsigned minorVersion;
ca_uint16_t *pMinorVersion;
/*
* ignore broadcast replies for deleted channels
*
* lock required around use of the sprintf buffer
*/
piiu->pcas->lock ();
chan = piiu->pcas->lookupChan (pMsg->m_available);
if ( ! chan ) {
piiu->pcas->unlock ();
if ( addr.sa.sa_family != AF_INET ) {
return;
}
@@ -483,9 +515,9 @@ LOCAL void search_resp_action (udpiiu *piiu, caHdr *pMsg, const struct sockaddr_
* is appended to the end of each search reply.
* This value is ignored by earlier clients.
*/
if ( pMsg->m_postsize >= sizeof (*pMinorVersion) ){
pMinorVersion = (unsigned short *) (pMsg+1);
minorVersion = ntohs (*pMinorVersion);
if ( msg.m_postsize >= sizeof (*pMinorVersion) ){
pMinorVersion = (ca_uint16_t *) ( &msg + 1 );
minorVersion = ntohs ( *pMinorVersion );
}
else {
minorVersion = CA_UKN_MINOR_VERSION;
@@ -495,109 +527,49 @@ LOCAL void search_resp_action (udpiiu *piiu, caHdr *pMsg, const struct sockaddr_
* the type field is abused to carry the port number
* so that we can have multiple servers on one host
*/
ina.sin_family = AF_INET;
serverAddr.ia.sin_family = AF_INET;
if ( CA_V48 (CA_PROTOCOL_VERSION,minorVersion) ) {
if ( pMsg->m_cid != INADDR_BROADCAST ) {
if ( msg.m_cid != INADDR_BROADCAST ) {
/*
* Leave address in network byte order (m_cid has not been
* converted to the local byte order)
*/
ina.sin_addr.s_addr = pMsg->m_cid;
serverAddr.ia.sin_addr.s_addr = msg.m_cid;
}
else {
ina.sin_addr = pnet_addr->sin_addr;
serverAddr.ia.sin_addr = addr.ia.sin_addr;
}
ina.sin_port = htons (pMsg->m_dataType);
serverAddr.ia.sin_port = htons (msg.m_dataType);
}
else if ( CA_V45 (CA_PROTOCOL_VERSION,minorVersion) ) {
ina.sin_port = htons (pMsg->m_dataType);
ina.sin_addr = pnet_addr->sin_addr;
serverAddr.ia.sin_port = htons ( msg.m_dataType );
serverAddr.ia.sin_addr = addr.ia.sin_addr;
}
else {
ina.sin_port = htons (piiu->pcas->ca_server_port);
ina.sin_addr = pnet_addr->sin_addr;
serverAddr.ia.sin_port = htons ( this->serverPort );
serverAddr.ia.sin_addr = addr.ia.sin_addr;
}
/*
* Ignore duplicate search replies
*/
if ( chan->piiu->compareIfTCP (*chan, *pnet_addr) ) {
piiu->pcas->unlock ();
return;
}
allocpiiu = constructTCPIIU (piiu->pcas, &ina, minorVersion);
if ( ! allocpiiu ) {
piiu->pcas->unlock ();
return;
}
/*
* If this is the first channel to be
* added to this niiu then communicate
* the client's name to the server.
* (CA V4.1 or higher)
*/
if ( ellCount ( &allocpiiu->chidList ) == 0 ) {
allocpiiu->userNameSetMsg ();
allocpiiu->hostNameSetMsg ();
}
piiu->pcas->notifySearchResponse ( chan->retrySeqNo );
/*
* Assume that we have access once connected briefly
* until the server is able to tell us the correct
* state for backwards compatibility.
*
* Their access rights call back does not get
* called for the first time until the information
* arrives however.
*/
chan->ar.read_access = TRUE;
chan->ar.write_access = TRUE;
/*
* remove it from the broadcast niiu
*/
chan->piiu->removeFromChanList ( *chan );
/*
* chan->piiu must be correctly set prior to issuing the
* claim request
*
* add to the beginning of the list until we
* have sent the claim message (after which we
* move it to the end of the list)
*
* claim pending flag is set here
*/
allocpiiu->addToChanList ( *chan );
if ( CA_V42 ( CA_PROTOCOL_VERSION, minorVersion ) ) {
chan->searchReplySetUp ( pMsg->m_cid, USHRT_MAX, 0 );
this->clientCtx ().lookupChannelAndTransferToTCP
( msg.m_available, msg.m_cid, USHRT_MAX, 0,
minorVersion, serverAddr );
}
else {
chan->searchReplySetUp ( pMsg->m_cid, pMsg->m_dataType, pMsg->m_count );
this->clientCtx ().lookupChannelAndTransferToTCP
( msg.m_available, msg.m_cid, msg.m_dataType,
minorVersion, msg.m_count, serverAddr );
}
chan->claimMsg ( allocpiiu );
cacRingBufferWriteFlush ( &allocpiiu->send );
piiu->pcas->unlock ();
}
/*
* beacon_action ()
*/
LOCAL void beacon_action ( udpiiu * piiu,
caHdr *pMsg, const struct sockaddr_in *pnet_addr)
void udpiiu::beaconAction ( const caHdr &msg, const osiSockAddr &net_addr )
{
struct sockaddr_in ina;
piiu->pcas->lock ();
if ( net_addr.sa.sa_family != AF_INET ) {
return;
}
/*
* this allows a fan-out server to potentially
* insert the true address of the CA server
@@ -613,143 +585,96 @@ LOCAL void beacon_action ( udpiiu * piiu,
* then it is the overriding IP address of the server.
*/
ina.sin_family = AF_INET;
if ( pMsg->m_available != htonl (INADDR_ANY) ) {
ina.sin_addr.s_addr = pMsg->m_available;
if ( msg.m_available != htonl (INADDR_ANY) ) {
ina.sin_addr.s_addr = msg.m_available;
}
else {
ina.sin_addr = pnet_addr->sin_addr;
ina.sin_addr = net_addr.ia.sin_addr;
}
if ( pMsg->m_count != 0 ) {
ina.sin_port = htons ( pMsg->m_count );
if ( msg.m_count != 0 ) {
ina.sin_port = htons ( msg.m_count );
}
else {
/*
* old servers dont supply this and the
* default port must be assumed
*/
ina.sin_port = htons (piiu->pcas->ca_server_port);
ina.sin_port = htons ( this->serverPort );
}
piiu->pcas->beaconNotify (ina);
piiu->pcas->unlock ();
this->clientCtx ().beaconNotify ( ina );
return;
}
/*
* repeater_ack_action ()
*/
LOCAL void repeater_ack_action (udpiiu * piiu,
caHdr * /* pMsg */, const struct sockaddr_in * /* pnet_addr */)
void udpiiu::repeaterAckAction ( const caHdr &, const osiSockAddr &)
{
piiu->pcas->repeaterSubscribeConfirmNotify ();
this->clientCtx ().repeaterSubscribeConfirmNotify ();
}
/*
* not_here_resp_action ()
*/
LOCAL void not_here_resp_action (udpiiu * /* piiu */, caHdr * /* pMsg */, const struct sockaddr_in * /* pnet_addr */)
void udpiiu::notHereRespAction ( const caHdr &, const osiSockAddr &)
{
return;
}
/*
* udp_exception_resp_action ()
*/
LOCAL void udp_exception_resp_action ( udpiiu *piiu,
caHdr *pMsg, const struct sockaddr_in *pnet_addr )
void udpiiu::exceptionRespAction ( const caHdr &msg, const osiSockAddr &net_addr )
{
caHdr *pReqMsg = pMsg + 1;
const caHdr &reqMsg = * ( &msg + 1 );
char name[64];
ipAddrToA ( pnet_addr, name, sizeof ( name ) );
sockAddrToA ( &net_addr.sa, name, sizeof ( name ) );
if ( pMsg->m_postsize > sizeof (caHdr) ){
if ( msg.m_postsize > sizeof ( caHdr ) ){
errlogPrintf ( "error condition \"%s\" detected by %s with context \"%s\"\n",
ca_message ( ntohl ( pMsg->m_available ) ),
name, reinterpret_cast <char *> ( pReqMsg + 1 ) );
ca_message ( msg.m_available ),
name, reinterpret_cast <const char *> ( &reqMsg + 1 ) );
}
else{
errlogPrintf ( "error condition \"%s\" detected by %s\n",
ca_message ( ntohl ( pMsg->m_available ) ), name );
ca_message ( msg.m_available ), name );
}
return;
}
/*
* UDP protocol jump table
*/
LOCAL const pProtoStubUDP udpJumpTableCAC[] =
{
udp_noop_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
search_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
udp_exception_resp_action,
bad_udp_resp_action,
beacon_action,
not_here_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
repeater_ack_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action,
bad_udp_resp_action
};
/*
* post_udp_msg ()
*/
int udpiiu::post_msg (const struct sockaddr_in *pnet_addr,
char *pInBuf, unsigned long blockSize)
int udpiiu::postMsg ( const osiSockAddr &net_addr,
char *pInBuf, unsigned long blockSize )
{
caHdr *pCurMsg;
while ( blockSize ) {
unsigned long size;
if ( blockSize < sizeof (*pCurMsg) ) {
if ( blockSize < sizeof ( *pCurMsg ) ) {
return ECA_TOLARGE;
}
pCurMsg = reinterpret_cast <caHdr *> (pInBuf);
pCurMsg = reinterpret_cast <caHdr *> ( pInBuf );
/*
* fix endian of bytes
*/
pCurMsg->m_postsize = ntohs (pCurMsg->m_postsize);
pCurMsg->m_cmmd = ntohs (pCurMsg->m_cmmd);
pCurMsg->m_dataType = ntohs (pCurMsg->m_dataType);
pCurMsg->m_count = ntohs (pCurMsg->m_count);
pCurMsg->m_postsize = ntohs ( pCurMsg->m_postsize );
pCurMsg->m_cmmd = ntohs ( pCurMsg->m_cmmd );
pCurMsg->m_dataType = ntohs ( pCurMsg->m_dataType );
pCurMsg->m_count = ntohs ( pCurMsg->m_count );
#if 0
printf ("UDP Cmd=%3d Type=%3d Count=%4d Size=%4d",
printf ( "UDP Cmd=%3d Type=%3d Count=%4d Size=%4d",
pCurMsg->m_cmmd,
pCurMsg->m_dataType,
pCurMsg->m_count,
pCurMsg->m_postsize);
pCurMsg->m_postsize );
printf (" Avail=%8x Cid=%6d\n",
pCurMsg->m_available,
pCurMsg->m_cid);
pCurMsg->m_cid );
#endif
size = pCurMsg->m_postsize + sizeof (*pCurMsg);
size = pCurMsg->m_postsize + sizeof ( *pCurMsg );
/*
* dont allow msg body extending beyond frame boundary
@@ -762,13 +687,13 @@ int udpiiu::post_msg (const struct sockaddr_in *pnet_addr,
* execute the response message
*/
pProtoStubUDP pStub;
if ( pCurMsg->m_cmmd>=NELEMENTS (udpJumpTableCAC) ) {
pStub = bad_udp_resp_action;
if ( pCurMsg->m_cmmd >= NELEMENTS ( udpJumpTableCAC ) ) {
pStub = badUDPRespAction;
}
else {
pStub = udpJumpTableCAC [pCurMsg->m_cmmd];
}
(*pStub) (this, pCurMsg, pnet_addr);
(this->*pStub) ( *pCurMsg, net_addr);
blockSize -= size;
pInBuf += size;;
@@ -789,110 +714,44 @@ const char * udpiiu::pHostName () const
return "<disconnected>";
}
bool udpiiu::ca_v42_ok () const
{
return false;
}
bool udpiiu::ca_v41_ok () const
{
return false;
}
bool udpiiu::compareIfTCP (nciu &, const sockaddr_in &) const
{
return false;
}
/*
* Add chan to iiu and guarantee that
* one chan on the B cast iiu list is pointed to by
* ca_pEndOfBCastList
*/
void udpiiu::addToChanList ( nciu &chan )
{
this->pcas->lock ();
/*
* add to the beginning of the list so that search requests for
* this channel will be sent first (since the retry count is zero)
*/
if ( ellCount ( &this->chidList ) == 0 ) {
this->pcas->endOfBCastList = tsDLIterBD <nciu> ( &chan );
}
/*
* add to the front of the list so that
* search requests for new channels will be sent first
*/
chan.retry = 0u;
this->chidList.push ( chan );
chan.piiu = this;
this->pcas->unlock ();
}
void udpiiu::removeFromChanList ( nciu &chan )
{
tsDLIterBD <nciu> iter ( &chan );
this->pcas->lock ();
if ( chan.piiu->pcas->endOfBCastList == iter ) {
if ( iter.itemBefore ().valid () ) {
chan.piiu->pcas->endOfBCastList = iter.itemBefore ();
}
else {
chan.piiu->pcas->endOfBCastList =
tsDLIterBD<nciu> ( chan.piiu->chidList.last () );
}
}
chan.piiu->chidList.remove ( chan );
chan.piiu = NULL;
this->pcas->unlock ();
}
void udpiiu::disconnect ( nciu & /* chan */ )
{
// NOOP
}
/*
* udpiiu::pushDatagramMsg ()
*/
int udpiiu::pushDatagramMsg (const caHdr *pMsg, const void *pExt, ca_uint16_t extsize)
bool udpiiu::pushDatagramMsg ( const caHdr &msg, const void *pExt, ca_uint16_t extsize )
{
unsigned long msgsize;
ca_uint16_t allignedExtSize;
caHdr *pbufmsg;
allignedExtSize = CA_MESSAGE_ALIGN (extsize);
msgsize = sizeof (caHdr) + allignedExtSize;
allignedExtSize = CA_MESSAGE_ALIGN ( extsize );
msgsize = sizeof ( caHdr ) + allignedExtSize;
/* fail out if max message size exceeded */
if ( msgsize >= sizeof (this->xmitBuf)-7 ) {
return ECA_TOLARGE;
if ( msgsize >= sizeof ( this->xmitBuf ) - 7 ) {
return false;
}
semMutexMustTake (this->xmitBufLock);
this->lock ();
if ( msgsize + this->nBytesInXmitBuf > sizeof ( this->xmitBuf ) ) {
semMutexGive (this->xmitBufLock);
return ECA_TOLARGE;
this->unlock ();
return false;
}
pbufmsg = (caHdr *) &this->xmitBuf[this->nBytesInXmitBuf];
*pbufmsg = *pMsg;
memcpy (pbufmsg+1, pExt, extsize);
*pbufmsg = msg;
memcpy ( pbufmsg+1, pExt, extsize );
if ( extsize != allignedExtSize ) {
char *pDest = (char *) (pbufmsg+1);
memset (pDest + extsize, '\0', allignedExtSize - extsize);
char *pDest = (char *) ( pbufmsg + 1 );
memset ( pDest + extsize, '\0', allignedExtSize - extsize );
}
pbufmsg->m_postsize = htons (allignedExtSize);
pbufmsg->m_postsize = htons ( allignedExtSize );
this->nBytesInXmitBuf += msgsize;
semMutexGive (this->xmitBufLock);
this->unlock ();
return ECA_NORMAL;
return true;
}
//
@@ -902,7 +761,12 @@ void udpiiu::flush ()
{
osiSockAddrNode *pNode;
semMutexMustTake (this->xmitBufLock);
this->lock ();
if ( this->nBytesInXmitBuf == 0u ) {
this->unlock ();
return;
}
pNode = (osiSockAddrNode *) ellFirst ( &this->dest );
while ( pNode ) {
@@ -940,7 +804,7 @@ void udpiiu::flush ()
else {
char buf[64];
ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) );
sockAddrToA ( &pNode->addr.sa, buf, sizeof ( buf ) );
ca_printf (
"CAC: error = \"%s\" sending UDP msg to %s\n",
@@ -954,17 +818,12 @@ void udpiiu::flush ()
this->nBytesInXmitBuf = 0u;
semMutexGive ( this->xmitBufLock );
}
int udpiiu::pushStreamMsg ( const caHdr * /* pmsg */,
const void * /* pext */, bool /* blockingOk */ )
{
ca_printf ("in pushStreamMsg () for a udp iiu?\n");
return ECA_DISCONNCHID;
this->unlock ();
}
SOCKET udpiiu::getSock () const
{
return this->sock;
}
}