large array changes

This commit is contained in:
Jeff Hill
2001-05-22 02:02:10 +00:00
parent fa87c186fe
commit 70de17474b
56 changed files with 3457 additions and 2831 deletions
+5 -5
View File
@@ -153,7 +153,7 @@ bool CASG::ioComplete () const
return ( this->ioList.count () == 0u );
}
int CASG::put ( chid pChan, unsigned type, unsigned long count, const void *pValue )
int CASG::put ( chid pChan, unsigned type, arrayElementCount count, const void *pValue )
{
try {
epicsAutoMutex locker ( this->mutex );
@@ -191,7 +191,7 @@ int CASG::put ( chid pChan, unsigned type, unsigned long count, const void *pVal
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
@@ -201,7 +201,7 @@ int CASG::put ( chid pChan, unsigned type, unsigned long count, const void *pVal
}
}
int CASG::get ( chid pChan, unsigned type, unsigned long count, void *pValue )
int CASG::get ( chid pChan, unsigned type, arrayElementCount count, void *pValue )
{
try {
@@ -240,7 +240,7 @@ int CASG::get ( chid pChan, unsigned type, unsigned long count, void *pValue )
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
@@ -300,4 +300,4 @@ int CASG::printf ( const char *pformat, ... )
return status;
}
+35 -96
View File
@@ -12,6 +12,8 @@
*
*/
#include <new>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
@@ -81,32 +83,6 @@ int fetchClientContext ( oldCAC **ppcac )
return status;
}
/*
* Default Exception Handler
*/
extern "C" void ca_default_exception_handler ( struct exception_handler_args args )
{
if ( args.chid && args.op != CA_OP_OTHER ) {
ca_signal_formated (
args.stat,
args.pFile,
args.lineNo,
"%s - with request chan=%s op=%ld data type=%s count=%ld",
args.ctx,
ca_name ( args.chid ),
args.op,
dbr_type_to_text ( args.type ),
args.count );
}
else {
ca_signal_formated (
args.stat,
args.pFile,
args.lineNo,
args.ctx );
}
}
/*
* ca_task_initialize ()
*/
@@ -211,7 +187,7 @@ extern "C" int epicsShareAPI ca_task_exit ()
* backwards compatible entry point to ca_search_and_connect()
*/
extern "C" int epicsShareAPI ca_build_and_connect ( const char *name_str, chtype get_type,
unsigned long get_count, chid * chan, void *pvalue,
arrayElementCount get_count, chid * chan, void *pvalue,
caCh *conn_func, void *puser )
{
if ( get_type != TYPENOTCONN && pvalue != 0 && get_count != 0 ) {
@@ -269,7 +245,7 @@ extern "C" int epicsShareAPI ca_clear_channel ( chid pChan )
* ca_array_get ()
*/
extern "C" int epicsShareAPI ca_array_get ( chtype type,
unsigned long count, chid pChan, void *pValue )
arrayElementCount count, chid pChan, void *pValue )
{
oldCAC *pcac;
int caStatus = fetchClientContext ( &pcac );
@@ -283,7 +259,7 @@ extern "C" int epicsShareAPI ca_array_get ( chtype type,
unsigned tmpType = static_cast < unsigned > ( type );
autoPtrDestroy < getCopy > pNotify
( new getCopy ( *pcac, tmpType, count, pValue ) );
( new getCopy ( *pcac, *pChan, tmpType, count, pValue ) );
if ( ! pNotify.get() ) {
return ECA_ALLOCMEM;
}
@@ -317,10 +293,13 @@ extern "C" int epicsShareAPI ca_array_get ( chtype type,
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
catch ( cacChannel::msgBodyCacheTooSmall ) {
return ECA_TOLARGE;
}
catch ( ... )
{
return ECA_GETFAIL;
@@ -331,7 +310,7 @@ extern "C" int epicsShareAPI ca_array_get ( chtype type,
* ca_array_get_callback ()
*/
extern "C" int epicsShareAPI ca_array_get_callback ( chtype type,
unsigned long count, chid pChan,
arrayElementCount count, chid pChan,
caEventCallBackFunc *pfunc, void *arg )
{
if ( type < 0 ) {
@@ -374,10 +353,13 @@ extern "C" int epicsShareAPI ca_array_get_callback ( chtype type,
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
catch ( cacChannel::msgBodyCacheTooSmall ) {
return ECA_TOLARGE;
}
catch ( ... )
{
return ECA_GETFAIL;
@@ -387,7 +369,7 @@ extern "C" int epicsShareAPI ca_array_get_callback ( chtype type,
/*
* ca_array_put_callback ()
*/
extern "C" int epicsShareAPI ca_array_put_callback ( chtype type, unsigned long count,
extern "C" int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count,
chid pChan, const void *pValue, caEventCallBackFunc *pfunc, void *usrarg )
{
if ( type < 0 ) {
@@ -430,7 +412,7 @@ extern "C" int epicsShareAPI ca_array_put_callback ( chtype type, unsigned long
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
@@ -443,7 +425,7 @@ extern "C" int epicsShareAPI ca_array_put_callback ( chtype type, unsigned long
/*
* ca_array_put ()
*/
extern "C" int epicsShareAPI ca_array_put ( chtype type, unsigned long count,
extern "C" int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count,
chid pChan, const void *pValue )
{
if ( type < 0 ) {
@@ -479,7 +461,7 @@ extern "C" int epicsShareAPI ca_array_put ( chtype type, unsigned long count,
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
@@ -526,7 +508,7 @@ extern "C" int epicsShareAPI ca_add_exception_event ( caExceptionHandler *pfunc,
* ca_add_masked_array_event
*/
extern "C" int epicsShareAPI ca_add_masked_array_event (
chtype type, unsigned long count, chid pChan,
chtype type, arrayElementCount count, chid pChan,
caEventCallBackFunc *pCallBack, void *pCallBackArg,
ca_real, ca_real, ca_real,
evid *monixptr, long mask )
@@ -553,20 +535,6 @@ extern "C" int epicsShareAPI ca_add_masked_array_event (
return ECA_BADMASK;
}
/*
* Check for huge waveform
*
* (the count is not checked here against the native count
* when connected because this introduces a race condition
* for the client tool - the requested count is clipped to
* the actual count when the monitor request is sent so
* verifying that the requested count is valid here isnt
* required)
*/
if ( dbr_size_n ( type, count ) > MAX_MSG_SIZE - sizeof ( caHdr ) ) {
return ECA_TOLARGE;
}
try {
autoPtrDestroy < oldSubscription > pSubsr
( new oldSubscription (
@@ -600,10 +568,13 @@ extern "C" int epicsShareAPI ca_add_masked_array_event (
{
return ECA_NOTINSERVICE;
}
catch ( cacChannel::noMemory & )
catch ( std::bad_alloc & )
{
return ECA_ALLOCMEM;
}
catch ( cacChannel::msgBodyCacheTooSmall ) {
return ECA_TOLARGE;
}
catch ( ... )
{
return ECA_INTERNAL;
@@ -732,56 +703,24 @@ extern "C" void epicsShareAPI ca_signal_formated ( long ca_status, const char *p
int lineno, const char *pFormat, ... )
{
oldCAC *pcac;
va_list theArgs;
static const char *severity[] =
{
"Warning",
"Success",
"Error",
"Info",
"Fatal",
"Fatal",
"Fatal",
"Fatal"
};
if ( caClientContextId ) {
pcac = (oldCAC *) epicsThreadPrivateGet ( caClientContextId );
pcac = ( oldCAC * ) epicsThreadPrivateGet ( caClientContextId );
}
else {
pcac = NULL;
pcac = 0;
}
va_start ( theArgs, pFormat );
pcac->printf ( "CA.Client.Diagnostic..............................................\n" );
pcac->printf ( " %s: \"%s\"\n",
severity[ CA_EXTRACT_SEVERITY ( ca_status ) ],
ca_message ( ca_status ) );
if ( pFormat ) {
pcac->printf ( " Context: \"" );
pcac->vPrintf ( pFormat, theArgs );
pcac->printf ( "\"\n" );
va_list theArgs;
va_start ( theArgs, pFormat );
if ( pcac ) {
pcac->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs );
}
if (pfilenm) {
pcac->printf ( " Source File: %s Line Number: %d\n",
pfilenm, lineno );
else {
fprintf ( stderr, "file=%s line=%d: CA exception delivered to a thread w/o ca context\n",
pfilenm, lineno );
vfprintf ( stderr, pFormat, theArgs );
}
/*
* Terminate execution if unsuccessful
*/
if( ! ( ca_status & CA_M_SUCCESS ) &&
CA_EXTRACT_SEVERITY ( ca_status ) != CA_K_WARNING ){
errlogFlush();
abort();
}
pcac->printf ( "..................................................................\n" );
va_end ( theArgs );
}
@@ -836,7 +775,7 @@ extern "C" int epicsShareAPI ca_v42_ok ( chid pChan )
*/
extern "C" const char * epicsShareAPI ca_version ()
{
return CA_VERSION_STRING;
return CA_VERSION_STRING ( CA_MINOR_PROTOCOL_REVISION );
}
/*
@@ -866,7 +805,7 @@ extern "C" short epicsShareAPI ca_field_type ( chid pChan )
/*
* ca_element_count ()
*/
extern "C" unsigned long epicsShareAPI ca_element_count ( chid pChan )
extern "C" arrayElementCount epicsShareAPI ca_element_count ( chid pChan )
{
return pChan->nativeElementCount ();
}
+66 -15
View File
@@ -617,7 +617,7 @@ void performCtrlDoubleTest (chid chan)
ca_element_count(chan),
chan, pCtrlDbl);
SEVCHK (status, "performCtrlDoubleTest, ca_array_get");
status = ca_pend_io (20.0);
status = ca_pend_io (30.0);
assert (status==ECA_NORMAL);
/*
@@ -1246,17 +1246,37 @@ void eventClearTest ( chid chan )
SEVCHK ( status, NULL);
}
/*
* array test
*
* verify that we can at least write and read back the same array
* if multiple elements are present
*/
static arrayReadNotifyComplete = 0;
static arrayWriteNotifyComplete = 0;
void arrayReadNotify ( struct event_handler_args args )
{
dbr_double_t *pWF = ( dbr_double_t * ) ( args.usr );
dbr_double_t *pRF = ( dbr_double_t * ) ( args.dbr );
int i;
for ( i = 0; i < args.count; i++ ) {
if ( pWF[i] != pRF[i] ) {
assert ( 0 );
}
}
arrayReadNotifyComplete = 1;
}
void arrayWriteNotify ( struct event_handler_args args )
{
arrayWriteNotifyComplete = 1;
}
void arrayTest ( chid chan )
{
dbr_double_t *pRF, *pWF;
unsigned i;
int status;
evid id;
if ( ! ca_write_access ( chan ) ) {
printf ( "skipping array test - no write access\n" );
@@ -1293,7 +1313,7 @@ void arrayTest ( chid chan )
/*
* verify read response matches values written
*/
for ( i = 0; i < ca_element_count (chan); i++ ) {
for ( i = 0; i < ca_element_count ( chan ); i++ ) {
assert ( pWF[i] == pRF[i] );
}
@@ -1302,26 +1322,55 @@ void arrayTest ( chid chan )
*/
{
char *pRS;
/* clip to 16k message buffer limit */
unsigned maxElem = ( ( 1 << 14 ) - 16 ) / MAX_STRING_SIZE;
unsigned nElem;
if ( maxElem > ca_element_count (chan) ) {
nElem = ca_element_count (chan);
}
else {
nElem = maxElem;
}
pRS = malloc ( nElem * MAX_STRING_SIZE );
pRS = malloc ( ca_element_count (chan) * MAX_STRING_SIZE );
assert ( pRS );
status = ca_array_get ( DBR_STRING, nElem, chan, pRS );
status = ca_array_get ( DBR_STRING,
ca_element_count (chan), chan, pRS );
SEVCHK ( status, "array read request failed" );
status = ca_pend_io ( 30.0 );
SEVCHK ( status, "array read failed" );
free ( pRS );
}
/*
* write some random numbers into the array
*/
for ( i = 0; i < ca_element_count (chan); i++ ) {
pWF[i] = rand ();
pRF[i] = - pWF[i];
}
status = ca_array_put_callback ( DBR_DOUBLE, ca_element_count ( chan ),
chan, pWF, arrayWriteNotify, 0 );
SEVCHK ( status, "array write notify request failed" );
status = ca_array_get_callback ( DBR_DOUBLE, ca_element_count (chan),
chan, arrayReadNotify, pWF );
SEVCHK ( status, "array read notify request failed" );
while ( ! arrayWriteNotifyComplete && ! arrayReadNotifyComplete ) {
ca_pend_event ( 0.1 );
}
/*
* write some random numbers into the array
*/
for ( i = 0; i < ca_element_count (chan); i++ ) {
pWF[i] = rand ();
pRF[i] = - pWF[i];
}
arrayReadNotifyComplete = 0;
status = ca_array_put ( DBR_DOUBLE, ca_element_count ( chan ),
chan, pWF );
SEVCHK ( status, "array write notify request failed" );
status = ca_add_array_event ( DBR_DOUBLE, ca_element_count ( chan ),
chan, arrayReadNotify, pWF, 0.0, 0.0, 0.0, &id );
SEVCHK ( status, "array subscription request failed" );
while ( ! arrayReadNotifyComplete ) {
ca_pend_event ( 0.1 );
}
status = ca_clear_event ( id );
SEVCHK ( status, "clear event request failed" );
free ( pRF );
free ( pWF );
@@ -1629,6 +1678,8 @@ int acctst ( char *pName, unsigned channelCount, unsigned repetitionCount )
printf ( "CA Client V%s, channel name \"%s\"\n", ca_version (), pName );
putenv ( "EPICS_CA_MAX_ARRAY_BYTES=10000000" );
verifyDataTypeMacros ();
connections = ca_get_ioc_connection_count ();
@@ -1646,6 +1697,7 @@ int acctst ( char *pName, unsigned channelCount, unsigned repetitionCount )
printf ( "testing with a local channel\n" );
}
arrayTest ( chan );
verifyMonitorSubscriptionFlushIO ( chan );
monitorSubscriptionFirstUpdateTest ( chan );
performGrEnumTest ( chan );
@@ -1665,7 +1717,6 @@ int acctst ( char *pName, unsigned channelCount, unsigned repetitionCount )
test_sync_groups ( chan );
performDeleteTest ( chan );
eventClearTest ( chan );
arrayTest ( chan );
performMonitorUpdateTest ( chan );
/*
+5 -5
View File
@@ -43,11 +43,11 @@ bhe::~bhe ()
*
* updates beacon period, and looks for beacon anomalies
*/
bool bhe::updatePeriod ( epicsTime programBeginTime )
bool bhe::updatePeriod ( const epicsTime & programBeginTime,
const epicsTime & currentTime )
{
double currentPeriod;
bool netChange = false;
epicsTime current = epicsTime::getCurrent ();
if ( this->timeStamp == epicsTime () ) {
@@ -61,7 +61,7 @@ bool bhe::updatePeriod ( epicsTime programBeginTime )
* a TCP/IP connection created the beacon.
* (nothing to do but set the beacon time stamp and return)
*/
this->timeStamp = current;
this->timeStamp = currentTime;
return netChange;
}
@@ -69,7 +69,7 @@ bool bhe::updatePeriod ( epicsTime programBeginTime )
/*
* compute the beacon period (if we have seen at least two beacons)
*/
currentPeriod = current - this->timeStamp;
currentPeriod = currentTime - this->timeStamp;
if ( this->averagePeriod < 0.0 ) {
double totalRunningTime;
@@ -158,7 +158,7 @@ bool bhe::updatePeriod ( epicsTime programBeginTime )
this->averagePeriod = currentPeriod * 0.125 + this->averagePeriod * 0.875;
}
this->timeStamp = current;
this->timeStamp = currentTime;
return netChange;
}
+14 -4
View File
@@ -40,8 +40,10 @@ public:
epicsShareFunc bhe ( const epicsTime &initialTimeStamp, const inetAddrID &addr );
tcpiiu *getIIU () const;
void bindToIIU ( tcpiiu & );
void unbindFromIIU ();
epicsShareFunc void destroy ();
epicsShareFunc bool updatePeriod ( epicsTime programBeginTime );
epicsShareFunc bool updatePeriod ( const epicsTime &programBeginTime,
const epicsTime & currentTime );
epicsShareFunc double period () const;
epicsShareFunc void show ( unsigned level) const;
epicsShareFunc void * operator new ( size_t size );
@@ -71,13 +73,14 @@ private:
* between the 1st and 2nd beacons)
*/
inline bhe::bhe ( const epicsTime &initialTimeStamp, const inetAddrID &addr ) :
inetAddrID (addr), piiu (0), timeStamp (initialTimeStamp), averagePeriod ( - DBL_MAX )
inetAddrID ( addr ), piiu ( 0 ),
timeStamp ( initialTimeStamp ), averagePeriod ( - DBL_MAX )
{
# ifdef DEBUG
{
char name[64];
ipAddrToDottedIP (&addr, name, sizeof(name));
::printf ("created beacon entry for %s\n", name);
addr.name ( name, sizeof ( name ) );
::printf ( "created beacon entry for %s\n", name );
}
# endif
}
@@ -95,6 +98,13 @@ inline void bhe::bindToIIU ( tcpiiu &iiuIn )
}
}
inline void bhe::unbindFromIIU ()
{
this->piiu = 0;
this->timeStamp = epicsTime();
this->averagePeriod = - DBL_MAX;
}
#endif // ifdef bheh
+43 -47
View File
@@ -35,55 +35,57 @@
#define capStrOfX(A) capStrOf ( A )
/*
* CA protocol number
* CA protocol revision
* TCP/UDP port number (bumped each major protocol change)
*/
#define CA_PROTOCOL_VERSION 4
#define CA_MINOR_VERSION 8
#define CA_VERSION_STRING \
( capStrOfX ( CA_PROTOCOL_VERSION ) "." capStrOfX ( CA_MINOR_VERSION ) )
#define CA_MAJOR_PROTOCOL_REVISION 4
#define CA_VERSION_STRING( MINOR_REVISION ) \
( capStrOfX ( CA_MAJOR_PROTOCOL_REVISION ) "." capStrOfX ( MINOR_REVISION ) )
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
#if CA_PROTOCOL_VERSION == 4u
# define CA_V41(MAJOR,MINOR) ((MINOR)>=1u)
# define CA_V42(MAJOR,MINOR) ((MINOR)>=2u)
# define CA_V43(MAJOR,MINOR) ((MINOR)>=3u)
# define CA_V44(MAJOR,MINOR) ((MINOR)>=4u)
# define CA_V45(MAJOR,MINOR) ((MINOR)>=5u)
# define CA_V46(MAJOR,MINOR) ((MINOR)>=6u)
# define CA_V47(MAJOR,MINOR) ((MINOR)>=7u)
# define CA_V48(MAJOR,MINOR) ((MINOR)>=8u)
#elif CA_PROTOCOL_VERSION > 4u
# define CA_V41(MAJOR,MINOR) ( 1u )
# define CA_V42(MAJOR,MINOR) ( 1u )
# define CA_V43(MAJOR,MINOR) ( 1u )
# define CA_V44(MAJOR,MINOR) ( 1u )
# define CA_V45(MAJOR,MINOR) ( 1u )
# define CA_V46(MAJOR,MINOR) ( 1u )
# define CA_V47(MAJOR,MINOR) ( 1u )
# define CA_V48(MAJOR,MINOR) ( 1u )
#if CA_MAJOR_PROTOCOL_REVISION == 4u
# define CA_V41(MINOR) ((MINOR)>=1u)
# define CA_V42(MINOR) ((MINOR)>=2u)
# define CA_V43(MINOR) ((MINOR)>=3u)
# define CA_V44(MINOR) ((MINOR)>=4u)
# define CA_V45(MINOR) ((MINOR)>=5u)
# define CA_V46(MINOR) ((MINOR)>=6u)
# define CA_V47(MINOR) ((MINOR)>=7u)
# define CA_V48(MINOR) ((MINOR)>=8u)
# define CA_V49(MINOR) ((MINOR)>=9u)
#elif CA_MAJOR_PROTOCOL_REVISION > 4u
# define CA_V41(MINOR) ( 1u )
# define CA_V42(MINOR) ( 1u )
# define CA_V43(MINOR) ( 1u )
# define CA_V44(MINOR) ( 1u )
# define CA_V45(MINOR) ( 1u )
# define CA_V46(MINOR) ( 1u )
# define CA_V47(MINOR) ( 1u )
# define CA_V48(MINOR) ( 1u )
# define CA_V49(MINOR) ( 1u )
#else
# define CA_V41(MAJOR,MINOR) ( 0u )
# define CA_V42(MAJOR,MINOR) ( 0u )
# define CA_V43(MAJOR,MINOR) ( 0u )
# define CA_V44(MAJOR,MINOR) ( 0u )
# define CA_V45(MAJOR,MINOR) ( 0u )
# define CA_V46(MAJOR,MINOR) ( 0u )
# define CA_V47(MAJOR,MINOR) ( 0u )
# define CA_V48(MAJOR,MINOR) ( 0u )
# define CA_V41(MINOR) ( 0u )
# define CA_V42(MINOR) ( 0u )
# define CA_V43(MINOR) ( 0u )
# define CA_V44(MINOR) ( 0u )
# define CA_V45(MINOR) ( 0u )
# define CA_V46(MINOR) ( 0u )
# define CA_V47(MINOR) ( 0u )
# define CA_V48(MINOR) ( 0u )
# define CA_V49(MINOR) ( 0u )
#endif
/*
* NOTE: These port numbers are only used if the CA repeater and
* These port numbers are only used if the CA repeater and
* CA server port numbers cant be obtained from the EPICS
* 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)
#define CA_SERVER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u)
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*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)
* (the MTU of Ethernet is currently independent of its speed varient)
*/
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
@@ -174,20 +176,19 @@ typedef ca_uint32_t caResId;
* the common part of each message sent/recv by the
* CA server.
*/
typedef struct ca_hdr {
typedef struct ca_hdr {
ca_uint16_t m_cmmd; /* operation to be performed */
ca_uint16_t m_postsize; /* size of message extension */
ca_uint16_t m_dataType; /* operation data type */
ca_uint16_t m_postsize; /* size of payload */
ca_uint16_t m_dataType; /* operation data type */
ca_uint16_t m_count; /* operation data count */
ca_uint32_t m_cid; /* channel identifier */
ca_uint32_t m_available; /* undefined message location for use
* by client processes */
}caHdr;
ca_uint32_t m_available; /* protocol stub dependent */
} caHdr;
/*
* for monitor (event) message extension
*/
struct mon_info{
struct mon_info {
ca_float32_t m_lval; /* low delta */
ca_float32_t m_hval; /* high delta */
ca_float32_t m_toval; /* period btween samples */
@@ -195,11 +196,6 @@ struct mon_info{
ca_uint16_t m_pad; /* extend to 32 bits */
};
struct monops { /* monitor req opi to ioc */
caHdr m_header;
struct mon_info m_info;
};
/*
* PV names greater than this length assumed to be invalid
*/
+384 -207
View File
File diff suppressed because it is too large Load Diff
+99 -46
View File
@@ -21,6 +21,7 @@
#include "ipAddrToAsciiAsynchronous.h"
#include "epicsTimer.h"
#include "epicsEvent.h"
#include "freeList.h"
#include "nciu.h"
@@ -93,6 +94,7 @@ public:
struct CASG;
class inetAddrID;
struct caHdrLargeArray;
class cac : private cacRecycle
{
@@ -101,7 +103,8 @@ public:
virtual ~cac ();
// beacon management
void beaconNotify ( const inetAddrID &addr );
void beaconNotify ( const inetAddrID &addr,
const epicsTime &currentTime );
void repeaterSubscribeConfirmNotify ();
// IIU routines
@@ -122,7 +125,7 @@ public:
void connectAllIO ( nciu &chan );
void disconnectAllIO ( nciu &chan );
void destroyAllIO ( nciu &chan );
void executeResponse ( tcpiiu &, caHdr &, char *pMshBody );
bool executeResponse ( tcpiiu &, caHdrLargeArray &, char *pMsgBody );
void ioCancel ( nciu &chan, const cacChannel::ioid &id );
void ioShow ( const cacChannel::ioid &id, unsigned level ) const;
@@ -130,8 +133,8 @@ public:
bool connectChannel ( unsigned id );
void installNetworkChannel ( nciu &, netiiu *&piiu );
bool lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
unsigned typeCode, unsigned long count, unsigned minorVersionNumber,
const osiSockAddr & );
ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber,
const osiSockAddr &, const epicsTime & currentTime );
void uninstallChannel ( nciu & );
cacChannel & createChannel ( const char *name_str, cacChannelNotify &chan );
void registerService ( cacService &service );
@@ -144,7 +147,7 @@ public:
cacChannel::ioid readNotifyRequest ( nciu &, unsigned type,
unsigned nElem, cacReadNotify & );
cacChannel::ioid subscriptionRequest ( nciu &, unsigned type,
unsigned long nElem, unsigned mask, cacStateNotify & );
arrayElementCount nElem, unsigned mask, cacStateNotify & );
// sync group routines
CASG * lookupCASG ( unsigned id );
@@ -154,9 +157,6 @@ public:
// exception generation
void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo );
void exception ( int status, const char *pContext,
unsigned type, unsigned long count,
const char *pFileName, unsigned lineNo );
// callback preemption control
void enableCallbackPreemption ();
@@ -165,21 +165,30 @@ public:
// diagnostics
unsigned connectionCount () const;
void show ( unsigned level ) const;
int printf ( const char *pformat, ... );
int vPrintf ( const char *pformat, va_list args );
int printf ( const char *pformat, ... ) const;
int vPrintf ( const char *pformat, va_list args ) const;
void ipAddrToAsciiAsynchronousRequestInstall ( ipAddrToAsciiAsynchronous & request );
void signal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, ... );
void vSignal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args );
// misc
const char * userNamePointer () const;
unsigned getInitializingThreadsPriority () const;
epicsMutex & mutexRef ();
void attachToClientCtx ();
char * allocateSmallBufferTCP ();
void releaseSmallBufferTCP ( char * );
unsigned largeBufferSizeTCP () const;
char * allocateLargeBufferTCP ();
void releaseLargeBufferTCP ( char * );
private:
ioCounterNet ioCounter;
ipAddrToAsciiEngine ipToAEngine;
cacServiceList services;
tsDLList <tcpiiu> iiuList;
tsDLList < tcpiiu > iiuList;
chronIntIdResTable
< nciu > chanTable;
chronIntIdResTable
@@ -208,10 +217,13 @@ private:
class searchTimer *pSearchTmr;
class repeaterSubscribeTimer
*pRepeaterSubscribeTmr;
void *tcpSmallRecvBufFreeList;
void *tcpLargeRecvBufFreeList;
cacNotify &notify;
unsigned ioNotifyInProgressId;
unsigned initializingThreadsPriority;
unsigned threadsBlockingOnNotifyCompletion;
unsigned maxRecvBytesTCP;
bool enablePreemptiveCallback;
bool ioInProgress;
bool setupUDP ();
@@ -220,39 +232,57 @@ private:
void recycleWriteNotifyIO ( netWriteNotifyIO &io );
void recycleSubscription ( netSubscription &io );
bool ioCompletionNotify ( unsigned id, unsigned type,
unsigned long count, const void *pData );
bool ioExceptionNotify ( unsigned id,
void ioCompletionNotify ( unsigned id, unsigned type,
arrayElementCount count, const void *pData );
void ioExceptionNotify ( unsigned id,
int status, const char *pContext );
bool ioExceptionNotify ( unsigned id, int status,
const char *pContext, unsigned type, unsigned long count );
bool ioCompletionNotifyAndDestroy ( unsigned id );
bool ioCompletionNotifyAndDestroy ( unsigned id,
unsigned type, unsigned long count, const void *pData );
bool ioExceptionNotifyAndDestroy ( unsigned id,
void ioExceptionNotify ( unsigned id, int status,
const char *pContext, unsigned type, arrayElementCount count );
void ioCompletionNotifyAndDestroy ( unsigned id );
void ioCompletionNotifyAndDestroy ( unsigned id,
unsigned type, arrayElementCount count, const void *pData );
void ioExceptionNotifyAndDestroy ( unsigned id,
int status, const char *pContext );
bool ioExceptionNotifyAndDestroy ( unsigned id,
int status, const char *pContext, unsigned type, unsigned long count );
void ioExceptionNotifyAndDestroy ( unsigned id,
int status, const char *pContext, unsigned type, arrayElementCount count );
// recv protocol stubs
bool noopAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool echoRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool writeNotifyRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool readNotifyRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool eventRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool readRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool clearChannelRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool exceptionRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool accessRightsRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool claimCIURespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool verifyAndDisconnectChan ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool badTCPRespAction ( tcpiiu &, const caHdr &, void *pMsgBdy );
bool noopAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool echoRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool writeNotifyRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool readNotifyRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool eventRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool readRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool clearChannelRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool exceptionRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool accessRightsRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool claimCIURespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool verifyAndDisconnectChan ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
bool badTCPRespAction ( tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
typedef bool ( cac::*pProtoStubTCP ) (
tcpiiu &, const caHdr &, void *pMsgBdy );
tcpiiu &, const caHdrLargeArray &, void *pMsgBdy );
static const pProtoStubTCP tcpJumpTableCAC [];
};
extern "C" void ca_default_exception_handler ( struct exception_handler_args args );
bool defaultExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool eventAddExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool readExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool writeExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool clearChanExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool readNotifyExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool writeNotifyExcep ( tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
typedef bool ( cac::*pExcepProtoStubTCP ) (
tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
static const pExcepProtoStubTCP tcpExcepJumpTableCAC [];
};
inline const char * cac::userNamePointer () const
{
@@ -300,18 +330,41 @@ inline void cac::exception ( int status, const char *pContext,
this->notify.exception ( status, pContext, pFileName, lineNo );
}
inline void cac::exception ( int status, const char *pContext,
unsigned type, unsigned long count,
const char *pFileName, unsigned lineNo )
{
this->notify.exception ( status, pContext, type, count, pFileName, lineNo );
}
inline int cac::vPrintf ( const char *pformat, va_list args )
inline int cac::vPrintf ( const char *pformat, va_list args ) const
{
return this->notify.vPrintf ( pformat, args );
}
inline void cac::attachToClientCtx ()
{
this->notify.attachToClientCtx ();
}
inline char * cac::allocateSmallBufferTCP ()
{
return ( char * ) freeListMalloc ( this->tcpSmallRecvBufFreeList );
}
inline void cac::releaseSmallBufferTCP ( char *pBuf )
{
freeListFree ( this->tcpSmallRecvBufFreeList, pBuf );
}
inline unsigned cac::largeBufferSizeTCP () const
{
return this->maxRecvBytesTCP;
}
inline char * cac::allocateLargeBufferTCP ()
{
return ( char * ) freeListMalloc ( this->tcpLargeRecvBufFreeList );
}
inline void cac::releaseLargeBufferTCP ( char *pBuf )
{
freeListFree ( this->tcpLargeRecvBufFreeList, pBuf );
}
inline bool recvProcessThread::isCurrentThread () const
{
return this->thread.isCurrentThread ();
+24 -18
View File
@@ -45,12 +45,16 @@
class cacChannel;
// this should not be passing caerr.h status to the exception callback
typedef unsigned long arrayElementCount;
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
class epicsShareClass cacWriteNotify {
public:
virtual ~cacWriteNotify () = 0;
virtual void completion () = 0;
virtual void exception ( int status, const char *pContext ) = 0;
virtual void exception ( int status, const char *pContext,
unsigned type, arrayElementCount count ) = 0;
};
// 1) this should not be passing caerr.h status to the exception callback
@@ -59,9 +63,9 @@ class epicsShareClass cacReadNotify {
public:
virtual ~cacReadNotify () = 0;
virtual void completion ( unsigned type,
unsigned long count, const void *pData ) = 0;
arrayElementCount count, const void *pData ) = 0;
virtual void exception ( int status,
const char *pContext, unsigned type, unsigned long count ) = 0;
const char *pContext, unsigned type, arrayElementCount count ) = 0;
};
// 1) this should not be passing caerr.h status to the exception callback
@@ -70,9 +74,9 @@ class epicsShareClass cacStateNotify {
public:
virtual ~cacStateNotify () = 0;
virtual void current ( unsigned type,
unsigned long count, const void *pData ) = 0;
arrayElementCount count, const void *pData ) = 0;
virtual void exception ( int status,
const char *pContext, unsigned type, unsigned long count ) = 0;
const char *pContext, unsigned type, arrayElementCount count ) = 0;
};
class caAccessRights {
@@ -103,6 +107,10 @@ public:
virtual void disconnectNotify () = 0;
virtual void accessRightsNotify ( const caAccessRights & ) = 0;
virtual void exception ( int status, const char *pContext ) = 0;
virtual void readException ( int status, const char *pContext,
unsigned type, arrayElementCount count, void *pValue ) = 0;
virtual void writeException ( int status, const char *pContext,
unsigned type, arrayElementCount count ) = 0;
// not for public consumption -- can we get rid of this ????
virtual bool includeFirstConnectInCountOfOutstandingIO () const;
};
@@ -125,21 +133,21 @@ public:
virtual const char *pName () const = 0;
virtual void show ( unsigned level ) const = 0;
virtual void initiateConnect () = 0;
virtual void write ( unsigned type, unsigned long count,
virtual void write ( unsigned type, arrayElementCount count,
const void *pValue ) = 0;
// we may need to include an optimization for read copy here if we want to enable
// reasonable performance of the old API. Adding it here means that the outstanding IO
// count must be visible :-(.
virtual ioStatus read ( unsigned type, unsigned long count,
virtual ioStatus read ( unsigned type, arrayElementCount count,
cacReadNotify &, ioid * = 0 ) = 0;
virtual ioStatus write ( unsigned type, unsigned long count,
virtual ioStatus write ( unsigned type, arrayElementCount count,
const void *pValue, cacWriteNotify &, ioid * = 0 ) = 0;
virtual void subscribe ( unsigned type, unsigned long count,
virtual void subscribe ( unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &, ioid * = 0 ) = 0;
virtual void ioCancel ( const ioid & ) = 0;
virtual void ioShow ( const ioid &, unsigned level ) const = 0;
virtual short nativeType () const = 0;
virtual unsigned long nativeElementCount () const = 0;
virtual arrayElementCount nativeElementCount () const = 0;
virtual caAccessRights accessRights () const; // defaults to unrestricted access
virtual unsigned searchAttempts () const; // defaults to zero
virtual double beaconPeriod () const; // defaults to negative DBL_MAX
@@ -160,7 +168,7 @@ public:
class noReadAccess {};
class notConnected {};
class unsupportedByService {};
class noMemory {};
class msgBodyCacheTooSmall {}; // hopefully this one goes away in the future
private:
cacChannelNotify & callback;
@@ -169,17 +177,15 @@ private:
class cacNotify {
public:
virtual ~cacNotify () = 0;
// exception mechanism needs to be designed
virtual void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo ) = 0;
virtual void exception ( int status, const char *pContext,
unsigned type, unsigned long count,
virtual void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo ) = 0;
// perhaps this should be phased out in deference to the exception mechanism
virtual int vPrintf ( const char *pformat, va_list args ) = 0;
virtual int vPrintf ( const char *pformat, va_list args ) const = 0;
// this should probably be phased out (its not OS independent)
virtual void fdWasCreated ( int fd ) = 0;
virtual void fdWasDestroyed ( int fd ) = 0;
// backwards compatibility
virtual void attachToClientCtx () = 0;
};
struct cacService : public tsDLNode < cacService > {
+1 -1
View File
@@ -142,7 +142,7 @@ READONLY char *ca_message_text[]
"Unable to allocate additional dynamic memory",
"Unknown IO channel",
"Record field specified inappropriate for channel specified",
"The array or data structure specified will not fit in CA message buffer",
"The array or data structure specified is less than EPICS_CA_MAX_ARRAY_BYTES",
"User specified timeout on IO operation expired",
"Sorry, that feature is planned but not supported at this time",
"The supplied string is unusually large",
+6 -6
View File
@@ -29,8 +29,8 @@ int main ( int, char ** )
char buf [0x4000];
const char *pCurBuf;
const caHdr *pCurMsg;
unsigned serverPort;
unsigned repeaterPort;
ca_uint16_t serverPort;
ca_uint16_t repeaterPort;
int status;
serverPort =
@@ -151,13 +151,14 @@ int main ( int, char ** )
}
bool netChange;
epicsTime currentTime = epicsTime::getCurrent();
/*
* look for it in the hash table
*/
bhe *pBHE = beaconTable.lookup ( ina );
if ( pBHE ) {
netChange = pBHE->updatePeriod ( programBeginTime );
netChange = pBHE->updatePeriod ( programBeginTime, currentTime );
}
else {
/*
@@ -168,7 +169,7 @@ int main ( int, char ** )
* shortly after the program started up)
*/
netChange = false;
pBHE = new bhe ( epicsTime::getCurrent (), ina );
pBHE = new bhe ( currentTime, ina );
if ( pBHE ) {
if ( beaconTable.add ( *pBHE ) < 0 ) {
pBHE->destroy ();
@@ -178,8 +179,7 @@ int main ( int, char ** )
if ( netChange ) {
char date[64];
epicsTime current = epicsTime::getCurrent ();
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
char host[64];
ipAddrToA ( &ina, host, sizeof ( host ) );
printf ("CA server beacon anomaly: %s %s\n", date, host );
+4 -2
View File
@@ -49,13 +49,13 @@ typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
* test_pend()
*/
LOCAL void test_pend(
ti *pItems,
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
int status;
for (i=0; i<iterations; i++) {
status = ca_pend_event(1e-9);
@@ -107,6 +107,7 @@ unsigned *pInlineIter
/*
* test_sync_search()
*/
#if 0
LOCAL void test_sync_search(
ti *pItems,
unsigned iterations,
@@ -125,6 +126,7 @@ unsigned *pInlineIter
*pInlineIter = 1;
}
#endif
/*
* test_free ()
+85 -41
View File
@@ -17,6 +17,8 @@
#ifndef comBufh
#define comBufh
#include <new>
#include <string.h>
#include "epicsAssert.h"
@@ -31,6 +33,7 @@ class wireSendAdapter {
public:
virtual unsigned sendBytes ( const void *pBuf,
unsigned nBytesInBuf ) = 0;
virtual void forcedShutdown () = 0;
};
class wireRecvAdapter {
@@ -62,17 +65,20 @@ public:
unsigned copyOutBytes ( void *pBuf, unsigned nBytes );
bool copyOutAllBytes ( void *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
void * operator new ( size_t size );
void * operator new ( size_t size, const std::nothrow_t & );
void operator delete ( void *pCadaver, size_t size );
bool flushToWire ( wireSendAdapter & );
unsigned fillFromWire ( wireRecvAdapter & );
epicsUInt8 getByte ();
class insufficentBytesAvailable {};
protected:
~comBuf ();
private:
unsigned nextWriteIndex;
unsigned nextReadIndex;
unsigned char buf [ comBufSize ]; // optimal for 100 Mb Ethernet LAN MTU
unsigned clipNElem ( unsigned elemSize, unsigned nElem );
epicsUInt8 buf [ comBufSize ];
unsigned unoccupiedElem ( unsigned elemSize, unsigned nElem );
unsigned occupiedElem ( unsigned elemSize, unsigned nElem );
static tsFreeList < class comBuf, 0x20 > freeList;
static epicsMutex freeListMutex;
};
@@ -90,7 +96,7 @@ inline void comBuf::destroy ()
delete this;
}
inline void * comBuf::operator new ( size_t size )
inline void * comBuf::operator new ( size_t size, const std::nothrow_t & )
{
epicsAutoMutex locker ( comBuf::freeListMutex );
return comBuf::freeList.allocate ( size );
@@ -109,17 +115,18 @@ inline unsigned comBuf::unoccupiedBytes () const
inline unsigned comBuf::occupiedBytes () const
{
// assert (this->nextWriteIndex >= this->nextReadIndex);
return this->nextWriteIndex - this->nextReadIndex;
}
inline bool comBuf::copyInAllBytes ( const void *pBuf, unsigned nBytes )
{
if ( nBytes > this->unoccupiedBytes () ) {
return false;
if ( nBytes <= this->unoccupiedBytes () ) {
memcpy ( &this->buf[this->nextWriteIndex], pBuf, nBytes);
this->nextWriteIndex += nBytes;
return true;
}
memcpy ( &this->buf[this->nextWriteIndex], pBuf, nBytes);
this->nextWriteIndex += nBytes;
return true;
return false;
}
inline unsigned comBuf::copyInBytes ( const void *pBuf, unsigned nBytes )
@@ -145,12 +152,12 @@ inline unsigned comBuf::copyIn ( comBuf &bufIn )
inline bool comBuf::copyOutAllBytes ( void *pBuf, unsigned nBytes )
{
if ( nBytes > this->occupiedBytes () ) {
return false;
if ( nBytes <= this->occupiedBytes () ) {
memcpy ( pBuf, &this->buf[this->nextReadIndex], nBytes);
this->nextReadIndex += nBytes;
return true;
}
memcpy ( pBuf, &this->buf[this->nextReadIndex], nBytes);
this->nextReadIndex += nBytes;
return true;
return false;
}
inline unsigned comBuf::copyOutBytes ( void *pBuf, unsigned nBytes )
@@ -197,7 +204,7 @@ inline unsigned comBuf::fillFromWire ( wireRecvAdapter &wire )
return nNewBytes;
}
inline unsigned comBuf::clipNElem ( unsigned elemSize, unsigned nElem )
inline unsigned comBuf::unoccupiedElem ( unsigned elemSize, unsigned nElem )
{
unsigned avail = this->unoccupiedBytes ();
if ( elemSize * nElem > avail ) {
@@ -218,75 +225,112 @@ 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 );
nElem = this->unoccupiedElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
this->buf[this->nextWriteIndex++] = pValue[i] >> 8u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 0u;
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 8u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 0u );
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsUInt16 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
nElem = this->unoccupiedElem ( sizeof (*pValue), nElem );
for ( unsigned i = 0u; i < nElem; i++ ) {
this->buf[this->nextWriteIndex++] = pValue[i] >> 8u;
this->buf[this->nextWriteIndex++] = pValue[i] >> 0u;
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 8u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 0u );
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsInt32 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
nElem = this->unoccupiedElem ( 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;
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 24u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 16u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 8u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 0u );
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsUInt32 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
nElem = this->unoccupiedElem ( 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;
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 24u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 16u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 8u );
this->buf[this->nextWriteIndex++] =
static_cast < char > ( pValue[i] >> 0u );
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsFloat32 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
nElem = this->unoccupiedElem ( 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;
this->nextWriteIndex += sizeof ( *pValue );
}
return nElem;
}
inline unsigned comBuf::copyIn ( const epicsFloat64 *pValue, unsigned nElem )
{
nElem = this->clipNElem ( sizeof (*pValue), nElem );
nElem = this->unoccupiedElem ( 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;
this->nextWriteIndex += sizeof ( *pValue );
}
return nElem;
}
#endif // comBuf
inline unsigned comBuf::copyIn ( const epicsOldString *pValue, unsigned nElem )
{
nElem = this->unoccupiedElem ( sizeof (*pValue), nElem );
unsigned size = nElem * sizeof ( *pValue );
memcpy ( &this->buf[ this->nextWriteIndex ], pValue, size );
this->nextWriteIndex += size;
return nElem;
}
inline unsigned comBuf::occupiedElem ( unsigned elemSize, unsigned nElem )
{
unsigned avail = this->occupiedBytes ();
if ( elemSize * nElem > avail ) {
return avail / elemSize;
}
else {
return nElem;
}
}
inline epicsUInt8 comBuf::getByte ()
{
if ( this->occupiedBytes () ) {
return this->buf[ this->nextReadIndex++ ];
}
else {
throw insufficentBytesAvailable ();
}
}
#endif // ifndef comBufh
+47 -11
View File
@@ -59,27 +59,47 @@ unsigned comQueRecv::occupiedBytes () const
return nBytes;
}
bool comQueRecv::copyOutBytes ( void *pBuf, unsigned nBytes )
unsigned comQueRecv::copyOutBytes ( void *pBuf, unsigned nBytes )
{
char *pCharBuf = static_cast < char * > ( pBuf );
// dont return partial message
if ( nBytes > this->occupiedBytes () ) {
return false;
}
unsigned bytesLeft = nBytes;
while ( bytesLeft ) {
unsigned totalBytes = 0u;
do {
comBuf * pComBuf = this->bufs.first ();
assert ( pComBuf );
bytesLeft -= pComBuf->copyOutBytes ( &pCharBuf[nBytes-bytesLeft], bytesLeft );
if ( ! pComBuf ) {
return totalBytes;
}
totalBytes += pComBuf->copyOutBytes ( &pCharBuf[totalBytes], nBytes - totalBytes );
if ( pComBuf->occupiedBytes () == 0u ) {
this->bufs.remove ( *pComBuf );
pComBuf->destroy ();
}
}
while ( totalBytes < nBytes );
return totalBytes;
}
return true;
unsigned comQueRecv::removeBytes ( unsigned nBytes )
{
unsigned totalBytes = 0u;
unsigned bytesLeft = nBytes;
while ( bytesLeft ) {
comBuf * pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
return totalBytes;
}
unsigned nBytes = pComBuf->removeBytes ( bytesLeft );
if ( pComBuf->occupiedBytes () == 0u ) {
this->bufs.remove ( *pComBuf );
pComBuf->destroy ();
}
if ( nBytes == 0u) {
return totalBytes;
}
totalBytes += nBytes;
bytesLeft = nBytes - totalBytes;
}
return nBytes;
}
void comQueRecv::pushLastComBufReceived ( comBuf & bufIn )
@@ -98,3 +118,19 @@ void comQueRecv::pushLastComBufReceived ( comBuf & bufIn )
}
}
epicsUInt8 comQueRecv::popUInt8 ()
{
comBuf *pComBuf = this->bufs.first ();
if ( pComBuf ) {
epicsUInt8 tmp = pComBuf->getByte ();
if ( pComBuf->occupiedBytes() == 0u ) {
this->bufs.remove ( *pComBuf );
pComBuf->destroy ();
}
return tmp;
}
throw insufficentBytesAvailable ();
}
+6 -36
View File
@@ -87,66 +87,36 @@ void comQueSend::clear ()
this->nBytesPending -= pBuf->occupiedBytes ();
pBuf->destroy ();
}
this->reservoir.drain ();
}
// 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)
void comQueSend::reserveSpace ( unsigned msgSize )
{
unsigned bytesReserved;
bytesReserved = this->reservoir.nBytes ();
comBuf *pComBuf = this->bufs.last ();
if ( pComBuf ) {
bytesReserved += pComBuf->unoccupiedBytes ();
}
while ( bytesReserved < msgSize ) {
reservoir.addOneBuffer ();
bytesReserved += comBuf::capacityBytes ();
}
}
void comQueSend::copy_dbr_string ( const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->nBytesPending, this->bufs, this->reservoir,
static_cast <const dbr_string_t *> ( pValue ), nElem );
this->copyIn ( static_cast <const dbr_string_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_short ( const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->nBytesPending, this->bufs, this->reservoir,
static_cast <const dbr_short_t *> ( pValue ), nElem );
this->copyIn ( static_cast <const dbr_short_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_float ( const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->nBytesPending, this->bufs, this->reservoir,
static_cast <const dbr_float_t *> ( pValue ), nElem );
this->copyIn ( static_cast <const dbr_float_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_char ( const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->nBytesPending, this->bufs, this->reservoir,
static_cast <const dbr_char_t *> ( pValue ), nElem );
this->copyIn ( static_cast <const dbr_char_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_long ( const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->nBytesPending, this->bufs, this->reservoir,
static_cast <const dbr_long_t *> ( pValue ), nElem );
this->copyIn ( static_cast <const dbr_long_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_double ( const void *pValue, unsigned nElem )
{
comQueSend_copyIn ( this->nBytesPending, this->bufs, this->reservoir,
static_cast <const dbr_double_t *> ( pValue ), nElem );
this->copyIn ( static_cast <const dbr_double_t *> ( pValue ), nElem );
}
const comQueSend::copyFunc_t comQueSend::dbrCopyVector [39] = {
+163 -161
View File
@@ -21,6 +21,8 @@
#include "iocinf.h"
#include "caProto.h"
typedef unsigned long arrayElementCount;
#define epicsExportSharedSymbols
#include "net_convert.h"
@@ -55,10 +57,10 @@
*
*/
LOCAL void cvrt_string(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
char *pSrc = (char *) s;
@@ -79,15 +81,15 @@ unsigned long num /* number of values */
* CVRT_SHORT()
*/
LOCAL void cvrt_short(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
dbr_short_t *pSrc = (dbr_short_t *) s;
dbr_short_t *pDest = (dbr_short_t *) d;
unsigned long i;
dbr_short_t *pSrc = (dbr_short_t *) s;
dbr_short_t *pDest = (dbr_short_t *) d;
arrayElementCount i;
for(i=0; i<num; i++){
*pDest = dbr_ntohs( *pSrc );
@@ -107,15 +109,15 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_char(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
unsigned long i;
dbr_char_t *pSrc = (dbr_char_t *) s;
dbr_char_t *pDest = (dbr_char_t *) d;
arrayElementCount i;
dbr_char_t *pSrc = (dbr_char_t *) s;
dbr_char_t *pDest = (dbr_char_t *) d;
/* convert "in place" -> nothing to do */
if (s == d)
@@ -129,15 +131,15 @@ unsigned long num /* number of values */
* CVRT_LONG()
*/
LOCAL void cvrt_long(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
unsigned long i;
dbr_long_t *pSrc = (dbr_long_t *) s;
dbr_long_t *pDest = (dbr_long_t *) d;
arrayElementCount i;
dbr_long_t *pSrc = (dbr_long_t *) s;
dbr_long_t *pDest = (dbr_long_t *) d;
for(i=0; i<num; i++){
*pDest = dbr_ntohl( *pSrc );
@@ -157,15 +159,15 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_enum(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
unsigned long i;
dbr_enum_t *pSrc;
dbr_enum_t *pDest;
arrayElementCount i;
dbr_enum_t *pSrc;
dbr_enum_t *pDest;
pSrc = (dbr_enum_t *) s;
pDest = (dbr_enum_t *) d;
@@ -189,15 +191,15 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_float(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
unsigned long i;
dbr_float_t *pSrc = (dbr_float_t *) s;
dbr_float_t *pDest = (dbr_float_t *) d;
arrayElementCount i;
dbr_float_t *pSrc = (dbr_float_t *) s;
dbr_float_t *pDest = (dbr_float_t *) d;
for(i=0; i<num; i++){
if(encode){
@@ -218,15 +220,15 @@ unsigned long num /* number of values */
* CVRT_DOUBLE()
*/
LOCAL void cvrt_double(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
unsigned long i;
dbr_double_t *pSrc = (dbr_double_t *) s;
dbr_double_t *pDest = (dbr_double_t *) d;
arrayElementCount i;
dbr_double_t *pSrc = (dbr_double_t *) s;
dbr_double_t *pDest = (dbr_double_t *) d;
for(i=0; i<num; i++){
if(encode){
@@ -257,10 +259,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_string(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_string *pSrc = (struct dbr_sts_string *) s;
@@ -295,10 +297,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_short(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_int *pSrc = (struct dbr_sts_int *) s;
@@ -330,10 +332,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_float(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_float *pSrc = (struct dbr_sts_float *) s;
@@ -356,10 +358,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_double(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_double *pSrc = (struct dbr_sts_double *) s;
@@ -385,10 +387,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_enum(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_enum *pSrc = (struct dbr_sts_enum *) s;
@@ -413,10 +415,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_short(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_gr_int *pSrc = (struct dbr_gr_int *) s;
@@ -450,10 +452,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_char(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_gr_char *pSrc = (struct dbr_gr_char *) s;
@@ -491,10 +493,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_long(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_gr_long *pSrc = (struct dbr_gr_long *) s;
@@ -529,10 +531,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_enum(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_gr_enum *pSrc = (struct dbr_gr_enum *) s;
@@ -562,10 +564,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_double(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_gr_double *pSrc = (struct dbr_gr_double *) s;
@@ -624,10 +626,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_float(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_gr_float *pSrc = (struct dbr_gr_float *) s;
@@ -687,10 +689,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_short(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_ctrl_int *pSrc = (struct dbr_ctrl_int *) s;
@@ -727,10 +729,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_long(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_ctrl_long *pSrc = (struct dbr_ctrl_long*) s;
@@ -767,10 +769,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_char(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_ctrl_char *pSrc = (struct dbr_ctrl_char *) s;
@@ -805,10 +807,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_double(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_ctrl_double *pSrc = (struct dbr_ctrl_double *) s;
@@ -869,10 +871,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_float(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_ctrl_float *pSrc = (struct dbr_ctrl_float *) s;
@@ -932,10 +934,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_enum(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_ctrl_enum *pSrc = (struct dbr_ctrl_enum *) s;
@@ -968,10 +970,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_char(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_char *pSrc = (struct dbr_sts_char *) s;
@@ -999,10 +1001,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_long(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_sts_long *pSrc = (struct dbr_sts_long *) s;
@@ -1031,10 +1033,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_string(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_string *pSrc = (struct dbr_time_string *) s;
@@ -1063,10 +1065,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_short(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_short *pSrc = (struct dbr_time_short *) s;
@@ -1097,10 +1099,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_float(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_float *pSrc = (struct dbr_time_float *) s;
@@ -1125,10 +1127,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_double(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_double *pSrc = (struct dbr_time_double *) s;
@@ -1154,10 +1156,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_enum(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_enum *pSrc = (struct dbr_time_enum *) s;
@@ -1184,10 +1186,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_char(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_char *pSrc = (struct dbr_time_char *) s;
@@ -1216,10 +1218,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_long(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_time_long *pSrc = (struct dbr_time_long *) s;
@@ -1247,15 +1249,15 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_put_ackt(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
dbr_put_ackt_t *pSrc = (dbr_put_ackt_t *) s;
dbr_put_ackt_t *pDest = (dbr_put_ackt_t *) d;
unsigned long i;
dbr_put_ackt_t *pSrc = (dbr_put_ackt_t *) s;
dbr_put_ackt_t *pDest = (dbr_put_ackt_t *) d;
arrayElementCount i;
for(i=0; i<num; i++){
*pDest = dbr_ntohs( *pSrc );
@@ -1281,10 +1283,10 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_stsack_string(
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
arrayElementCount num /* number of values */
)
{
struct dbr_stsack_string *pSrc = (struct dbr_stsack_string *) s;
+1 -1
View File
@@ -586,7 +586,7 @@ struct dbr_ctrl_double{
};
#define dbr_size_n(TYPE,COUNT)\
((unsigned)((COUNT)==1?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
/* size for each type - array indexed by the DBR_ type code */
epicsShareExtern READONLY unsigned short dbr_size[LAST_BUFFER_TYPE+1];
+16
View File
@@ -13,3 +13,19 @@ o detect name conflicts at boot time
o multi priority connections (quality of service)
o reduce protocol overhead
o compressed protocol
o If there is a beacon anomaly then this indicates that
the server is _not_ available. Perhaps we should only
reset the search timer interval when we see a beacon
anomaly transition into a sure steady beacon.
o make certain that a monitor callback canceling itself
does not deadlock.
o the free list library does not now cause exceptions to
occur (it uses new ( nothrow )), and therefore we should
change the new handlers to be nothrow also if this is
the design goal.
o test the library when an IOC is running low on memory.
+2 -2
View File
@@ -32,7 +32,7 @@ getCallback::~getCallback ()
}
void getCallback::completion (
unsigned type, unsigned long count, const void *pData )
unsigned type, arrayElementCount count, const void *pData )
{
struct event_handler_args args;
args.usr = this->pPrivate;
@@ -47,7 +47,7 @@ void getCallback::completion (
void getCallback::exception (
int status, const char * /* pContext */,
unsigned type, unsigned long count )
unsigned type, arrayElementCount count )
{
struct event_handler_args args;
args.usr = this->pPrivate;
+7 -7
View File
@@ -24,9 +24,9 @@
tsFreeList < class getCopy, 1024 > getCopy::freeList;
epicsMutex getCopy::freeListMutex;
getCopy::getCopy ( oldCAC &cacCtxIn, unsigned typeIn,
unsigned long countIn, void *pValueIn ) :
count ( countIn ), cacCtx ( cacCtxIn ), pValue ( pValueIn ),
getCopy::getCopy ( oldCAC &cacCtxIn, oldChannelNotify &chanIn, unsigned typeIn,
arrayElementCount countIn, void *pValueIn ) :
count ( countIn ), cacCtx ( cacCtxIn ), chan ( chanIn ), pValue ( pValueIn ),
readSeq ( cacCtxIn.sequenceNumberOfOutstandingIO () ), type ( typeIn )
{
cacCtxIn.incrementOutstandingIO ();
@@ -37,7 +37,7 @@ getCopy::~getCopy ()
}
void getCopy::completion ( unsigned typeIn,
unsigned long countIn, const void *pDataIn )
arrayElementCount countIn, const void *pDataIn )
{
if ( this->type == typeIn ) {
memcpy ( this->pValue, pDataIn, dbr_size_n ( typeIn, countIn ) );
@@ -52,10 +52,10 @@ void getCopy::completion ( unsigned typeIn,
}
void getCopy::exception (
int status, const char *pContext, unsigned typeIn, unsigned long countIn )
int status, const char *pContext, unsigned typeIn, arrayElementCount countIn )
{
this->cacCtx.exception ( status, pContext, typeIn,
countIn, __FILE__, __LINE__ );
this->cacCtx.exception ( status, pContext,
__FILE__, __LINE__, this->chan, this->type, this->count, CA_OP_GET );
delete this;
}
+6
View File
@@ -23,6 +23,7 @@ public:
resTableIndex hash ( unsigned nBitsHashIndex ) const;
static unsigned maxIndexBitWidth ();
static unsigned minIndexBitWidth ();
void name ( char *pBuf, unsigned bufSize ) const;
private:
const struct sockaddr_in addr;
};
@@ -60,6 +61,11 @@ inline unsigned inetAddrID::minIndexBitWidth ()
return 8u;
}
inline void inetAddrID::name ( char *pBuf, unsigned bufSize ) const
{
ipAddrToDottedIP ( &this->addr, pBuf, bufSize );
}
#endif // ifdef inetAddrID
+1 -13
View File
@@ -22,7 +22,7 @@
#define NO_PLACEMENT_DELETE
#ifdef DEBUG
# define debugPrintf(argsInParen) printf argsInParen
# define debugPrintf(argsInParen) ::printf argsInParen
#else
# define debugPrintf(argsInParen)
#endif
@@ -38,18 +38,6 @@
#define MSEC_PER_SEC 1000L
#define USEC_PER_SEC 1000000L
/*
* these control the duration and period of name resolution
* broadcasts
*/
#define MAXCONNTRIES 100 /* N conn retries on unchanged net */
#define INITIALTRIESPERFRAME 1u /* initial UDP frames per search try */
#define MAXTRIESPERFRAME 64u /* max UDP frames per search try */
#define CA_RECAST_DELAY 0.5 /* initial delay to next search (sec) */
#define CA_RECAST_PORT_MASK 0xff /* additional random search interval from port */
#define CA_RECAST_PERIOD 5.0 /* quiescent search period (sec) */
#if defined (CLOCKS_PER_SEC)
# define CAC_SIGNIFICANT_SELECT_DELAY ( 1.0 / CLOCKS_PER_SEC )
+21 -11
View File
@@ -81,7 +81,7 @@ nciu::~nciu ()
}
void nciu::connect ( unsigned nativeType,
unsigned long nativeCount, unsigned sidIn )
unsigned nativeCount, unsigned sidIn )
{
bool v41Ok;
@@ -99,6 +99,12 @@ void nciu::connect ( unsigned nativeType,
return;
}
if ( ! dbf_type_is_valid ( nativeType ) ) {
this->cacCtx.printf (
"CAC: Ignored conn resp with bad native data type CID=%u SID=%u?\n",
this->getId (), sidIn );
return;
}
if ( ! this->f_connectTimeOutSeen && ! this->f_previousConn ) {
if ( this->f_firstConnectDecrementsOutstandingIO ) {
@@ -112,7 +118,7 @@ void nciu::connect ( unsigned nativeType,
else {
v41Ok = false;
}
this->typeCode = nativeType;
this->typeCode = static_cast < unsigned short > ( nativeType );
this->count = nativeCount;
this->sid = sidIn;
this->f_connected = true;
@@ -131,6 +137,11 @@ void nciu::connect ( unsigned nativeType,
// resubscribe for monitors from this channel
this->cacCtx.connectAllIO ( *this );
static bool once = 0;
if ( ! once ) {
printf ( "there is a problem here where we are calling through a defunct vf table\n" );
once = 1;
}
this->notify().connectNotify ();
/*
@@ -189,7 +200,7 @@ bool nciu::searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisCh
msg.m_cmmd = htons ( CA_PROTO_SEARCH );
msg.m_available = this->getId ();
msg.m_dataType = htons ( DONTREPLY );
msg.m_count = htons ( CA_MINOR_VERSION );
msg.m_count = htons ( CA_MINOR_PROTOCOL_REVISION );
msg.m_cid = this->getId ();
success = this->piiu->pushDatagramMsg ( msg,
@@ -199,7 +210,7 @@ bool nciu::searchMsg ( unsigned short retrySeqNumber, unsigned &retryNoForThisCh
// increment the number of times we have tried
// to find this channel
//
if ( this->retry < MAXCONNTRIES ) {
if ( this->retry < UINT_MAX ) {
this->retry++;
}
this->retrySeqNo = retrySeqNumber;
@@ -226,7 +237,7 @@ void nciu::createChannelRequest ()
this->f_claimSent = true;
}
cacChannel::ioStatus nciu::read ( unsigned type, unsigned long countIn,
cacChannel::ioStatus nciu::read ( unsigned type, arrayElementCount countIn,
cacReadNotify &notify, ioid *pId )
{
//
@@ -270,7 +281,7 @@ void nciu::stringVerify ( const char *pStr, const unsigned count )
}
void nciu::write ( unsigned type,
unsigned long countIn, const void *pValue )
arrayElementCount countIn, const void *pValue )
{
if ( ! this->accessRightState.writePermit() ) {
throw noWriteAccess();
@@ -287,7 +298,7 @@ void nciu::write ( unsigned type,
this->cacCtx.writeRequest ( *this, type, countIn, pValue );
}
cacChannel::ioStatus nciu::write ( unsigned type, unsigned long countIn,
cacChannel::ioStatus nciu::write ( unsigned type, arrayElementCount countIn,
const void *pValue, cacWriteNotify &notify, ioid *pId )
{
if ( ! this->accessRightState.writePermit() ) {
@@ -309,7 +320,7 @@ cacChannel::ioStatus nciu::write ( unsigned type, unsigned long countIn,
return cacChannel::iosAsynch;
}
void nciu::subscribe ( unsigned type, unsigned long nElem,
void nciu::subscribe ( unsigned type, arrayElementCount nElem,
unsigned mask, cacStateNotify &notify, ioid *pId )
{
if ( INVALID_DB_REQ(type) ) {
@@ -380,10 +391,10 @@ short nciu::nativeType () const
return type;
}
unsigned long nciu::nativeElementCount () const
arrayElementCount nciu::nativeElementCount () const
{
epicsAutoMutex locker ( this->cacCtx.mutexRef() );
unsigned long countOut;
arrayElementCount countOut;
if ( this->f_connected ) {
countOut = this->count;
}
@@ -471,4 +482,3 @@ void nciu::show ( unsigned level ) const
+19 -11
View File
@@ -23,6 +23,7 @@
#include "tsFreeList.h"
#include "epicsMutex.h"
#define CA_MINOR_PROTOCOL_REVISION 9
#include "caProto.h"
#define epicsExportSharedSymbols
@@ -44,7 +45,7 @@ public:
nciu ( cac &, netiiu &,
cacChannelNotify &, const char *pNameIn );
void connect ( unsigned nativeType,
unsigned long nativeCount, unsigned sid );
unsigned nativeCount, unsigned sid );
void connect ();
void disconnect ( netiiu &newiiu );
bool searchMsg ( unsigned short retrySeqNumber,
@@ -61,15 +62,16 @@ public:
netiiu * getPIIU ();
cac & getClient ();
void searchReplySetUp ( netiiu &iiu, unsigned sidIn,
unsigned typeIn, unsigned long countIn );
ca_uint16_t typeIn, arrayElementCount countIn );
void show ( unsigned level ) const;
void connectTimeoutNotify ();
const char *pName () const;
unsigned nameLen () const;
const char * pHostName () const; // deprecated - please do not use
unsigned long nativeElementCount () const;
arrayElementCount nativeElementCount () const;
bool connected () const;
bool previouslyConnected () const;
void writeException ( int status, const char *pContext, unsigned type, arrayElementCount count );
protected:
~nciu (); // force pool allocation
private:
@@ -80,22 +82,22 @@ private:
netiiu *piiu;
ca_uint32_t sid; // server id
unsigned retry; // search retry number
unsigned short retrySeqNo; // search retry seq number
unsigned short nameLength; // channel name length
unsigned short typeCode;
ca_uint16_t retrySeqNo; // search retry seq number
ca_uint16_t nameLength; // channel name length
ca_uint16_t typeCode;
unsigned f_connected:1;
unsigned f_previousConn:1; // T if connected in the past
unsigned f_claimSent:1;
unsigned f_firstConnectDecrementsOutstandingIO:1;
unsigned f_connectTimeOutSeen:1;
void initiateConnect ();
ioStatus read ( unsigned type, unsigned long count,
ioStatus read ( unsigned type, arrayElementCount count,
cacReadNotify &, ioid * );
void write ( unsigned type, unsigned long count,
void write ( unsigned type, arrayElementCount count,
const void *pValue );
ioStatus write ( unsigned type, unsigned long count,
ioStatus write ( unsigned type, arrayElementCount count,
const void *pValue, cacWriteNotify &, ioid * );
void subscribe ( unsigned type, unsigned long nElem,
void subscribe ( unsigned type, arrayElementCount nElem,
unsigned mask, cacStateNotify &notify, ioid * );
void ioCancel ( const ioid & );
void ioShow ( const ioid &, unsigned level ) const;
@@ -161,7 +163,7 @@ inline void nciu::connect ()
}
inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn,
unsigned typeIn, unsigned long countIn )
ca_uint16_t typeIn, arrayElementCount countIn )
{
this->piiu = &iiu;
this->typeCode = typeIn;
@@ -194,4 +196,10 @@ inline void nciu::connectTimeoutNotify ()
this->f_connectTimeOutSeen = true;
}
inline void nciu::writeException ( int status,
const char *pContext, unsigned type, arrayElementCount count )
{
this->notify().writeException ( status, pContext, type, count );
}
#endif // ifdef nciuh
+25 -21
View File
@@ -27,11 +27,13 @@ public:
virtual class netSubscription * isSubscription ();
virtual void destroy ( class cacRecycle & ) = 0; // only called by cac
virtual void completion () = 0;
virtual void exception ( int status, const char *pContext ) = 0;
virtual void completion ( unsigned type,
unsigned long count, const void *pData ) = 0;
virtual void exception ( int status,
const char *pContext, unsigned type, unsigned long count ) = 0;
const char *pContext ) = 0;
virtual void exception ( int status,
const char *pContext, unsigned type,
arrayElementCount count ) = 0;
virtual void completion ( unsigned type,
arrayElementCount count, const void *pData ) = 0;
void show ( unsigned level ) const;
ca_uint32_t getID () const;
nciu & channel () const;
@@ -48,27 +50,29 @@ class netSubscription : public baseNMIU {
public:
static netSubscription * factory (
tsFreeList < class netSubscription, 1024 > &,
nciu &chan, unsigned type, unsigned long count,
nciu &chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &notify );
void show ( unsigned level ) const;
unsigned long getCount () const;
arrayElementCount getCount () const;
unsigned getType () const;
unsigned getMask () const;
void destroy ( class cacRecycle & );
void completion ();
void exception ( int status, const char *pContext );
void completion ( unsigned type,
unsigned long count, const void *pData );
void exception ( int status,
const char *pContext, unsigned type, unsigned long count );
const char *pContext );
void completion ( unsigned type,
arrayElementCount count, const void *pData );
void exception ( int status,
const char *pContext, unsigned type,
arrayElementCount count );
protected:
~netSubscription ();
private:
const unsigned long count;
const arrayElementCount count;
cacStateNotify &notify;
const unsigned type;
const unsigned mask;
netSubscription ( nciu &chan, unsigned type, unsigned long count,
netSubscription ( nciu &chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &notify );
class netSubscription * isSubscription ();
void * operator new ( size_t,
@@ -89,9 +93,9 @@ public:
void completion ();
void exception ( int status, const char *pContext );
void completion ( unsigned type,
unsigned long count, const void *pData );
void exception ( int status,
const char *pContext, unsigned type, unsigned long count );
arrayElementCount count, const void *pData );
void exception ( int status, const char *pContext,
unsigned type, arrayElementCount count );
protected:
~netReadNotifyIO ();
private:
@@ -115,9 +119,9 @@ public:
void completion ();
void exception ( int status, const char *pContext );
void completion ( unsigned type,
unsigned long count, const void *pData );
void exception ( int status,
const char *pContext, unsigned type, unsigned long count );
arrayElementCount count, const void *pData );
void exception ( int status, const char *pContext,
unsigned type, arrayElementCount count );
protected:
~netWriteNotifyIO ();
private:
@@ -143,7 +147,7 @@ inline class nciu & baseNMIU::channel () const
inline netSubscription * netSubscription::factory (
tsFreeList < class netSubscription, 1024 > &freeList,
nciu &chan, unsigned type, unsigned long count,
nciu &chan, unsigned type, arrayElementCount count,
unsigned mask, cacStateNotify &notify )
{
return new ( freeList ) netSubscription ( chan, type,
@@ -169,9 +173,9 @@ inline void netSubscription::operator delete ( void *pCadaver, size_t size,
}
#endif
inline unsigned long netSubscription::getCount () const
inline arrayElementCount netSubscription::getCount () const
{
unsigned long nativeCount = this->chan.nativeElementCount ();
arrayElementCount nativeCount = this->chan.nativeElementCount ();
if ( this->count == 0u || this->count > nativeCount ) {
return nativeCount;
}
+9 -9
View File
@@ -48,20 +48,20 @@ void netReadNotifyIO::completion ()
void netReadNotifyIO::exception ( int status, const char *pContext )
{
this->notify.exception ( status, pContext, UINT_MAX, 0 );
this->notify.exception ( status, pContext, UINT_MAX, 0u );
}
void netReadNotifyIO::completion ( unsigned type,
unsigned long count, const void *pData )
{
this->notify.completion ( type, count, pData );
}
void netReadNotifyIO::exception ( int status,
const char *pContext, unsigned type, unsigned long count )
void netReadNotifyIO::exception ( int status, const char *pContext,
unsigned type, arrayElementCount count )
{
this->notify.exception ( status, pContext, type, count );
}
void netReadNotifyIO::completion ( unsigned type,
arrayElementCount count, const void *pData )
{
this->notify.completion ( type, count, pData );
}
+14 -7
View File
@@ -22,11 +22,17 @@
#undef epicsExportSharedSymbols
netSubscription::netSubscription ( nciu &chan,
unsigned typeIn, unsigned long countIn,
unsigned typeIn, arrayElementCount countIn,
unsigned maskIn, cacStateNotify &notifyIn ) :
baseNMIU ( chan ), count ( countIn ),
notify ( notifyIn ), type ( typeIn ), mask ( maskIn )
{
if ( ! dbr_type_is_valid ( typeIn ) ) {
throw cacChannel::badType ();
}
if ( this->mask == 0u ) {
throw cacChannel::badEventSelection ();
}
}
netSubscription::~netSubscription ()
@@ -65,16 +71,17 @@ void netSubscription::exception ( int status, const char *pContext )
this->notify.exception ( status, pContext, UINT_MAX, 0 );
}
void netSubscription::exception ( int status, const char *pContext,
unsigned type, arrayElementCount count )
{
this->notify.exception ( status, pContext, type, count );
}
void netSubscription::completion ( unsigned typeIn,
unsigned long countIn, const void *pDataIn )
arrayElementCount countIn, const void *pDataIn )
{
this->notify.current ( typeIn, countIn, pDataIn );
}
void netSubscription::exception ( int status,
const char *pContext, unsigned typeIn, unsigned long countIn )
{
this->notify.exception ( status, pContext, typeIn, countIn );
}
+9 -8
View File
@@ -48,21 +48,22 @@ void netWriteNotifyIO::completion ()
void netWriteNotifyIO::exception ( int status, const char *pContext )
{
this->notify.exception ( status, pContext );
this->notify.exception ( status, pContext, UINT_MAX, 0u );
}
void netWriteNotifyIO::exception ( int status, const char *pContext,
unsigned type, arrayElementCount count )
{
this->notify.exception ( status, pContext, type, count );
}
void netWriteNotifyIO::completion ( unsigned /* type */,
unsigned long /* count */, const void * /* pData */ )
arrayElementCount /* count */, const void * /* pData */ )
{
this->chan.getClient().printf ( "Write response with data ?\n" );
}
void netWriteNotifyIO::exception ( int status,
const char *pContext, unsigned /* type */, unsigned long /* count */ )
{
this->notify.exception ( status, pContext );
}
+1 -1
View File
@@ -67,7 +67,7 @@ extern "C" {
* net format: big endian and IEEE float
*/
typedef void CACVRTFUNC (const void *pSrc, void *pDest, int hton, unsigned long count);
typedef void CACVRTFUNC (const void *pSrc, void *pDest, int hton, arrayElementCount count);
#ifdef CONVERSION_REQUIRED
/* cvrt is (array of) (pointer to) (function returning) int */
+49 -34
View File
@@ -44,24 +44,24 @@ public:
void show ( unsigned level ) const;
void initiateConnect ();
void read (
unsigned type, unsigned long count,
unsigned type, arrayElementCount count,
cacReadNotify &notify, cacChannel::ioid *pId = 0 );
void read (
unsigned type, unsigned long count,
unsigned type, arrayElementCount count,
void *pValue );
void write (
unsigned type, unsigned long count,
unsigned type, arrayElementCount count,
const void *pValue );
void write (
unsigned type, unsigned long count, const void *pValue,
unsigned type, arrayElementCount count, const void *pValue,
cacWriteNotify &, cacChannel::ioid *pId = 0 );
void subscribe (
unsigned type, unsigned long count, unsigned mask,
unsigned type, arrayElementCount count, unsigned mask,
cacStateNotify &, cacChannel::ioid & );
void ioCancel ( const cacChannel::ioid & );
void ioShow ( const cacChannel::ioid &, unsigned level ) const;
short nativeType () const;
unsigned long nativeElementCount () const;
arrayElementCount nativeElementCount () const;
caAccessRights accessRights () const; // defaults to unrestricted access
unsigned searchAttempts () const; // defaults to zero
double beaconPeriod () const; // defaults to negative DBL_MAX
@@ -81,6 +81,10 @@ private:
void disconnectNotify ();
void accessRightsNotify ( const caAccessRights & );
void exception ( int status, const char *pContext );
void readException ( int status, const char *pContext,
unsigned type, arrayElementCount count, void *pValue );
void writeException ( int status, const char *pContext,
unsigned type, arrayElementCount count );
bool includeFirstConnectInCountOfOutstandingIO () const;
static tsFreeList < struct oldChannelNotify, 1024 > freeList;
static epicsMutex freeListMutex;
@@ -88,8 +92,8 @@ private:
class getCopy : public cacReadNotify {
public:
getCopy ( oldCAC &cacCtx, unsigned type,
unsigned long count, void *pValue );
getCopy ( oldCAC &cacCtx, oldChannelNotify &, unsigned type,
arrayElementCount count, void *pValue );
void destroy ();
void show ( unsigned level ) const;
void * operator new ( size_t size );
@@ -97,15 +101,16 @@ public:
protected:
~getCopy (); // allocate only out of pool
private:
unsigned long count;
arrayElementCount count;
oldCAC &cacCtx;
oldChannelNotify &chan;
void *pValue;
unsigned readSeq;
unsigned type;
void completion (
unsigned type, unsigned long count, const void *pData);
void exception (
int status, const char *pContext, unsigned type, unsigned long count );
unsigned type, arrayElementCount count, const void *pData);
void exception ( int status,
const char *pContext, unsigned type, arrayElementCount count );
static tsFreeList < class getCopy, 1024 > freeList;
static epicsMutex freeListMutex;
};
@@ -124,9 +129,9 @@ private:
caEventCallBackFunc *pFunc;
void *pPrivate;
void completion (
unsigned type, unsigned long count, const void *pData);
void exception (
int status, const char *pContext, unsigned type, unsigned long count );
unsigned type, arrayElementCount count, const void *pData);
void exception ( int status,
const char *pContext, unsigned type, arrayElementCount count );
static tsFreeList < class getCallback, 1024 > freeList;
static epicsMutex freeListMutex;
};
@@ -145,8 +150,8 @@ private:
caEventCallBackFunc *pFunc;
void *pPrivate;
void completion ();
void exception (
int status, const char *pContext );
void exception ( int status, const char *pContext,
unsigned type, arrayElementCount count );
static tsFreeList < class putCallback, 1024 > freeList;
static epicsMutex freeListMutex;
};
@@ -155,7 +160,7 @@ struct oldSubscription : public cacStateNotify {
public:
oldSubscription (
oldChannelNotify &,
unsigned type, unsigned long nElem, unsigned mask,
unsigned type, arrayElementCount nElem, unsigned mask,
caEventCallBackFunc *pFunc, void *pPrivate );
bool ioAttachOK ();
void destroy ();
@@ -171,9 +176,9 @@ private:
void *pPrivate;
bool subscribed;
void current (
unsigned type, unsigned long count, const void *pData );
void exception (
int status, const char *pContext, unsigned type, unsigned long count );
unsigned type, arrayElementCount count, const void *pData );
void exception ( int status,
const char *pContext, unsigned type, arrayElementCount count );
static tsFreeList < struct oldSubscription, 1024 > freeList;
static epicsMutex freeListMutex;
};
@@ -197,22 +202,24 @@ public:
unsigned sequenceNumberOfOutstandingIO () const;
void incrementOutstandingIO ();
void decrementOutstandingIO ( unsigned sequenceNo );
void exception ( int status, const char *pContext,
void exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo );
void exception ( int status, const char *pContext,
unsigned type, unsigned long count,
const char *pFileName, unsigned lineNo );
// perhaps these should be eliminated in deference to the exception mechanism
int printf ( const char *pformat, ... );
int vPrintf ( const char *pformat, va_list args );
const char *pFileName, unsigned lineNo, oldChannelNotify &chan,
unsigned type, arrayElementCount count, unsigned op );
CASG * lookupCASG ( unsigned id );
void installCASG ( CASG & );
void uninstallCASG ( CASG & );
void enableCallbackPreemption ();
void disableCallbackPreemption ();
// perhaps these should be eliminated in deference to the exception mechanism
int printf ( const char *pformat, ... ) const;
int vPrintf ( const char *pformat, va_list args ) const;
void vSignal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args );
private:
cac & clientCtx;
mutable epicsMutex mutex;
cac & clientCtx;
caExceptionHandler *ca_exception_func;
void *ca_exception_arg;
caPrintfFunc *pVPrintfFunc;
@@ -221,6 +228,7 @@ private:
// this should probably be phased out (its not OS independent)
void fdWasCreated ( int fd );
void fdWasDestroyed ( int fd );
void attachToClientCtx ();
};
int fetchClientContext ( oldCAC **ppcac );
@@ -250,26 +258,26 @@ inline void oldChannelNotify::initiateConnect ()
this->io.initiateConnect ();
}
inline void oldChannelNotify::read ( unsigned type, unsigned long count,
inline void oldChannelNotify::read ( unsigned type, arrayElementCount count,
cacReadNotify &notify, cacChannel::ioid *pId )
{
this->io.read ( type, count, notify, pId );
}
inline void oldChannelNotify::write ( unsigned type,
unsigned long count, const void *pValue )
arrayElementCount count, const void *pValue )
{
this->io.write ( type, count, pValue );
}
inline void oldChannelNotify::write ( unsigned type, unsigned long count,
inline void oldChannelNotify::write ( unsigned type, arrayElementCount count,
const void *pValue, cacWriteNotify &notify, cacChannel::ioid *pId )
{
this->io.write ( type, count, pValue, notify, pId );
}
inline void oldChannelNotify::subscribe ( unsigned type,
unsigned long count, unsigned mask, cacStateNotify &notify,
arrayElementCount count, unsigned mask, cacStateNotify &notify,
cacChannel::ioid &idOut)
{
this->io.subscribe ( type, count, mask, notify, &idOut );
@@ -290,7 +298,7 @@ inline short oldChannelNotify::nativeType () const
return this->io.nativeType ();
}
inline unsigned long oldChannelNotify::nativeElementCount () const
inline arrayElementCount oldChannelNotify::nativeElementCount () const
{
return this->io.nativeElementCount ();
}
@@ -337,7 +345,7 @@ inline const char * oldChannelNotify::pHostName () const
inline oldSubscription::oldSubscription (
oldChannelNotify &chanIn,
unsigned type, unsigned long nElem, unsigned mask,
unsigned type, arrayElementCount nElem, unsigned mask,
caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
chan ( chanIn ), id ( 0 ), pFunc ( pFuncIn ),
pPrivate ( pPrivateIn ), subscribed ( false )
@@ -497,4 +505,11 @@ inline void oldCAC::disableCallbackPreemption ()
this->clientCtx.disableCallbackPreemption ();
}
inline void oldCAC::vSignal ( int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args )
{
this->clientCtx.vSignal ( ca_status, pfilenm,
lineno, pFormat, args );
}
#endif // ifndef oldAccessh
+70 -36
View File
@@ -14,13 +14,15 @@
* 505 665 1831
*/
#include <stdio.h>
#include "iocinf.h"
#include "oldAccess.h"
oldCAC::oldCAC ( bool enablePreemptiveCallback ) :
clientCtx ( * new cac ( *this, enablePreemptiveCallback ) ),
ca_exception_func ( ca_default_exception_handler ), ca_exception_arg ( 0 ),
ca_exception_func ( 0 ), ca_exception_arg ( 0 ),
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 )
{
if ( ! & this->clientCtx ) {
@@ -36,14 +38,8 @@ oldCAC::~oldCAC ()
void oldCAC::changeExceptionEvent ( caExceptionHandler *pfunc, void *arg )
{
epicsAutoMutex autoMutex ( this->mutex );
if ( pfunc ) {
this->ca_exception_func = pfunc;
this->ca_exception_arg = arg;
}
else {
this->ca_exception_func = ca_default_exception_handler;
this->ca_exception_arg = NULL;
}
this->ca_exception_func = pfunc;
this->ca_exception_arg = arg;
// should block here until releated callback in progress completes
}
@@ -67,8 +63,21 @@ void oldCAC::registerForFileDescriptorCallBack ( CAFDHANDLER *pFunc, void *pArg
// should block here until releated callback in progress completes
}
int oldCAC::printf ( const char *pformat, ... ) const
{
va_list theArgs;
int status;
int oldCAC::vPrintf ( const char *pformat, va_list args )
va_start ( theArgs, pformat );
status = this->oldCAC::vPrintf ( pformat, theArgs );
va_end ( theArgs );
return status;
}
int oldCAC::vPrintf ( const char *pformat, va_list args ) const
{
caPrintfFunc *pFunc;
{
@@ -79,18 +88,12 @@ int oldCAC::vPrintf ( const char *pformat, va_list args )
return ( *pFunc ) ( pformat, args );
}
else {
return vfprintf ( stderr, pformat, args );
return ::vfprintf ( stderr, pformat, args );
}
}
void oldCAC::exception ( int stat, const char *pCtx, const char *pFile, unsigned lineNo )
{
this->exception ( stat, pCtx, UINT_MAX, 0, pFile, lineNo );
}
void oldCAC::exception ( int stat, const char *ctx,
unsigned type, unsigned long count,
const char *pFile, unsigned lineNo )
void oldCAC::exception ( int stat, const char *pCtx,
const char *pFile, unsigned lineNo )
{
struct exception_handler_args args;
caExceptionHandler *pFunc;
@@ -104,17 +107,54 @@ void oldCAC::exception ( int stat, const char *ctx,
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = NULL;
args.type = type;
args.count = count;
args.type = TYPENOTCONN;
args.count = 0;
args.addr = NULL;
args.stat = stat;
args.op = CA_OP_OTHER;
args.ctx = ctx;
args.ctx = pCtx;
args.pFile = pFile;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
}
else {
this->clientCtx.signal ( stat, pFile, lineNo, pCtx );
}
}
void oldCAC::exception ( int status, const char *pContext,
const char *pFileName, unsigned lineNo, oldChannelNotify &chan,
unsigned type, arrayElementCount count, unsigned op )
{
struct exception_handler_args args;
caExceptionHandler *pFunc;
void *pArg;
{
epicsAutoMutex autoMutex ( this->mutex );
pFunc = this->ca_exception_func;
pArg = this->ca_exception_arg;
}
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = &chan;
args.type = type;
args.count = count;
args.addr = NULL;
args.stat = status;
args.op = op;
args.ctx = pContext;
args.pFile = pFileName;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
}
else {
this->clientCtx.signal ( status, pFileName, lineNo,
"op=%u, channel=%s, type=%s, count=lu, ctx=\"%s\"",
op, ca_name ( &chan ), dbr_type_to_text ( type ), count, pContext );
}
}
void oldCAC::fdWasCreated ( int fd )
@@ -145,20 +185,6 @@ void oldCAC::fdWasDestroyed ( int fd )
}
}
int oldCAC::printf ( const char *pformat, ... )
{
va_list theArgs;
int status;
va_start ( theArgs, pformat );
status = this->vPrintf ( pformat, theArgs );
va_end ( theArgs );
return status;
}
void oldCAC::show ( unsigned level ) const
{
::printf ( "oldCAC at %p\n",
@@ -179,3 +205,11 @@ void oldCAC::show ( unsigned level ) const
}
}
void oldCAC::attachToClientCtx ()
{
int status = ca_attach_context ( this );
SEVCHK ( status, "error in virtual attach to client context" );
}
+14
View File
@@ -113,6 +113,20 @@ void oldChannelNotify::exception ( int status, const char *pContext )
ca_signal ( status, pContext );
}
void oldChannelNotify::readException ( int status, const char *pContext,
unsigned type, arrayElementCount count, void *pValue )
{
ca_signal_formated ( status, 0, 0u, "ctx=%s type=%s count=%u ptr=%p",
pContext, dbr_type_to_text ( type ), count, pValue );
}
void oldChannelNotify::writeException ( int status, const char *pContext,
unsigned type, arrayElementCount count )
{
ca_signal_formated ( status, 0, 0u, "ctx=%s type=%s count=%u",
pContext, dbr_type_to_text ( type ), count );
}
bool oldChannelNotify::includeFirstConnectInCountOfOutstandingIO () const
{
return ( this->pConnCallBack == cacNoopConnHandler );
+2 -2
View File
@@ -22,7 +22,7 @@ oldSubscription::~oldSubscription ()
}
void oldSubscription::current (
unsigned type, unsigned long count, const void *pData)
unsigned type, arrayElementCount count, const void *pData)
{
struct event_handler_args args;
@@ -37,7 +37,7 @@ void oldSubscription::current (
void oldSubscription::exception (
int status, const char * /* pContext */,
unsigned type, unsigned long count )
unsigned type, arrayElementCount count )
{
struct event_handler_args args;
+4 -3
View File
@@ -46,14 +46,15 @@ void putCallback::completion ()
}
void putCallback::exception (
int status, const char * /* pContext */ )
int status, const char * /* pContext */,
unsigned type, arrayElementCount count )
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = & this->chan;
args.type = TYPENOTCONN;
args.count = 0;
args.type = type;
args.count = count;
args.status = status;
args.dbr = 0;
( *this->pFunc ) (args);
+2 -2
View File
@@ -47,8 +47,8 @@ recvProcessThread::~recvProcessThread ()
void recvProcessThread::run ()
{
int status = ca_attach_context ( this->pcac );
SEVCHK ( status, "attaching to client context in recv process thread" );
this->pcac->attachToClientCtx ();
while ( ! this->shutDown ) {
{
+3 -3
View File
@@ -22,10 +22,10 @@
#undef epicsExportSharedSymbols
repeaterSubscribeTimer::repeaterSubscribeTimer ( udpiiu &iiuIn, epicsTimerQueue &queueIn ) :
timer ( queueIn.createTimer ( *this ) ), iiu ( iiuIn ),
timer ( queueIn.createTimer () ), iiu ( iiuIn ),
attempts ( 0 ), registered ( false ), once ( false )
{
this->timer.start ( 10.0 );
this->timer.start ( *this, 10.0 );
}
repeaterSubscribeTimer::~repeaterSubscribeTimer ()
@@ -33,7 +33,7 @@ repeaterSubscribeTimer::~repeaterSubscribeTimer ()
delete & this->timer;
}
epicsTimerNotify::expireStatus repeaterSubscribeTimer::expire ()
epicsTimerNotify::expireStatus repeaterSubscribeTimer::expire ( const epicsTime & currentTime )
{
static const unsigned nTriesToMsg = 50;
if ( this->attempts > nTriesToMsg && ! this->once ) {
+1 -1
View File
@@ -34,7 +34,7 @@ private:
unsigned attempts;
bool registered;
bool once;
expireStatus expire ();
expireStatus expire ( const epicsTime & currentTime );
};
#endif // ifdef repeaterSubscribeTimerh
+144 -66
View File
@@ -23,22 +23,35 @@
#include "udpiiu.h"
#undef epicsExportSharedSymbols
static const unsigned maxSearchTries = 100u; // max tries on unchanged net
static const unsigned initialTriesPerFrame = 1u; // initial UDP frames per search try
static const unsigned maxTriesPerFrame = 64u; // max UDP frames per search try
static const double initialRoundTripEstimate = 0.250; // seconds
static const double minSearchPeriod = 0.030; // seconds
static const double maxSearchPeriod = 5.0; // seconds
//
// searchTimer::searchTimer ()
//
searchTimer::searchTimer ( udpiiu &iiuIn, epicsTimerQueue &queueIn, epicsMutex &mutexIn ) :
timer ( queueIn.createTimer ( *this ) ),
period ( initialRoundTripEstimate * 2.0 ),
roundTripDelayEstimate ( initialRoundTripEstimate ),
timer ( queueIn.createTimer () ),
mutex ( mutexIn ),
iiu ( iiuIn ),
framesPerTry ( INITIALTRIESPERFRAME ),
framesPerTry ( initialTriesPerFrame ),
framesPerTryCongestThresh ( UINT_MAX ),
minRetry ( UINT_MAX ),
retry ( 0u ),
searchTriesWithinThisPass ( 0u ),
searchResponsesWithinThisPass ( 0u ),
searchAttempts ( 0u ),
searchResponses ( 0u ),
searchAttemptsThisPass ( 0u ),
searchResponsesThisPass ( 0u ),
retrySeqNo ( 0u ),
retrySeqAtPassBegin ( 0u ),
period ( CA_RECAST_DELAY )
active ( false ),
noDelay ( false )
{
}
@@ -52,59 +65,68 @@ searchTimer::~searchTimer ()
//
void searchTimer::resetPeriod ( double delayToNextTry )
{
bool reschedule;
if ( delayToNextTry < CA_RECAST_DELAY ) {
delayToNextTry = CA_RECAST_DELAY;
}
{
epicsAutoMutex locker ( this->mutex );
this->retry = 0;
if ( this->period > delayToNextTry ) {
reschedule = true;
bool start;
delayToNextTry += initialRoundTripEstimate;
this->retry = 0;
if ( this->iiu.channelCount () > 0 ) {
if ( this->period > delayToNextTry || ! this->active ) {
this->active = true;
this->noDelay = delayToNextTry == 0.0;
start = true;
}
else {
reschedule = false;
start = false;
}
this->period = CA_RECAST_DELAY;
}
if ( reschedule ) {
this->timer.start ( delayToNextTry );
debugPrintf ( ("rescheduled search timer for completion in %f sec\n", delayToNextTry) );
}
else {
this->timer.start ( delayToNextTry );
debugPrintf ( ("if inactive, search timer started to completion in %f sec\n", delayToNextTry) );
start = false;
}
// upper bound
//this->period = initialRoundTripEstimate * 2.0;
double newPeriod = this->roundTripDelayEstimate * 2.0;
if ( newPeriod <= initialRoundTripEstimate * 2.0 ) {
this->period = newPeriod;
}
else {
this->period = initialRoundTripEstimate * 2.0;
}
// lower bound
if ( this->period < minSearchPeriod ) {
this->period = minSearchPeriod;
}
if ( start ) {
epicsAutoMutexRelease autoRelease ( this->mutex );
this->timer.start ( *this, delayToNextTry );
// debugPrintf ( ("rescheduled search timer for completion in %f sec\n", delayToNextTry) );
}
}
/*
* searchTimer::setRetryInterval ()
*/
void searchTimer::setRetryInterval (unsigned retryNo)
void searchTimer::setRetryInterval ( unsigned retryNo )
{
unsigned idelay;
double delay;
epicsAutoMutex locker ( this->mutex );
/*
* set the retry number
*/
this->retry = tsMin ( retryNo, MAXCONNTRIES + 1u );
this->retry = tsMin ( retryNo, maxSearchTries + 1u );
/*
* set the retry interval
*/
idelay = 1u << tsMin ( static_cast < size_t > ( this->retry ),
CHAR_BIT * sizeof ( idelay ) - 1u );
delay = idelay * CA_RECAST_DELAY; /* sec */
/*
* place upper limit on the retry delay
*/
this->period = tsMin ( CA_RECAST_PERIOD, delay );
delay = idelay * this->roundTripDelayEstimate * 2.0; /* sec */
//delay = idelay * initialRoundTripEstimate * 2.0; /* sec */
this->period = tsMin ( maxSearchPeriod, delay );
this->period = tsMax ( minSearchPeriod, this->period );
debugPrintf ( ("new CA search period is %f sec\n", this->period) );
}
@@ -116,31 +138,55 @@ void searchTimer::setRetryInterval (unsigned retryNo)
// at least one response. However, dont reset this delay if we
// get a delayed response to an old search request.
//
void searchTimer::notifySearchResponse ( unsigned short retrySeqNoIn )
void searchTimer::notifySearchResponse ( unsigned short retrySeqNoIn,
const epicsTime & currentTime )
{
bool reschedualNeeded;
{
epicsAutoMutex locker ( this->mutex );
if ( this->retrySeqAtPassBegin <= retrySeqNoIn ) {
if ( this->searchResponses < UINT_MAX ) {
this->searchResponses++;
}
}
if ( this->retrySeqAtPassBegin <= retrySeqNoIn ) {
if ( this->searchResponsesWithinThisPass < UINT_MAX ) {
this->searchResponsesWithinThisPass++;
}
}
if ( retrySeqNoIn == this->retrySeqNo && ! this->noDelay ) {
double curRTT = currentTime - this->timeAtLastRetry;
this->roundTripDelayEstimate =
( this->roundTripDelayEstimate + curRTT ) / 2.0;
this->period = this->roundTripDelayEstimate * 2.0;
this->period = tsMin ( maxSearchPeriod, this->period );
this->period = tsMax ( minSearchPeriod, this->period );
reschedualNeeded = true;
this->active = true;
this->noDelay = true;
}
reschedualNeeded = ( retrySeqNoIn == this->retrySeqNo );
if ( this->searchResponses == this->searchAttempts ) {
reschedualNeeded = true;
this->active = true;
this->noDelay = true;
}
else {
reschedualNeeded = false;
}
if ( reschedualNeeded ) {
this->timer.start ( 0.0 );
epicsAutoMutexRelease autoRelease (this->mutex );
# if defined(DEBUG) && 0
char buf[64];
epicsTime ts = epicsTime::getCurrent();
ts.strftime ( buf, sizeof(buf), "%M:%S.%09f");
# endif
// debugPrintf ( ( "Response set timer delay to zero. ts=%s, RTT=%f sec\n",
// buf, this->roundTripDelayEstimate ) );
this->timer.start ( *this, currentTime );
}
}
//
// searchTimer::expire ()
//
epicsTimerNotify::expireStatus searchTimer::expire ()
epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTime )
{
epicsAutoMutex locker ( this->mutex );
unsigned nFrameSent = 0u;
@@ -150,6 +196,9 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
* check to see if there is nothing to do here
*/
if ( this->iiu.channelCount () == 0 ) {
this->active = false;
this->noDelay = false;
debugPrintf ( ( "all channels located - search timer terminating\n" ) );
return noRestart;
}
@@ -157,6 +206,7 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
* increment the retry sequence number
*/
this->retrySeqNo++; /* allowed to roll over */
this->timeAtLastRetry = currentTime;
/*
* dynamically adjust the number of UDP frames per
@@ -185,12 +235,12 @@ epicsTimerNotify::expireStatus 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->searchResponsesWithinThisPass >
(this->searchTriesWithinThisPass-(this->searchTriesWithinThisPass/16u)) ) {
if ( this->searchResponses >
( this->searchAttempts - (this->searchAttempts/16u) ) ) {
/*
* increase UDP frames per try if we have a good score
*/
if ( this->framesPerTry < MAXTRIESPERFRAME ) {
if ( this->framesPerTry < maxTriesPerFrame ) {
/*
* a congestion avoidance threshold similar to TCP is now used
*/
@@ -201,24 +251,38 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
this->framesPerTry += (this->framesPerTry/8) + 1;
}
debugPrintf ( ("Increasing frame count to %u t=%u r=%u\n",
this->framesPerTry, this->searchTriesWithinThisPass, this->searchResponsesWithinThisPass) );
this->framesPerTry, this->searchAttempts, this->searchResponses) );
}
}
/*
* if we detect congestion because we have less than a 87.5% success
* rate then gradually reduce the frames per try
*/
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->searchTriesWithinThisPass,
this->searchResponsesWithinThisPass) );
else if ( this->searchResponses <
( this->searchAttempts - (this->searchAttempts/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->searchAttempts, this->searchResponses) );
}
if ( this->searchAttemptsThisPass <= UINT_MAX - this->searchAttempts ) {
this->searchAttemptsThisPass += this->searchAttempts;
}
else {
this->searchAttemptsThisPass = UINT_MAX;
}
if ( this->searchResponsesThisPass <= UINT_MAX - this->searchResponses ) {
this->searchResponsesThisPass += this->searchResponses;
}
else {
this->searchResponsesThisPass = UINT_MAX;
}
this->searchAttempts = 0;
this->searchResponses = 0;
while ( 1 ) {
/*
@@ -228,8 +292,8 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
* dont increase the delay between search
* requests
*/
if ( this->searchTriesWithinThisPass >= this->iiu.channelCount () ) {
if ( this->searchResponsesWithinThisPass == 0u ) {
if ( this->searchAttemptsThisPass >= this->iiu.channelCount () ) {
if ( this->searchResponsesThisPass == 0u ) {
debugPrintf ( ("increasing search try interval\n") );
this->setRetryInterval ( this->minRetry + 1u );
}
@@ -250,8 +314,8 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
*/
this->retrySeqAtPassBegin = this->retrySeqNo;
this->searchTriesWithinThisPass = 0;
this->searchResponsesWithinThisPass = 0;
this->searchAttemptsThisPass = 0;
this->searchResponsesThisPass = 0;
debugPrintf ( ("saw end of list\n") );
}
@@ -275,8 +339,8 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
this->minRetry = retryNoForThisChannel;
}
if ( this->searchTriesWithinThisPass < UINT_MAX ) {
this->searchTriesWithinThisPass++;
if ( this->searchAttempts < UINT_MAX ) {
this->searchAttempts++;
}
if ( nChanSent < UINT_MAX ) {
nChanSent++;
@@ -308,15 +372,29 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
// flush out the search request buffer
this->iiu.datagramFlush ();
debugPrintf ( ("sent %u delay sec=%f\n", nFrameSent, this->period) );
# ifdef DEBUG
char buf[64];
epicsTime ts = epicsTime::getCurrent();
ts.strftime ( buf, sizeof(buf), "%M:%S.%09f");
debugPrintf ( ("sent %u delay sec=%f RTT=%f ts=%s\n",
nFrameSent, this->period,
this->roundTripDelayEstimate, buf ) );
# endif
if ( this->iiu.channelCount () == 0 ) {
debugPrintf ( ( "all channels connected\n" ) );
this->active = false;
this->noDelay = false;
return noRestart;
}
else if ( this->retry < MAXCONNTRIES ) {
else if ( this->retry < maxSearchTries ) {
this->noDelay = this->period == 0.0;
return expireStatus ( restart, this->period );
}
else {
debugPrintf ( ( "maximum search tries exceeded - giving up\n" ) );
this->active = false;
this->noDelay = false;
return noRestart;
}
}
+12 -6
View File
@@ -27,10 +27,13 @@ class searchTimer : private epicsTimerNotify {
public:
searchTimer ( udpiiu &iiu, epicsTimerQueue &queue, epicsMutex & );
virtual ~searchTimer ();
void notifySearchResponse ( unsigned short retrySeqNo );
void notifySearchResponse ( unsigned short retrySeqNo, const epicsTime & currentTime );
void resetPeriod ( double delayToNextTry );
void show ( unsigned level ) const;
private:
epicsTime timeAtLastRetry;
double period; /* period between tries */
double roundTripDelayEstimate;
epicsTimer &timer;
epicsMutex &mutex;
udpiiu &iiu;
@@ -38,13 +41,16 @@ private:
unsigned framesPerTryCongestThresh; /* one half N tries w congest */
unsigned minRetry; /* min retry number so far */
unsigned retry;
unsigned searchTriesWithinThisPass; /* num search tries within this pass through the list */
unsigned searchResponsesWithinThisPass; /* num search resp within this pass through the list */
unsigned searchAttempts; /* num search tries within this timer experation */
unsigned searchResponses; /* num search resp within this timer experation */
unsigned searchAttemptsThisPass; /* num search tries within this pass */
unsigned searchResponsesThisPass; /* num search resp within this pass */
unsigned short retrySeqNo; /* search retry seq number */
unsigned short retrySeqAtPassBegin; /* search retry seq number at beg of pass through list */
double period; /* period between tries */
expireStatus expire ();
void setRetryInterval (unsigned retryNo);
bool active;
bool noDelay;
expireStatus expire ( const epicsTime & currentTime );
void setRetryInterval ( unsigned retryNo );
};
#endif // ifdef searchTimerh
+9 -9
View File
@@ -58,7 +58,7 @@ public:
static syncGroupReadNotify * factory (
tsFreeList < class syncGroupReadNotify, 128 > &,
struct CASG &, chid, unsigned type,
unsigned long count, void *pValueIn );
arrayElementCount count, void *pValueIn );
void destroy ( casgRecycle & );
void show ( unsigned level ) const;
protected:
@@ -66,7 +66,7 @@ protected:
private:
void *pValue;
syncGroupReadNotify ( struct CASG &sgIn, chid,
unsigned type, unsigned long count, void *pValueIn );
unsigned type, arrayElementCount count, void *pValueIn );
void * operator new ( size_t,
tsFreeList < class syncGroupReadNotify, 128 > & );
# if ! defined ( NO_PLACEMENT_DELETE )
@@ -74,9 +74,9 @@ private:
tsFreeList < class syncGroupReadNotify, 128 > & );
# endif
void completion (
unsigned type, unsigned long count, const void *pData );
unsigned type, arrayElementCount count, const void *pData );
void exception (
int status, const char *pContext, unsigned type, unsigned long count );
int status, const char *pContext, unsigned type, arrayElementCount count );
};
class syncGroupWriteNotify : public syncGroupNotify, public cacWriteNotify {
@@ -84,7 +84,7 @@ public:
static syncGroupWriteNotify * factory (
tsFreeList < class syncGroupWriteNotify, 128 > &,
struct CASG &, chid, unsigned type,
unsigned long count, const void *pValueIn );
arrayElementCount count, const void *pValueIn );
void destroy ( casgRecycle & );
void show ( unsigned level ) const;
protected:
@@ -92,7 +92,7 @@ protected:
private:
void *pValue;
syncGroupWriteNotify ( struct CASG &, chid, unsigned type,
unsigned long count, const void *pValueIn );
arrayElementCount count, const void *pValueIn );
void * operator new ( size_t,
tsFreeList < class syncGroupWriteNotify, 128 > & );
# if ! defined ( NO_PLACEMENT_DELETE )
@@ -100,7 +100,7 @@ private:
tsFreeList < class syncGroupWriteNotify, 128 > & );
# endif
void completion ();
void exception (int status, const char *pContext );
void exception ( int status, const char *pContext, unsigned type, arrayElementCount count );
};
class oldCAC;
@@ -114,8 +114,8 @@ public:
int block ( double timeout );
void reset ();
void show ( unsigned level ) const;
int get ( chid pChan, unsigned type, unsigned long count, void *pValue );
int put ( chid pChan, unsigned type, unsigned long count, const void *pValue );
int get ( chid pChan, unsigned type, arrayElementCount count, void *pValue );
int put ( chid pChan, unsigned type, arrayElementCount count, const void *pValue );
void destroyIO ( syncGroupNotify & );
void * operator new ( size_t size );
void operator delete ( void *pCadaver, size_t size );
+4 -4
View File
@@ -35,7 +35,7 @@
#include "oldAccess.h"
syncGroupReadNotify::syncGroupReadNotify ( CASG &sgIn, chid pChan,
unsigned type, unsigned long count, void *pValueIn ) :
unsigned type, arrayElementCount count, void *pValueIn ) :
syncGroupNotify ( sgIn, pChan ), pValue ( pValueIn )
{
pChan->read ( type, count, *this, &this->id );
@@ -45,7 +45,7 @@ syncGroupReadNotify::syncGroupReadNotify ( CASG &sgIn, chid pChan,
syncGroupReadNotify * syncGroupReadNotify::factory (
tsFreeList < class syncGroupReadNotify, 128 > &freeList,
struct CASG &sg, chid chan, unsigned type,
unsigned long count, void *pValueIn )
arrayElementCount count, void *pValueIn )
{
return new ( freeList ) syncGroupReadNotify ( sg, chan, type,
count, pValueIn);
@@ -62,7 +62,7 @@ syncGroupReadNotify::~syncGroupReadNotify ()
}
void syncGroupReadNotify::completion (
unsigned type, unsigned long count, const void *pData )
unsigned type, arrayElementCount count, const void *pData )
{
if ( this->magic != CASG_MAGIC ) {
this->sg.printf ( "cac: sync group io_complete(): bad sync grp op magic number?\n" );
@@ -79,7 +79,7 @@ void syncGroupReadNotify::completion (
}
void syncGroupReadNotify::exception (
int status, const char *pContext, unsigned type, unsigned long count )
int status, const char *pContext, unsigned type, arrayElementCount count )
{
ca_signal_formated ( status, __FILE__, __LINE__,
"CA sync group read request failed with chan=%s type=%d count=%ld because \"%s\"\n",
+5 -5
View File
@@ -35,7 +35,7 @@
#include "oldAccess.h"
syncGroupWriteNotify::syncGroupWriteNotify ( CASG &sgIn, chid pChan, unsigned type,
unsigned long count, const void *pValueIn ) :
arrayElementCount count, const void *pValueIn ) :
syncGroupNotify ( sgIn, pChan )
{
pChan->write ( type, count, pValueIn, *this, &this->id );
@@ -45,7 +45,7 @@ syncGroupWriteNotify::syncGroupWriteNotify ( CASG &sgIn, chid pChan, unsigned ty
syncGroupWriteNotify * syncGroupWriteNotify::factory (
tsFreeList < class syncGroupWriteNotify, 128 > &freeList,
struct CASG &sg, chid chan, unsigned type,
unsigned long count, const void *pValueIn )
arrayElementCount count, const void *pValueIn )
{
return new ( freeList ) syncGroupWriteNotify ( sg, chan, type,
count, pValueIn);
@@ -73,11 +73,11 @@ void syncGroupWriteNotify::completion ()
}
void syncGroupWriteNotify::exception (
int status, const char *pContext )
int status, const char *pContext, unsigned type, arrayElementCount count )
{
ca_signal_formated ( status, __FILE__, __LINE__,
"CA sync group write request for channel \"%s\" failed because \"%s\"\n",
this->chan->pName(), pContext);
"CA sync group write request for channel \"%s\" failed because \"%s\" type=%s count=%u\n",
this->chan->pName(), pContext, dbr_type_to_text ( type ), count);
//
// This notify is left installed at this point as a place holder indicating that
// all requests have not been completed. This notify is not uninstalled until
+7 -5
View File
@@ -189,12 +189,12 @@ extern "C" int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid )
* ca_sg_array_put()
*/
extern "C" int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid, chtype type,
unsigned long count, chid pChan, const void *pValue )
arrayElementCount count, chid pChan, const void *pValue )
{
CASG *pcasg;
oldCAC *pcac;
int caStatus;
caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
@@ -205,14 +205,15 @@ extern "C" int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid, chtype typ
return ECA_BADSYNCGRP;
}
return pcasg->put ( pChan, type, count, pValue );
return pcasg->put ( pChan, type,
static_cast < unsigned > ( count ), pValue );
}
/*
* ca_sg_array_get()
*/
extern "C" int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid, chtype type,
unsigned long count, chid pChan, void *pValue )
arrayElementCount count, chid pChan, void *pValue )
{
CASG *pcasg;
oldCAC *pcac;
@@ -228,5 +229,6 @@ extern "C" int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid, chtype typ
return ECA_BADSYNCGRP;
}
return pcasg->get ( pChan, type, count, pValue );
return pcasg->get ( pChan, type,
static_cast < unsigned > ( count ), pValue );
}
+27 -5
View File
@@ -20,7 +20,7 @@
//
tcpRecvWatchdog::tcpRecvWatchdog
( tcpiiu &iiuIn, double periodIn, epicsTimerQueue & queueIn ) :
period ( periodIn ), timer ( queueIn.createTimer ( *this ) ),
period ( periodIn ), timer ( queueIn.createTimer () ),
iiu ( iiuIn ), responsePending ( false ),
beaconAnomaly ( true )
{
@@ -31,7 +31,7 @@ tcpRecvWatchdog::~tcpRecvWatchdog ()
delete & this->timer;
}
epicsTimerNotify::expireStatus tcpRecvWatchdog::expire ()
epicsTimerNotify::expireStatus tcpRecvWatchdog::expire ( const epicsTime & currentTime )
{
if ( this->responsePending ) {
this->cancel ();
@@ -52,7 +52,7 @@ epicsTimerNotify::expireStatus tcpRecvWatchdog::expire ()
void tcpRecvWatchdog::beaconArrivalNotify ()
{
if ( ! this->beaconAnomaly && ! this->responsePending ) {
this->timer.start ( this->period );
this->timer.start ( *this, this->period );
debugPrintf ( ("Saw a normal beacon - reseting TCP recv watchdog\n") );
}
}
@@ -74,13 +74,35 @@ void tcpRecvWatchdog::messageArrivalNotify ()
{
this->beaconAnomaly = false;
this->responsePending = false;
this->timer.start ( this->period );
this->timer.start ( *this, this->period );
debugPrintf ( ("received a message - reseting TCP recv watchdog\n") );
}
//
// The thread for outgoing requests in the client runs
// at a higher priority than the thread in the client
// that receives responses. Therefore, there could
// be considerable large array write send backlog that
// is delaying departure of an echo request and also
// interrupting delivery of an echo response.
// We must be careful not to timeout the echo response as
// long as we see indication of regular departures of
// message buffers from the client in a situation where
// we know that the TCP send queueing has been exceeded.
// The send watchdog will be responsible for detecting
// dead connections in this case.
//
void tcpRecvWatchdog::sendBacklogProgressNotify ()
{
this->beaconAnomaly = false;
this->responsePending = false;
this->timer.start ( *this, this->period );
debugPrintf ( ("saw heavy send backlog - reseting TCP recv watchdog\n") );
}
void tcpRecvWatchdog::connectNotify ()
{
this->timer.start ( this->period );
this->timer.start ( *this, this->period );
debugPrintf ( ("connected to the server - reseting TCP recv watchdog\n") );
}
+3 -3
View File
@@ -17,7 +17,7 @@
tcpSendWatchdog::tcpSendWatchdog
( tcpiiu &iiuIn, double periodIn, epicsTimerQueue & queueIn ) :
period ( periodIn ), timer ( queueIn.createTimer ( *this ) ),
period ( periodIn ), timer ( queueIn.createTimer () ),
iiu ( iiuIn )
{
}
@@ -27,7 +27,7 @@ tcpSendWatchdog::~tcpSendWatchdog ()
delete & this->timer;
}
epicsTimerNotify::expireStatus tcpSendWatchdog::expire ()
epicsTimerNotify::expireStatus tcpSendWatchdog::expire ( const epicsTime & currentTime )
{
char hostName[128];
this->iiu.hostName ( hostName, sizeof ( hostName ) );
@@ -39,7 +39,7 @@ epicsTimerNotify::expireStatus tcpSendWatchdog::expire ()
void tcpSendWatchdog::start ()
{
this->timer.start ( this->period );
this->timer.start ( *this, this->period );
}
void tcpSendWatchdog::cancel ()
+417 -482
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -22,26 +22,26 @@ extern "C" void epicsShareAPI ca_test_event ( struct event_handler_args args )
switch ( args.type ) {
case DBR_STRING:
printf ( "CAC: Value:\t<%s>\n", (const char *) args.dbr );
printf ( "CAC: Value:\t<%s>\n", (dbr_string_t *) args.dbr );
break;
case DBR_CHAR:
printf ( "CAC: Value:\t<%d>\n", *(char *) args.dbr );
printf ( "CAC: Value:\t<%d>\n", *(dbr_char_t *) args.dbr );
break;
#if DBR_INT != DBR_SHORT
case DBR_INT:
#endif
case DBR_SHORT:
case DBR_ENUM:
printf ( "CAC: Value:\t<%d>\n", *(short *) args.dbr );
printf ( "CAC: Value:\t<%d>\n", *(dbr_short_t *) args.dbr );
break;
case DBR_LONG:
printf ( "CAC: Value:\t<%ld>\n", *(long *)args.dbr );
printf ( "CAC: Value:\t<%ld>\n", *(dbr_long_t *)args.dbr );
break;
case DBR_FLOAT:
printf ( "CAC: Value:\t<%f>\n", *(float *)args.dbr );
printf ( "CAC: Value:\t<%f>\n", *(dbr_float_t *)args.dbr );
break;
case DBR_DOUBLE:
printf ( "CAC: Value:\t<%f>\n", *(double *)args.dbr );
printf ( "CAC: Value:\t<%f>\n", *(dbr_double_t *)args.dbr );
break;
case DBR_STS_STRING:
printf ( "CAC: Value:\t<%s>\n", ((struct dbr_sts_string *)args.dbr)->value );
+41 -31
View File
@@ -135,7 +135,7 @@ udpiiu::udpiiu ( cac &cac ) :
this->recvThreadExitSignal = epicsEventMustCreate ( epicsEventEmpty );
if ( ! this->recvThreadExitSignal ) {
socket_close ( this->sock );
throwWithLocation ( noMemory () );
throwWithLocation ( std::bad_alloc () );
}
/*
@@ -164,7 +164,7 @@ udpiiu::udpiiu ( cac &cac ) :
this->printf ("CA: unable to create UDP receive thread\n");
epicsEventDestroy (this->recvThreadExitSignal);
socket_close (this->sock);
throwWithLocation ( noMemory () );
throwWithLocation ( std::bad_alloc () );
}
}
@@ -232,8 +232,8 @@ void udpiiu::recvMsg ()
SOCKERRSTR (errnoCpy) );
}
else if ( status > 0 ) {
this->postMsg ( src,
this->recvBuf, (unsigned long) status );
this->postMsg ( src, this->recvBuf, (arrayElementCount) status,
epicsTime::getCurrent() );
}
return;
}
@@ -485,21 +485,25 @@ void udpiiu::shutdown ()
epicsEventMustWait ( this->recvThreadExitSignal );
}
bool udpiiu::badUDPRespAction ( const caHdr &msg, const osiSockAddr &netAddr )
bool udpiiu::badUDPRespAction ( const caHdr &msg,
const osiSockAddr &netAddr, const epicsTime &currentTime )
{
char buf[64];
sockAddrToDottedIP ( &netAddr.sa, buf, sizeof ( buf ) );
this->printf ( "CAC: undecipherable ( bad msg code %u ) UDP message from %s\n",
msg.m_cmmd, buf );
char date[64];
currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
this->printf ( "CAC: undecipherable ( bad msg code %u ) UDP message from %s at %s\n",
msg.m_cmmd, buf, date );
return false;
}
bool udpiiu::noopAction ( const caHdr &, const osiSockAddr & )
bool udpiiu::noopAction ( const caHdr &, const osiSockAddr &, const epicsTime & )
{
return true;
}
bool udpiiu::searchRespAction ( const caHdr &msg, const osiSockAddr &addr )
bool udpiiu::searchRespAction ( const caHdr &msg,
const osiSockAddr &addr, const epicsTime &currentTime )
{
osiSockAddr serverAddr;
unsigned minorVersion;
@@ -527,7 +531,7 @@ bool udpiiu::searchRespAction ( const caHdr &msg, const osiSockAddr &addr )
* so that we can have multiple servers on one host
*/
serverAddr.ia.sin_family = AF_INET;
if ( CA_V48 ( CA_PROTOCOL_VERSION,minorVersion ) ) {
if ( CA_V48 ( minorVersion ) ) {
if ( msg.m_cid != INADDR_BROADCAST ) {
/*
* Leave address in network byte order (m_cid has not been
@@ -540,7 +544,7 @@ bool udpiiu::searchRespAction ( const caHdr &msg, const osiSockAddr &addr )
}
serverAddr.ia.sin_port = htons ( msg.m_dataType );
}
else if ( CA_V45 (CA_PROTOCOL_VERSION,minorVersion) ) {
else if ( CA_V45 (minorVersion) ) {
serverAddr.ia.sin_port = htons ( msg.m_dataType );
serverAddr.ia.sin_addr = addr.ia.sin_addr;
}
@@ -549,19 +553,20 @@ bool udpiiu::searchRespAction ( const caHdr &msg, const osiSockAddr &addr )
serverAddr.ia.sin_addr = addr.ia.sin_addr;
}
if ( CA_V42 ( CA_PROTOCOL_VERSION, minorVersion ) ) {
if ( CA_V42 ( minorVersion ) ) {
return this->pCAC ()->lookupChannelAndTransferToTCP
( msg.m_available, msg.m_cid, USHRT_MAX,
0, minorVersion, serverAddr );
( msg.m_available, msg.m_cid, 0xffff,
0, minorVersion, serverAddr, currentTime );
}
else {
return this->pCAC ()->lookupChannelAndTransferToTCP
( msg.m_available, msg.m_cid, msg.m_dataType,
msg.m_count, minorVersion, serverAddr );
msg.m_count, minorVersion, serverAddr, currentTime );
}
}
bool udpiiu::beaconAction ( const caHdr &msg, const osiSockAddr &net_addr )
bool udpiiu::beaconAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime &currentTime )
{
struct sockaddr_in ina;
@@ -596,49 +601,54 @@ bool udpiiu::beaconAction ( const caHdr &msg, const osiSockAddr &net_addr )
ina.sin_port = htons ( this->serverPort );
}
this->pCAC ()->beaconNotify ( ina );
this->pCAC ()->beaconNotify ( ina, currentTime );
return true;
}
bool udpiiu::repeaterAckAction ( const caHdr &, const osiSockAddr &)
bool udpiiu::repeaterAckAction ( const caHdr &,
const osiSockAddr &, const epicsTime &)
{
this->pCAC ()->repeaterSubscribeConfirmNotify ();
return true;
}
bool udpiiu::notHereRespAction ( const caHdr &, const osiSockAddr &)
bool udpiiu::notHereRespAction ( const caHdr &,
const osiSockAddr &, const epicsTime & )
{
return true;
}
bool udpiiu::exceptionRespAction ( const caHdr &msg, const osiSockAddr &net_addr )
bool udpiiu::exceptionRespAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime &currentTime )
{
const caHdr &reqMsg = * ( &msg + 1 );
char name[64];
sockAddrToDottedIP ( &net_addr.sa, name, sizeof ( name ) );
char date[64];
currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
if ( msg.m_postsize > sizeof ( caHdr ) ){
errlogPrintf ( "error condition \"%s\" detected by %s with context \"%s\"\n",
errlogPrintf ( "error condition \"%s\" detected by %s with context \"%s\" at %s\n",
ca_message ( htonl ( msg.m_available ) ),
name, reinterpret_cast <const char *> ( &reqMsg + 1 ) );
name, reinterpret_cast <const char *> ( &reqMsg + 1 ), date );
}
else{
errlogPrintf ( "error condition \"%s\" detected by %s\n",
ca_message ( htonl ( msg.m_available ) ), name );
errlogPrintf ( "error condition \"%s\" detected by %s at %s\n",
ca_message ( htonl ( msg.m_available ) ), name, date );
}
return true;
}
void udpiiu::postMsg ( const osiSockAddr &net_addr,
char *pInBuf, unsigned long blockSize )
char *pInBuf, arrayElementCount blockSize,
const epicsTime &currentTime)
{
caHdr *pCurMsg;
while ( blockSize ) {
unsigned long size;
arrayElementCount size;
if ( blockSize < sizeof ( *pCurMsg ) ) {
char buf[64];
@@ -694,7 +704,7 @@ void udpiiu::postMsg ( const osiSockAddr &net_addr,
else {
pStub = &udpiiu::badUDPRespAction;
}
bool success = ( this->*pStub ) ( *pCurMsg, net_addr );
bool success = ( this->*pStub ) ( *pCurMsg, net_addr, currentTime );
if ( ! success ) {
char buf[256];
sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) );
@@ -712,9 +722,9 @@ void udpiiu::postMsg ( const osiSockAddr &net_addr,
*/
bool udpiiu::pushDatagramMsg ( const caHdr &msg, const void *pExt, ca_uint16_t extsize )
{
unsigned long msgsize;
ca_uint16_t allignedExtSize;
caHdr *pbufmsg;
arrayElementCount msgsize;
ca_uint16_t allignedExtSize;
caHdr *pbufmsg;
allignedExtSize = CA_MESSAGE_ALIGN ( extsize );
msgsize = sizeof ( caHdr ) + allignedExtSize;
+20 -10
View File
@@ -39,6 +39,8 @@ epicsShareFunc void epicsShareAPI caRepeaterRegistrationMessage ( SOCKET sock, u
extern "C" epicsShareFunc void caRepeaterThread ( void *pDummy );
epicsShareFunc void ca_repeater ( void );
class epicsTime;
class udpiiu : public netiiu {
public:
udpiiu ( class cac & );
@@ -46,7 +48,8 @@ public:
void shutdown ();
void recvMsg ();
void postMsg ( const osiSockAddr &net_addr,
char *pInBuf, unsigned long blockSize );
char *pInBuf, arrayElementCount blockSize,
const epicsTime &currenTime);
void repeaterRegistrationMessage ( unsigned attemptNumber );
void datagramFlush ();
unsigned getPort () const;
@@ -55,7 +58,6 @@ public:
// exceptions
class noSocket {};
class noMemory {};
SOCKET getSock () const;
@@ -75,19 +77,27 @@ private:
bool pushDatagramMsg ( const caHdr &msg, const void *pExt, ca_uint16_t extsize );
typedef bool ( udpiiu::*pProtoStubUDP ) ( const caHdr &, const osiSockAddr & );
typedef bool ( udpiiu::*pProtoStubUDP ) ( const caHdr &,
const osiSockAddr &, const epicsTime & );
// UDP protocol dispatch table
static const pProtoStubUDP udpJumpTableCAC[];
// UDP protocol stubs
bool noopAction ( const caHdr &, const osiSockAddr & );
bool badUDPRespAction ( const caHdr &msg, const osiSockAddr &netAddr );
bool searchRespAction ( const caHdr &msg, const osiSockAddr &net_addr );
bool exceptionRespAction ( const caHdr &msg, const osiSockAddr &net_addr );
bool beaconAction ( const caHdr &msg, const osiSockAddr &net_addr );
bool notHereRespAction ( const caHdr &msg, const osiSockAddr &net_addr );
bool repeaterAckAction ( const caHdr &msg, const osiSockAddr &net_addr );
bool noopAction ( const caHdr &,
const osiSockAddr &, const epicsTime & );
bool badUDPRespAction ( const caHdr &msg,
const osiSockAddr &netAddr, const epicsTime & );
bool searchRespAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime & );
bool exceptionRespAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime & );
bool beaconAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime & );
bool notHereRespAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime & );
bool repeaterAckAction ( const caHdr &msg,
const osiSockAddr &net_addr, const epicsTime & );
friend void cacRecvThreadUDP ( void *pParam );
};
+195 -170
View File
@@ -21,33 +21,23 @@
#include <new> // needed by comQueueSend
#include "epicsTimer.h"
#include "epicsMemory.h"
#include "ipAddrToAsciiAsynchronous.h"
#include "osiWireFormat.h"
#include "comBuf.h"
#include "netiiu.h"
enum iiu_conn_state {iiu_connecting, iiu_connected, iiu_disconnected};
enum iiu_conn_state { iiu_connecting, iiu_connected, iiu_disconnected };
class nciu;
class tcpiiu;
class bufferReservoir {
public:
~bufferReservoir ();
void addOneBuffer ();
comBuf *fetchOneBuffer ();
unsigned nBytes ();
void drain ();
private:
tsDLList < comBuf > reservedBufs;
};
class comQueSend {
public:
comQueSend ( wireSendAdapter & );
~comQueSend ();
void clear ();
void reserveSpace ( unsigned msgSize );
unsigned occupiedBytes () const;
bool flushEarlyThreshold ( unsigned nBytesThisMsg ) const;
bool flushBlockThreshold ( unsigned nBytesThisMsg ) const;
@@ -55,13 +45,12 @@ public:
void pushUInt16 ( const ca_uint16_t value );
void pushUInt32 ( const ca_uint32_t value );
void pushFloat32 ( const ca_float32_t value );
void pushString ( const char *pVal, unsigned nElem );
void pushString ( const char *pVal, unsigned nChar );
void push_dbr_type ( unsigned type, const void *pVal, unsigned nElem );
comBuf * popNextComBufToSend ();
private:
wireSendAdapter & wire;
tsDLList < comBuf > bufs;
bufferReservoir reservoir;
unsigned nBytesPending;
void copy_dbr_string ( const void *pValue, unsigned nElem );
void copy_dbr_short ( const void *pValue, unsigned nElem );
@@ -72,6 +61,63 @@ private:
typedef void ( comQueSend::*copyFunc_t ) (
const void *pValue, unsigned nElem );
static const copyFunc_t dbrCopyVector [39];
//
// visual C++ version 6.0 does not allow out of
// class member template function definition
//
template < class T >
inline void copyIn ( const T *pVal, unsigned nElem )
{
unsigned nCopied;
comBuf *pComBuf = this->bufs.last ();
if ( pComBuf ) {
nCopied = pComBuf->copyIn ( pVal, nElem );
this->nBytesPending += nCopied * sizeof ( T );
}
else {
nCopied = 0u;
}
while ( nElem > nCopied ) {
comBuf *pComBuf = new ( std::nothrow ) comBuf;
if ( ! pComBuf ) {
this->wire.forcedShutdown ();
throw std::bad_alloc ();
}
unsigned nNew = pComBuf->copyIn ( &pVal[nCopied], nElem - nCopied );
nCopied += nNew;
this->nBytesPending += nNew * sizeof ( T );
this->bufs.add ( *pComBuf );
}
}
//
// visual C++ version 6.0 does not allow out of
// class member template function definition
//
template < class T >
inline void copyIn ( const T &val )
{
comBuf *pComBuf = this->bufs.last ();
if ( pComBuf ) {
if ( pComBuf->copyIn ( &val, 1u ) >= 1u ) {
this->nBytesPending += sizeof ( T );
return;
}
}
pComBuf = new ( std::nothrow ) comBuf;
if ( ! pComBuf ) {
this->wire.forcedShutdown ();
throw std::bad_alloc ();
}
if ( pComBuf->copyIn ( &val, 1u ) == 0u ) {
this->wire.forcedShutdown ();
throw -1;
}
this->bufs.add ( *pComBuf );
this->nBytesPending += sizeof ( T );
return;
}
};
static const unsigned maxBytesPendingTCP = 0x4000;
@@ -81,9 +127,21 @@ public:
comQueRecv ();
~comQueRecv ();
unsigned occupiedBytes () const;
bool copyOutBytes ( void *pBuf, unsigned nBytes );
unsigned copyOutBytes ( void *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
void pushLastComBufReceived ( comBuf & );
void clear ();
epicsInt8 popInt8 ();
epicsUInt8 popUInt8 ();
epicsInt16 popInt16 ();
epicsUInt16 popUInt16 ();
epicsInt32 popInt32 ();
epicsUInt32 popUInt32 ();
epicsFloat32 popFloat32 ();
epicsFloat64 popFloat64 ();
void popString ( epicsOldString * );
class insufficentBytesAvailable {};
private:
tsDLList < comBuf > bufs;
};
@@ -93,6 +151,7 @@ public:
tcpRecvWatchdog ( tcpiiu &, double periodIn, epicsTimerQueue & queueIn );
virtual ~tcpRecvWatchdog ();
void rescheduleRecvTimer ();
void sendBacklogProgressNotify ();
void messageArrivalNotify ();
void beaconArrivalNotify ();
void beaconAnomalyNotify ();
@@ -105,7 +164,7 @@ private:
tcpiiu &iiu;
bool responsePending;
bool beaconAnomaly;
expireStatus expire ();
expireStatus expire ( const epicsTime & currentTime );
};
class tcpSendWatchdog : private epicsTimerNotify {
@@ -118,19 +177,18 @@ private:
const double period;
epicsTimer &timer;
tcpiiu &iiu;
expireStatus expire ();
expireStatus expire ( const epicsTime & currentTime );
};
class hostNameCache : public ipAddrToAsciiAsynchronous {
public:
hostNameCache ( const osiSockAddr &addr, ipAddrToAsciiEngine &engine );
~hostNameCache ();
void destroy ();
void ioCompletionNotify ( const char *pHostName );
void hostName ( char *pBuf, unsigned bufLength ) const;
void * operator new ( size_t size );
void operator delete ( void *pCadaver, size_t size );
protected:
~hostNameCache ();
private:
bool ioComplete;
char hostNameBuf [128];
@@ -141,14 +199,25 @@ private:
extern "C" void cacSendThreadTCP ( void *pParam );
extern "C" void cacRecvThreadTCP ( void *pParam );
// a modified ca header with capacity for large arrays
struct caHdrLargeArray {
ca_uint32_t m_postsize; // size of message extension
ca_uint32_t m_count; // operation data count
ca_uint32_t m_cid; // channel identifier
ca_uint32_t m_available; // protocol stub dependent
ca_uint16_t m_dataType; // operation data type
ca_uint16_t m_cmmd; // operation to be performed
};
class tcpiiu :
public netiiu, public tsDLNode < tcpiiu >,
private wireSendAdapter, private wireRecvAdapter {
public:
tcpiiu ( cac &cac, double connectionTimeout, epicsTimerQueue &timerQueue );
tcpiiu ( cac &cac, double connectionTimeout,
epicsTimerQueue &timerQueue, const osiSockAddr &addrIn,
unsigned minorVersion, class bhe &bhe,
ipAddrToAsciiEngine &engineIn );
~tcpiiu ();
bool initiateConnect ( const osiSockAddr &addrIn, unsigned minorVersion,
class bhe &bhe, ipAddrToAsciiEngine &engineIn );
void connect ();
void processIncoming ();
void destroy ();
@@ -157,7 +226,6 @@ public:
void beaconAnomalyNotify ();
void beaconArrivalNotify ();
bool fullyConstructed () const;
void flushRequest ();
bool flushBlockThreshold () const;
void flushRequestIfAboveEarlyThreshold ();
@@ -168,13 +236,14 @@ public:
bool ca_v41_ok () const;
bool ca_v42_ok () const;
bool ca_v44_ok () const;
bool ca_v49_ok () const;
void hostName ( char *pBuf, unsigned bufLength ) const;
const char * pHostName () const; // deprecated - please do not use
bool isVirtaulCircuit ( const char *pChannelName, const osiSockAddr &addr ) const;
bool alive () const;
double beaconPeriod () const;
bhe * getBHE () const;
bhe & getBHE () const;
SOCKET getSock() const;
bool trueOnceOnly ();
@@ -184,26 +253,29 @@ private:
tcpSendWatchdog sendDog;
comQueSend sendQue;
comQueRecv recvQue;
caHdrLargeArray curMsg;
osiSockAddr addr;
hostNameCache *pHostNameCache;
caHdr curMsg;
unsigned long curDataMax;
class bhe *pBHE;
arrayElementCount curDataMax;
arrayElementCount curDataBytes;
epics_auto_ptr < hostNameCache > pHostNameCache;
class bhe & BHE;
char *pCurData;
unsigned minorProtocolVersion;
iiu_conn_state state;
epicsEventId sendThreadFlushSignal;
epicsEventId recvThreadRingBufferSpaceAvailableSignal;
epicsEventId sendThreadExitSignal;
epicsEventId recvThreadExitSignal;
epicsEventId flushBlockSignal;
epicsEvent sendThreadFlushEvent;
epicsEvent recvThreadRingBufferSpaceAvailableEvent;
epicsEvent sendThreadExitEvent;
epicsEvent recvThreadExitEvent;
epicsEvent flushBlockEvent;
SOCKET sock;
unsigned contigRecvMsgCount;
unsigned blockingForFlush;
bool fullyConstructedFlag;
unsigned socketLibrarySendBufferSize;
unsigned unacknowledgedSendBytes;
bool busyStateDetected; // only modified by the recv thread
bool flowControlActive; // only modified by the send process thread
bool echoRequestPending;
bool oldMsgHeaderAvailable;
bool msgHeaderAvailable;
bool sockCloseCompleted;
bool f_trueOnceOnly;
@@ -235,38 +307,6 @@ private:
bool flush (); // only to be called by the send thread
};
inline bufferReservoir::~bufferReservoir ()
{
this->drain ();
}
inline comBuf *bufferReservoir::fetchOneBuffer ()
{
return this->reservedBufs.get ();
}
inline void bufferReservoir::addOneBuffer ()
{
comBuf *pBuf = new comBuf;
if ( ! pBuf ) {
throw std::bad_alloc();
}
this->reservedBufs.add ( *pBuf );
}
inline unsigned bufferReservoir::nBytes ()
{
return ( this->reservedBufs.count () * comBuf::capacityBytes () );
}
inline void bufferReservoir::drain ()
{
comBuf *pBuf;
while ( ( pBuf = this->reservedBufs.get () ) ) {
pBuf->destroy ();
}
}
inline bool comQueSend::dbr_type_ok ( unsigned type )
{
if ( type >= ( sizeof ( this->dbrCopyVector ) / sizeof ( this->dbrCopyVector[0] ) ) ) {
@@ -278,105 +318,24 @@ inline bool comQueSend::dbr_type_ok ( unsigned type )
return true;
}
//
// 1) 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).
//
// 2) Arguments here are a bit verbose until compilers all implement
// member template functions.
//
template < class T >
inline void comQueSend_copyIn ( unsigned &nBytesPending,
tsDLList < comBuf > &comBufList, bufferReservoir &reservoir,
const T *pVal, unsigned nElem )
{
nBytesPending += sizeof ( T ) * nElem;
comBuf *pComBuf = comBufList.last ();
if ( pComBuf ) {
unsigned nCopied = pComBuf->copyIn ( pVal, nElem );
if ( nElem > nCopied ) {
comQueSend_copyInWithReservour ( comBufList, reservoir, &pVal[nCopied],
nElem - nCopied );
}
}
else {
comQueSend_copyInWithReservour ( comBufList, reservoir, pVal, nElem );
}
}
template < class T >
void comQueSend_copyInWithReservour (
tsDLList < comBuf > &comBufList, bufferReservoir &reservoir,
const T *pVal, unsigned nElem )
{
unsigned nCopied = 0u;
while ( nElem > nCopied ) {
comBuf *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 ( unsigned &nBytesPending,
tsDLList < comBuf > &comBufList, bufferReservoir &reservoir,
const T &val )
{
nBytesPending += sizeof ( T );
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 );
}
inline void comQueSend::pushUInt16 ( const ca_uint16_t value )
{
comQueSend_copyIn ( this->nBytesPending,
this->bufs, this->reservoir, value );
this->copyIn ( value );
}
inline void comQueSend::pushUInt32 ( const ca_uint32_t value )
{
comQueSend_copyIn ( this->nBytesPending,
this->bufs, this->reservoir, value );
this->copyIn ( value );
}
inline void comQueSend::pushFloat32 ( const ca_float32_t value )
{
comQueSend_copyIn ( this->nBytesPending,
this->bufs, this->reservoir, value );
this->copyIn ( value );
}
inline void comQueSend::pushString ( const char *pVal, unsigned nElem )
inline void comQueSend::pushString ( const char *pVal, unsigned nChar )
{
comQueSend_copyIn ( this->nBytesPending,
this->bufs, this->reservoir, pVal, nElem );
this->copyIn ( pVal, nChar );
}
// it is assumed that dbr_type_ok() was called prior to calling this routine
@@ -415,19 +374,80 @@ inline comBuf * comQueSend::popNextComBufToSend ()
return pBuf;
}
inline bool tcpiiu::fullyConstructed () const
inline epicsInt8 comQueRecv::popInt8 ()
{
return this->fullyConstructedFlag;
return static_cast < epicsInt8 > ( this->popUInt8() );
}
inline epicsUInt16 comQueRecv::popUInt16 ()
{
epicsUInt16 tmp = this->popUInt8 ();
tmp <<= 8u;
tmp |= this->popUInt8 ();
return tmp;
}
inline epicsInt16 comQueRecv::popInt16 ()
{
epicsInt16 tmp = this->popInt8 ();
tmp <<= 8u;
tmp |= this->popInt8 ();
return tmp;
}
inline epicsUInt32 comQueRecv::popUInt32 ()
{
epicsUInt32 tmp = this->popUInt8 ();
tmp <<= 24u;
tmp |= this->popUInt8 () << 16u;
tmp |= this->popUInt8 () << 8u;
tmp |= this->popUInt8 ();
return tmp;
}
inline epicsInt32 comQueRecv::popInt32 ()
{
epicsInt32 tmp = this->popInt8 ();
tmp <<= 24u;
tmp |= this->popInt8 () << 16u;
tmp |= this->popInt8 () << 8u;
tmp |= this->popInt8 ();
return tmp;
}
inline epicsFloat32 comQueRecv::popFloat32 ()
{
epicsFloat32 tmp;
epicsUInt8 wire[ sizeof ( tmp ) ];
for ( unsigned i = 0u; i < sizeof ( tmp ); i++ ) {
wire[i] = this->popUInt8 ();
}
osiConvertFromWireFormat ( tmp, wire );
return tmp;
}
inline epicsFloat64 comQueRecv::popFloat64 ()
{
epicsFloat64 tmp;
epicsUInt8 wire[ sizeof ( tmp ) ];
for ( unsigned i = 0u; i < sizeof ( tmp ); i++ ) {
wire[i] = this->popUInt8 ();
}
osiConvertFromWireFormat ( tmp, wire );
return tmp;
}
inline void comQueRecv::popString ( epicsOldString *pStr )
{
for ( unsigned i = 0u; i < sizeof ( *pStr ); i++ ) {
pStr[0][i] = this->popInt8 ();
}
}
inline void tcpiiu::hostName ( char *pBuf, unsigned bufLength ) const
{
if ( this->pHostNameCache ) {
this->pHostNameCache->hostName ( pBuf, bufLength );
}
else {
netiiu::hostName ( pBuf, bufLength );
}
this->pHostNameCache->hostName ( pBuf, bufLength );
}
// deprecated - please dont use - this is _not_ thread safe
@@ -440,17 +460,22 @@ inline const char * tcpiiu::pHostName () const
inline void tcpiiu::flushRequest ()
{
epicsEventSignal ( this->sendThreadFlushSignal );
}
inline bool tcpiiu::ca_v44_ok () const
{
return CA_V44 ( CA_PROTOCOL_VERSION, this->minorProtocolVersion );
this->sendThreadFlushEvent.signal ();
}
inline bool tcpiiu::ca_v41_ok () const
{
return CA_V41 ( CA_PROTOCOL_VERSION, this->minorProtocolVersion );
return CA_V41 ( this->minorProtocolVersion );
}
inline bool tcpiiu::ca_v44_ok () const
{
return CA_V44 ( this->minorProtocolVersion );
}
inline bool tcpiiu::ca_v49_ok () const
{
return CA_V49 ( this->minorProtocolVersion );
}
inline bool tcpiiu::alive () const
@@ -464,9 +489,9 @@ inline bool tcpiiu::alive () const
}
}
inline bhe * tcpiiu::getBHE () const
inline bhe & tcpiiu::getBHE () const
{
return this->pBHE;
return this->BHE;
}
inline void tcpiiu::beaconAnomalyNotify ()
+713 -677
View File
File diff suppressed because it is too large Load Diff
+25 -22
View File
@@ -48,24 +48,23 @@
*
* CA server TCP client task (one spawned for each client)
*/
void camsgtask (struct client *client)
void camsgtask ( struct client *client )
{
int nchars;
int status;
int nchars;
int status;
client->tid = epicsThreadGetIdSelf ();
casAttachThreadToClient ( client );
taskwdInsert (epicsThreadGetIdSelf(), NULL, NULL);
while (TRUE) {
while ( TRUE ) {
client->recv.stk = 0;
nchars = recv (client->sock, &client->recv.buf[client->recv.cnt],
(int)(sizeof(client->recv.buf)-client->recv.cnt), 0);
if (nchars==0){
if (CASDEBUG>0) {
assert ( client->recv.maxstk >= client->recv.cnt );
nchars = recv ( client->sock, &client->recv.buf[client->recv.cnt],
(int) ( client->recv.maxstk - client->recv.cnt ), 0 );
if ( nchars == 0 ){
if ( CASDEBUG > 0 ) {
errlogPrintf ( "CAS: nill message disconnect ( %u bytes request )\n",
sizeof (client->recv.buf) - client->recv.cnt );
sizeof ( client->recv.buf ) - client->recv.cnt );
}
break;
}
@@ -75,19 +74,19 @@ void camsgtask (struct client *client)
/*
* normal conn lost conditions
*/
if ( (anerrno!=SOCK_ECONNABORTED&&
anerrno!=SOCK_ECONNRESET&&
anerrno!=SOCK_ETIMEDOUT)||
CASDEBUG>2) {
errlogPrintf ("CAS: client disconnect(errno=%d)\n", anerrno);
if ( ( anerrno != SOCK_ECONNABORTED &&
anerrno != SOCK_ECONNRESET &&
anerrno != SOCK_ETIMEDOUT ) ||
CASDEBUG > 2 ) {
errlogPrintf ( "CAS: client disconnect(errno=%d)\n", anerrno );
}
break;
}
epicsTimeGetCurrent (&client->time_at_last_recv);
client->recv.cnt += (unsigned long) nchars;
epicsTimeGetCurrent ( &client->time_at_last_recv );
client->recv.cnt += ( unsigned ) nchars;
status = camessage (client, &client->recv);
status = camessage ( client );
if (status == 0) {
/*
* if there is a partial message
@@ -138,6 +137,10 @@ void camsgtask (struct client *client)
cas_send_msg(client, TRUE);
}
}
destroy_client (client);
LOCK_CLIENTQ;
ellDelete ( &clientQ, &client->node );
UNLOCK_CLIENTQ;
destroy_tcp_client ( client );
}
+133 -69
View File
@@ -37,8 +37,10 @@
#include "osiSock.h"
#include "epicsTime.h"
#include "errlog.h"
#include "net_convert.h"
typedef unsigned long arrayElementCount;
#include "net_convert.h"
#include "server.h"
/*
@@ -46,65 +48,27 @@
*
* (channel access server send message)
*/
void cas_send_msg (struct client *pclient, int lock_needed)
void cas_send_msg ( struct client *pclient, int lock_needed )
{
int status;
if (CASDEBUG>2 && pclient->send.stk) {
errlogPrintf ("CAS: Sending a message of %d bytes\n", pclient->send.stk);
if ( CASDEBUG > 2 && pclient->send.stk ) {
errlogPrintf ( "CAS: Sending a message of %d bytes\n", pclient->send.stk );
}
if (pclient->disconnect) {
if (CASDEBUG>2) {
errlogPrintf ("CAS: msg Discard for sock %d addr %x\n",
pclient->sock, pclient->addr.sin_addr.s_addr);
if ( pclient->disconnect ) {
if ( CASDEBUG > 2 ) {
errlogPrintf ( "CAS: msg Discard for sock %d addr %x\n",
pclient->sock, pclient->addr.sin_addr.s_addr );
}
return;
}
if(lock_needed){
SEND_LOCK(pclient);
if ( lock_needed ) {
SEND_LOCK ( pclient );
}
if (pclient->send.stk) {
#ifdef CONVERSION_REQUIRED
/* Convert all caHdr into net format.
* The remaining bytes must already be in
* net format, because here we have no clue
* how to convert them.
*/
char *buf;
unsigned long msg_size, num_bytes;
caHdr *mp;
buf = (char *) pclient->send.buf;
num_bytes = pclient->send.stk;
/* convert only if we have at least a complete caHdr */
while (num_bytes >= sizeof(caHdr))
{
mp = (caHdr *) buf;
msg_size = sizeof (caHdr) + mp->m_postsize;
DLOG(3,"CAS: sending cmmd %d, postsize %d\n",
mp->m_cmmd, (int)mp->m_postsize,
0, 0, 0, 0);
/* convert the complete header into host format */
mp->m_cmmd = htons (mp->m_cmmd);
mp->m_postsize = htons (mp->m_postsize);
mp->m_dataType = htons (mp->m_dataType);
mp->m_count = htons (mp->m_count);
mp->m_cid = htonl (mp->m_cid);
mp->m_available = htonl (mp->m_available);
/* get next message: */
buf += msg_size;
num_bytes -= msg_size;
}
#endif
if ( pclient->send.stk ) {
status = sendto (pclient->sock, pclient->send.buf, pclient->send.stk, 0,
(struct sockaddr *)&pclient->addr, sizeof(pclient->addr));
@@ -156,39 +120,52 @@ void cas_send_msg (struct client *pclient, int lock_needed)
SEND_UNLOCK(pclient);
}
DLOG(3, "------------------------------\n\n", 0,0,0,0,0,0);
DLOG ( 3, ( "------------------------------\n\n" ) );
return;
}
/*
*
* cas_alloc_msg()
* cas_copy_in_header()
*
* see also ALLOC_MSG()/END_MSG() in server.h
*
* (allocate space in the outgoing message buffer)
* Allocate space in the outgoing message buffer and
* copy in message header. Return pointer to message body.
*
* send lock must be on while in this routine
*
* returns 1) a valid ptr to msg buffer space
* 2) NULL (msg will not fit)
* Returns a valid ptr to message body or NULL if the msg
* will not fit.
*/
caHdr *cas_alloc_msg (struct client *pclient, unsigned extsize)
int cas_copy_in_header (
struct client *pclient, ca_uint16_t response, ca_uint32_t payloadSize,
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
ca_uint32_t responseSpecific, void **ppPayload )
{
unsigned msgsize;
unsigned msgSize;
extsize = CA_MESSAGE_ALIGN(extsize);
if ( extsize > UINT_MAX - sizeof(caHdr) ) {
return NULL;
}
msgsize = extsize + sizeof(caHdr);
if ( msgsize > pclient->send.maxstk ) {
return NULL;
if ( payloadSize > UINT_MAX - sizeof ( caHdr ) - 8u ) {
return FALSE;
}
if ( pclient->send.stk > pclient->send.maxstk - msgsize ) {
payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
msgSize = payloadSize + sizeof ( caHdr );
if ( payloadSize >= 0xffff || nElem >= 0xffff ) {
if ( ! CA_V49 ( pclient->minor_version_number ) ) {
return FALSE;
}
msgSize += 2 * sizeof ( ca_uint32_t );
}
if ( msgSize > pclient->send.maxstk ) {
casExpandSendBuffer ( pclient, msgSize );
if ( msgSize > pclient->send.maxstk ) {
return FALSE;
}
}
if ( pclient->send.stk > pclient->send.maxstk - msgSize ) {
if ( pclient->disconnect ) {
pclient->send.stk = 0;
}
@@ -197,8 +174,95 @@ caHdr *cas_alloc_msg (struct client *pclient, unsigned extsize)
}
}
if ( payloadSize < 0xffff && nElem < 0xffff ) {
caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
pMsg->m_cmmd = htons ( response );
pMsg->m_postsize = htons ( ( ( ca_uint16_t ) payloadSize ) );
pMsg->m_dataType = htons ( dataType );
pMsg->m_count = htons ( ( ( ca_uint16_t ) nElem ) );
pMsg->m_cid = htonl ( cid );
pMsg->m_available = htonl ( responseSpecific );
if ( ppPayload ) {
*ppPayload = ( void * ) ( pMsg + 1 );
}
}
else {
caHdr *pMsg = ( caHdr * ) &pclient->send.buf[pclient->send.stk];
ca_uint32_t *pW32 = ( ca_uint32_t * ) ( pMsg + 1 );
pMsg->m_cmmd = htons ( response );
pMsg->m_postsize = htons ( 0xffff );
pMsg->m_dataType = htons ( dataType );
pMsg->m_count = htons ( 0u );
pMsg->m_cid = htonl ( cid );
pMsg->m_available = htonl ( responseSpecific );
pW32[0] = htonl ( payloadSize );
pW32[1] = htonl ( nElem );
if ( ppPayload ) {
*ppPayload = ( void * ) ( pW32 + 2 );
}
}
return TRUE;
}
void cas_set_header_cid ( struct client *pClient, ca_uint32_t cid )
{
caHdr *pMsg = ( caHdr * ) &pClient->send.buf[pClient->send.stk];
pMsg->m_cid = htonl ( cid );
}
void cas_commit_msg ( struct client *pClient, ca_uint32_t size )
{
caHdr * pMsg = ( caHdr * ) &pClient->send.buf[pClient->send.stk];
size = CA_MESSAGE_ALIGN ( size );
if ( pMsg->m_postsize == htons ( 0xffff ) ) {
ca_uint32_t * pLW = ( ca_uint32_t * ) ( pMsg + 1 );
assert ( size <= ntohl ( *pLW ) );
pLW[0] = htonl ( size );
size += sizeof ( caHdr ) + 2 * sizeof ( *pLW );
}
else {
assert ( size <= ntohs ( pMsg->m_postsize ) );
pMsg->m_postsize = htons ( (ca_uint16_t) size );
size += sizeof ( caHdr );
}
pClient->send.stk += size;
}
/*
* this assumes that we have already checked to see
* if sufficent bytes are available
*/
ca_uint16_t rsrvGetUInt16 ( struct message_buffer *recv )
{
ca_uint16_t tmp;
/*
* it fits END_MSG will push it on the stack
* this assumes that we have already checked to see
* if sufficent bytes are available
*/
return (caHdr *) &pclient->send.buf[pclient->send.stk];
assert ( recv->cnt - recv->stk >= 2u );
tmp = recv->buf[recv->stk++];
tmp <<= 8u;
tmp |= recv->buf[recv->stk++];
return tmp;
}
/*
* this assumes that we have already checked to see
* if sufficent bytes are available
*/
ca_uint16_t rsrvGetUInt32 ( struct message_buffer *recv )
{
ca_uint16_t tmp;
/*
* this assumes that we have already checked to see
* if sufficent bytes are available
*/
assert ( recv->cnt - recv->stk >= 4u );
tmp = recv->buf[recv->stk++];
tmp <<= 24u;
tmp |= recv->buf[recv->stk++] << 16u;
tmp |= recv->buf[recv->stk++] << 8u;
tmp |= recv->buf[recv->stk++];
return tmp;
}
+366 -312
View File
@@ -57,213 +57,6 @@
#define DELETE_TASK(NAME)\
if(threadNameToId(NAME)!=0)threadDestroy(threadNameToId(NAME));
/*
* create_base_client ()
*/
struct client *create_base_client ()
{
struct client *client;
client = freeListMalloc (rsrvClientFreeList);
if (!client) {
epicsPrintf ("CAS: no space in pool for a new client\n");
return NULL;
}
/*
* The following inits to zero done instead of a bfill since the send
* and recv buffers are large and don't need initialization.
*
* memset(client, 0, sizeof(*client));
*/
client->blockSem = epicsEventCreate(epicsEventEmpty);
if(!client->blockSem){
freeListFree(rsrvClientFreeList, client);
return NULL;
}
/*
* user name initially unknown
*/
client->pUserName = malloc(1);
if(!client->pUserName){
epicsEventDestroy(client->blockSem);
freeListFree(rsrvClientFreeList, client);
return NULL;
}
client->pUserName[0] = '\0';
/*
* host name initially unknown
*/
client->pHostName = malloc(1);
if(!client->pHostName){
epicsEventDestroy(client->blockSem);
free(client->pUserName);
freeListFree(rsrvClientFreeList, client);
return NULL;
}
client->pHostName[0] = '\0';
ellInit(&client->addrq);
ellInit(&client->putNotifyQue);
memset((char *)&client->addr, 0, sizeof(client->addr));
client->tid = 0;
client->sock = INVALID_SOCKET;
client->send.stk = 0ul;
client->send.cnt = 0ul;
client->recv.stk = 0ul;
client->recv.cnt = 0ul;
client->evuser = NULL;
client->disconnect = FALSE; /* for TCP only */
epicsTimeGetCurrent(&client->time_at_last_send);
epicsTimeGetCurrent(&client->time_at_last_recv);
client->proto = IPPROTO_UDP;
client->minor_version_number = CA_UKN_MINOR_VERSION;
client->send.maxstk = MAX_UDP_SEND;
client->lock = epicsMutexMustCreate();
client->putNotifyLock = epicsMutexMustCreate();
client->addrqLock = epicsMutexMustCreate();
client->eventqLock = epicsMutexMustCreate();
client->recv.maxstk = MAX_UDP_RECV;
return client;
}
/*
* create_client ()
*/
struct client *create_client (SOCKET sock)
{
int status;
struct client *client;
int true = TRUE;
osiSocklen_t addrSize;
unsigned priorityOfEvents;
/*
* see TCP(4P) this seems to make unsolicited single events much
* faster. I take care of queue up as load increases.
*/
status = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY,
(char *)&true, sizeof(true));
if (status < 0) {
errlogPrintf ("CAS: TCP_NODELAY option set failed\n");
socket_close (sock);
return NULL;
}
/*
* turn on KEEPALIVE so if the client crashes
* this task will find out and exit
*/
status = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE,
(char *)&true, sizeof(true));
if (status < 0) {
errlogPrintf ("CAS: SO_KEEPALIVE option set failed\n");
socket_close (sock);
return NULL;
}
/*
* some concern that vxWorks will run out of mBuf's
* if this change is made
*
* joh 11-10-98
*/
#if 0
/*
* set TCP buffer sizes to be synergistic
* with CA internal buffering
*/
i = MAX_MSG_SIZE;
status = setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof(i));
if (status < 0) {
errlogPrintf ("CAS: SO_SNDBUF set failed\n");
socket_close (sock);
return NULL;
}
i = MAX_MSG_SIZE;
status = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, sizeof(i));
if (status < 0) {
errlogPrintf ("CAS: SO_RCVBUF set failed\n");
socket_close (sock);
return NULL;
}
#endif
client = (struct client *) create_base_client ();
if (!client) {
errlogPrintf("CAS: client init failed\n");
socket_close (sock);
return NULL;
}
client->proto = IPPROTO_TCP;
client->send.maxstk = MAX_TCP;
client->recv.maxstk = MAX_TCP;
client->sock = sock;
addrSize = sizeof (client->addr);
status = getpeername (sock, (struct sockaddr *)&client->addr,
&addrSize);
if (status < 0) {
epicsPrintf ("CAS: peer address fetch failed\n");
destroy_client (client);
return NULL;
}
client->evuser = (struct event_user *) db_init_events();
if (!client->evuser) {
errlogPrintf ("CAS: unable to init the event facility\n");
destroy_client (client);
return NULL;
}
status = db_add_extra_labor_event (client->evuser, write_notify_reply, client);
if (status != DB_EVENT_OK) {
errlogPrintf("CAS: unable to setup the event facility\n");
destroy_client (client);
return NULL;
}
{
unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
epicsThreadBooleanStatus tbs;
tbs = epicsThreadLowestPriorityLevelAbove ( priorityOfSelf, &priorityOfEvents );
if ( tbs != epicsThreadBooleanStatusSuccess ) {
priorityOfEvents = priorityOfSelf;
}
}
status = db_start_events ( client->evuser, "CAS-event",
NULL, NULL, priorityOfEvents );
if (status != DB_EVENT_OK) {
errlogPrintf("CAS: unable to start the event facility\n");
destroy_client (client);
return NULL;
}
client->recv.cnt = 0ul;
if (CASDEBUG>0) {
char buf[64];
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
errlogPrintf ("CAS: conn req from %s\n", buf);
}
LOCK_CLIENTQ;
ellAdd (&clientQ, &client->node);
UNLOCK_CLIENTQ;
return client;
}
/*
*
* req_server()
@@ -404,18 +197,23 @@ LOCAL int req_server (void)
continue;
}
else {
struct client *pClient;
unsigned priorityOfClient;
epicsThreadId id;
struct client *pClient;
pClient = create_client (clientSock);
if (!pClient) {
pClient = create_tcp_client ( clientSock );
if ( ! pClient ) {
errlogPrintf ( "CAS: unable to create new client because \"%s\"\n",
strerror (errno) );
epicsThreadSleep(15.0);
strerror ( errno ) );
epicsThreadSleep ( 15.0 );
continue;
}
LOCK_CLIENTQ;
ellAdd ( &clientQ, &pClient->node );
UNLOCK_CLIENTQ;
/*
* go up two levels in priority so that the event task is above the
* task waiting in accept ()
@@ -433,10 +231,10 @@ LOCAL int req_server (void)
}
id = epicsThreadCreate ( "CAS-client", priorityOfClient,
epicsThreadGetStackSize (epicsThreadStackBig),
(EPICSTHREADFUNC)camsgtask, (void *)pClient );
if (id==0) {
destroy_client ( pClient );
epicsThreadGetStackSize ( epicsThreadStackBig ),
( EPICSTHREADFUNC ) camsgtask, pClient );
if ( id == 0 ) {
destroy_tcp_client ( pClient );
errlogPrintf ( "CAS: task creation for new client failed\n" );
epicsThreadSleep ( 15.0 );
continue;
@@ -451,21 +249,50 @@ LOCAL int req_server (void)
epicsShareFunc int epicsShareAPI rsrv_init (void)
{
epicsThreadId tid;
long maxBytesAsALong;
long status;
clientQlock = epicsMutexMustCreate();
ellInit (&clientQ);
freeListInitPvt (&rsrvClientFreeList, sizeof(struct client), 8);
freeListInitPvt (&rsrvChanFreeList, sizeof(struct channel_in_use), 512);
freeListInitPvt (&rsrvEventFreeList, sizeof(struct event_ext), 512);
ellInit (&beaconAddrList);
ellInit ( &clientQ );
freeListInitPvt ( &rsrvClientFreeList, sizeof(struct client), 8 );
freeListInitPvt ( &rsrvChanFreeList, sizeof(struct channel_in_use), 512 );
freeListInitPvt ( &rsrvEventFreeList, sizeof(struct event_ext), 512 );
freeListInitPvt ( &rsrvSmallBufFreeListTCP, MAX_TCP, 16 );
status = envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong );
if ( status || maxBytesAsALong < 0 ) {
errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" );
rsrvSizeofLargeBufTCP = MAX_TCP;
}
else {
/* allow room for the protocol header so that they get the array size they requested */
static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong;
if ( maxBytes < 0xffffffff - headerSize ) {
maxBytes += headerSize;
}
else {
maxBytes = 0xffffffff;
}
if ( maxBytes < MAX_TCP ) {
errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP );
rsrvSizeofLargeBufTCP = MAX_TCP;
}
else {
rsrvSizeofLargeBufTCP = maxBytes;
}
}
freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 );
ellInit ( &beaconAddrList );
prsrv_cast_client = NULL;
pCaBucket = NULL;
tid = epicsThreadCreate ("CAS-TCP",
tid = epicsThreadCreate ( "CAS-TCP",
epicsThreadPriorityChannelAccessServer,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC)req_server,0);
(EPICSTHREADFUNC)req_server, 0);
if ( tid == 0 ) {
epicsPrintf ( "CAS: unable to start connection request thread\n" );
}
@@ -483,9 +310,9 @@ LOCAL void log_one_client (struct client *client, unsigned level)
char *pproto;
double send_delay;
double recv_delay;
unsigned long bytes_reserved;
unsigned bytes_reserved;
char *state[] = {"up", "down"};
epicsTimeStamp current;
epicsTimeStamp current;
char clientHostName[256];
ipAddrToDottedIP (&client->addr, clientHostName, sizeof(clientHostName));
@@ -504,12 +331,11 @@ LOCAL void log_one_client (struct client *client, unsigned level)
send_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_send);
recv_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_recv);
printf( "%s(%s): User=\"%s\", V%d.%u, Channel Count=%d\n",
printf( "%s(%s): User=\"%s\", V%s, Channel Count=%d\n",
clientHostName,
client->pHostName,
client->pUserName,
CA_PROTOCOL_VERSION,
client->minor_version_number,
client->pHostName ? client->pHostName : "",
client->pUserName ? client->pUserName : "",
CA_VERSION_STRING ( client->minor_version_number ),
ellCount(&client->addrq));
if (level>=1) {
printf ("\tTask Id=%p, Protocol=%3s, Socket FD=%d\n", client->tid,
@@ -587,11 +413,11 @@ void epicsShareAPI casr (unsigned level)
return;
}
printf ("Channel Access Server V%d.%d\n",
CA_PROTOCOL_VERSION, CA_MINOR_VERSION);
printf ("Channel Access Server V%s\n",
CA_VERSION_STRING ( CA_MINOR_PROTOCOL_REVISION ) );
LOCK_CLIENTQ
client = (struct client *) ellNext (&clientQ);
client = (struct client *) ellNext ( &clientQ );
if (!client) {
printf("No clients connected.\n");
}
@@ -636,72 +462,118 @@ void epicsShareAPI casr (unsigned level)
/*
* destroy_client ()
*/
void destroy_client (struct client *client)
void destroy_client ( struct client *client )
{
if ( ! client ) {
return;
}
if ( client->tid != 0 ) {
taskwdRemove ( client->tid );
}
if ( client->sock != INVALID_SOCKET ) {
if ( socket_close (client->sock) < 0) {
errlogPrintf( "CAS: Unable to close socket\n" );
}
}
if ( client->proto == IPPROTO_TCP ) {
if ( client->send.type == mbtSmallTCP ) {
if ( client->send.buf ) {
freeListFree ( rsrvSmallBufFreeListTCP, client->send.buf );
}
if ( client->recv.buf ) {
freeListFree ( rsrvSmallBufFreeListTCP, client->recv.buf );
}
}
else if ( client->send.type == mbtLargeTCP ) {
if ( client->send.buf ) {
freeListFree ( rsrvLargeBufFreeListTCP, client->send.buf );
}
if ( client->recv.buf ) {
freeListFree ( rsrvLargeBufFreeListTCP, client->recv.buf );
}
}
else {
errlogPrintf ( "Currupt buffer type code during cleanup?\n" );
}
}
else if ( client->proto == IPPROTO_UDP ) {
if ( client->send.buf ) {
free ( client->send.buf );
}
if ( client->recv.buf ) {
free ( client->recv.buf );
}
}
epicsMutexDestroy ( client->eventqLock );
epicsMutexDestroy ( client->addrqLock );
epicsMutexDestroy ( client->putNotifyLock );
epicsMutexDestroy ( client->lock );
epicsEventDestroy ( client->blockSem );
if ( client->pUserName ) {
free ( client->pUserName );
}
if ( client->pHostName ) {
free ( client->pHostName );
}
freeListFree ( rsrvClientFreeList, client );
}
void destroy_tcp_client ( struct client *client )
{
struct event_ext *pevext;
struct channel_in_use *pciu;
int status;
if (!client) {
return;
}
if (client->proto != IPPROTO_TCP) {
errlogPrintf ("CAS: non TCP client delete ignored\n");
return;
if ( CASDEBUG > 0 ) {
errlogPrintf ( "CAS: Connection %d Terminated\n", client->sock );
}
LOCK_CLIENTQ;
ellDelete (&clientQ, &client->node);
UNLOCK_CLIENTQ;
if (CASDEBUG>0) {
errlogPrintf ("CAS: Connection %d Terminated\n", client->sock);
if ( client->evuser ) {
db_event_flow_ctrl_mode_off ( client->evuser );
}
/*
* exit flow control so the event system will
* shutdown correctly
*/
db_event_flow_ctrl_mode_off (client->evuser);
/*
* Server task deleted first since close() is not reentrant
*/
if ( client->tid != 0 ) {
taskwdRemove (client->tid);
}
while(TRUE){
epicsMutexMustLock (client->addrqLock);
pciu = (struct channel_in_use *) ellGet(&client->addrq);
epicsMutexUnlock (client->addrqLock);
if (!pciu) {
while ( TRUE ){
epicsMutexMustLock ( client->addrqLock );
pciu = (struct channel_in_use *) ellGet ( &client->addrq );
epicsMutexUnlock ( client->addrqLock );
if ( ! pciu ) {
break;
}
/*
* put notify in progress needs to be deleted
*/
if (pciu->pPutNotify) {
if (pciu->pPutNotify->busy) {
dbNotifyCancel (&pciu->pPutNotify->dbPutNotify);
if ( pciu->pPutNotify ) {
if ( pciu->pPutNotify->busy ) {
dbNotifyCancel ( &pciu->pPutNotify->dbPutNotify );
}
}
while (TRUE){
while ( TRUE ) {
/*
* AS state change could be using this list
*/
epicsMutexMustLock (client->eventqLock);
epicsMutexMustLock ( client->eventqLock );
pevext = (struct event_ext *) ellGet(&pciu->eventq);
epicsMutexUnlock (client->eventqLock);
if(!pevext){
pevext = (struct event_ext *) ellGet ( &pciu->eventq );
epicsMutexUnlock ( client->eventqLock );
if ( ! pevext ) {
break;
}
if (pevext->pdbev) {
if ( pevext->pdbev ) {
db_cancel_event (pevext->pdbev);
}
freeListFree (rsrvEventFreeList, pevext);
@@ -712,60 +584,242 @@ void destroy_client (struct client *client)
free(pciu->pPutNotify);
}
LOCK_CLIENTQ;
status = bucketRemoveItemUnsignedId (
pCaBucket,
&pciu->sid);
status = bucketRemoveItemUnsignedId ( pCaBucket, &pciu->sid);
UNLOCK_CLIENTQ;
if(status != S_bucket_success){
errPrintf (
status,
__FILE__,
__LINE__,
"Bad id=%d at close",
pciu->sid);
if ( status != S_bucket_success ) {
errPrintf ( status, __FILE__, __LINE__,
"Bad id=%d at close", pciu->sid);
}
status = asRemoveClient(&pciu->asClientPVT);
if(status!=0 && status != S_asLib_asNotActive){
printf("And the status is %x \n", status);
errPrintf(status, __FILE__, __LINE__, "asRemoveClient");
if ( status && status != S_asLib_asNotActive ) {
printf ( "bad asRemoveClient() status was %x \n", status );
errPrintf ( status, __FILE__, __LINE__, "asRemoveClient" );
}
/*
* place per channel block onto the
* free list
*/
freeListFree (rsrvChanFreeList, pciu);
freeListFree ( rsrvChanFreeList, pciu );
}
if ( client->evuser ) {
db_close_events (client->evuser);
}
if (client->sock!=INVALID_SOCKET) {
if ( socket_close (client->sock) < 0) {
errlogPrintf("CAS: Unable to close socket\n");
destroy_client ( client );
}
/*
* create_client ()
*/
struct client * create_client ( SOCKET sock, int proto )
{
struct client *client;
client = freeListCalloc ( rsrvClientFreeList );
if ( ! client ) {
epicsPrintf ("CAS: no space in pool for a new client\n");
return NULL;
}
client->sock = sock;
client->proto = proto;
client->blockSem = epicsEventCreate ( epicsEventEmpty );
client->lock = epicsMutexCreate();
client->putNotifyLock = epicsMutexCreate();
client->addrqLock = epicsMutexCreate();
client->eventqLock = epicsMutexCreate();
if ( ! client->blockSem || ! client->lock || ! client->putNotifyLock ||
! client->addrqLock || ! client->eventqLock ) {
destroy_client ( client );
return NULL;
}
client->pUserName = NULL;
client->pHostName = NULL;
ellInit ( &client->addrq );
ellInit ( &client->putNotifyQue );
memset ( (char *)&client->addr, 0, sizeof (client->addr) );
client->tid = 0;
if ( proto == IPPROTO_TCP ) {
client->send.buf = (char *) freeListCalloc ( rsrvSmallBufFreeListTCP );
client->send.maxstk = MAX_TCP;
client->send.type = mbtSmallTCP;
client->recv.buf = (char *) freeListCalloc ( rsrvSmallBufFreeListTCP );
client->recv.maxstk = MAX_TCP;
client->recv.type = mbtSmallTCP;
}
else if ( proto == IPPROTO_UDP ) {
client->send.buf = malloc ( MAX_UDP_SEND );
client->send.maxstk = MAX_UDP_SEND;
client->send.type = mbtUDP;
client->recv.buf = malloc ( MAX_UDP_RECV );
client->recv.maxstk = MAX_UDP_RECV;
client->recv.type = mbtUDP;
}
if ( ! client->send.buf || ! client->recv.buf ) {
destroy_client ( client );
return NULL;
}
client->send.stk = 0u;
client->send.cnt = 0u;
client->recv.stk = 0u;
client->recv.cnt = 0u;
client->evuser = NULL;
client->disconnect = FALSE;
epicsTimeGetCurrent ( &client->time_at_last_send );
epicsTimeGetCurrent ( &client->time_at_last_recv );
client->minor_version_number = CA_UKN_MINOR_VERSION;
client->recvBytesToDrain = 0u;
return client;
}
void casAttachThreadToClient ( struct client *pClient )
{
pClient->tid = epicsThreadGetIdSelf ();
taskwdInsert ( pClient->tid, NULL, NULL );
}
void casExpandSendBuffer ( struct client *pClient, ca_uint32_t size )
{
if ( pClient->send.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP ) {
char *pNewBuf = ( char * ) freeListCalloc ( rsrvLargeBufFreeListTCP );
memcpy ( pNewBuf, pClient->send.buf, pClient->send.stk );
pClient->send.buf = pNewBuf;
pClient->send.maxstk = rsrvSizeofLargeBufTCP;
pClient->send.type = mbtLargeTCP;
}
}
void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size )
{
if ( pClient->recv.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP ) {
char *pNewBuf = ( char * ) freeListCalloc ( rsrvLargeBufFreeListTCP );
assert ( pClient->recv.cnt >= pClient->recv.stk );
memcpy ( pNewBuf, &pClient->recv.buf[pClient->recv.stk], pClient->recv.cnt - pClient->recv.stk );
pClient->recv.buf = pNewBuf;
pClient->recv.cnt = pClient->recv.cnt - pClient->recv.stk;
pClient->recv.stk = 0u;
pClient->recv.maxstk = rsrvSizeofLargeBufTCP;
pClient->recv.type = mbtLargeTCP;
}
}
/*
* create_tcp_client ()
*/
struct client *create_tcp_client ( SOCKET sock )
{
int status;
struct client *client;
int true = TRUE;
osiSocklen_t addrSize;
unsigned priorityOfEvents;
client = create_client ( sock, IPPROTO_TCP );
if ( ! client ) {
errlogPrintf ("CAS: no space in pool for a new TCP client\n");
return NULL;
}
/*
* see TCP(4P) this seems to make unsolicited single events much
* faster. I take care of queue up as load increases.
*/
status = setsockopt ( sock, IPPROTO_TCP, TCP_NODELAY,
(char *) &true, sizeof (true) );
if (status < 0) {
errlogPrintf ( "CAS: TCP_NODELAY option set failed\n" );
destroy_client ( client );
return NULL;
}
/*
* turn on KEEPALIVE so if the client crashes
* this task will find out and exit
*/
status = setsockopt ( sock, SOL_SOCKET, SO_KEEPALIVE,
(char *) &true, sizeof (true) );
if ( status < 0 ) {
errlogPrintf ( "CAS: SO_KEEPALIVE option set failed\n" );
destroy_client ( client );
return NULL;
}
/*
* some concern that vxWorks will run out of mBuf's
* if this change is made
*
* joh 11-10-98
*/
#if 0
/*
* set TCP buffer sizes to be synergistic
* with CA internal buffering
*/
i = MAX_MSG_SIZE;
status = setsockopt ( sock, SOL_SOCKET, SO_SNDBUF, (char *) &i, sizeof (i) );
if (status < 0) {
errlogPrintf ( "CAS: SO_SNDBUF set failed\n" );
destroy_client ( client );
return NULL;
}
i = MAX_MSG_SIZE;
status = setsockopt ( sock, SOL_SOCKET, SO_RCVBUF, (char *) &i, sizeof (i) );
if (status < 0) {
errlogPrintf ( "CAS: SO_RCVBUF set failed\n" );
destroy_client ( client );
return NULL;
}
#endif
addrSize = sizeof ( client->addr );
status = getpeername ( sock, (struct sockaddr *)&client->addr,
&addrSize );
if ( status < 0 ) {
epicsPrintf ("CAS: peer address fetch failed\n");
destroy_tcp_client (client);
return NULL;
}
client->evuser = (struct event_user *) db_init_events ();
if ( ! client->evuser ) {
errlogPrintf ("CAS: unable to init the event facility\n");
destroy_tcp_client (client);
return NULL;
}
status = db_add_extra_labor_event (client->evuser, write_notify_reply, client);
if (status != DB_EVENT_OK) {
errlogPrintf("CAS: unable to setup the event facility\n");
destroy_tcp_client (client);
return NULL;
}
{
unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
epicsThreadBooleanStatus tbs;
tbs = epicsThreadLowestPriorityLevelAbove ( priorityOfSelf, &priorityOfEvents );
if ( tbs != epicsThreadBooleanStatusSuccess ) {
priorityOfEvents = priorityOfSelf;
}
}
epicsMutexDestroy (client->eventqLock);
epicsMutexDestroy (client->addrqLock);
epicsMutexDestroy (client->putNotifyLock);
epicsMutexDestroy (client->lock);
epicsEventDestroy (client->blockSem);
if (client->pUserName) {
free (client->pUserName);
status = db_start_events ( client->evuser, "CAS-event",
NULL, NULL, priorityOfEvents );
if (status != DB_EVENT_OK) {
errlogPrintf("CAS: unable to start the event facility\n");
destroy_tcp_client (client);
return NULL;
}
if (client->pHostName) {
free (client->pHostName);
if ( CASDEBUG > 0 ) {
char buf[64];
ipAddrToDottedIP ( &client->addr, buf, sizeof(buf) );
errlogPrintf ( "CAS: conn req from %s\n", buf );
}
client->minor_version_number = CA_UKN_MINOR_VERSION;
freeListFree (rsrvClientFreeList, client);
return client;
}
+10 -12
View File
@@ -60,7 +60,7 @@
#include "server.h"
#define TIMEOUT 60.0 /* sec */
#define TIMEOUT 60.0 /* sec */
/*
* clean_addrq
@@ -233,34 +233,33 @@ int cast_server(void)
* possible
*
*/
while (TRUE) {
prsrv_cast_client = create_base_client ();
if (prsrv_cast_client) {
while ( TRUE ) {
prsrv_cast_client = create_client ( IOC_cast_sock, IPPROTO_UDP );
if ( prsrv_cast_client ) {
break;
}
epicsThreadSleep(300.0);
}
prsrv_cast_client->sock = IOC_cast_sock;
prsrv_cast_client->tid = epicsThreadGetIdSelf ();
casAttachThreadToClient ( prsrv_cast_client );
while (TRUE) {
status = recvfrom (
IOC_cast_sock,
prsrv_cast_client->recv.buf,
sizeof(prsrv_cast_client->recv.buf),
prsrv_cast_client->recv.maxstk,
0,
(struct sockaddr *)&new_recv_addr,
&recv_addr_size);
if (status<0) {
epicsPrintf ("CAS: UDP recv error (errno=%s)\n",
SOCKERRSTR(SOCKERRNO));
epicsThreadSleep(1.0);
epicsThreadSleep(1.0);
}
else {
prsrv_cast_client->recv.cnt = (unsigned long) status;
prsrv_cast_client->recv.cnt = (unsigned) status;
prsrv_cast_client->recv.stk = 0ul;
epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv);
epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv);
/*
* If we are talking to a new client flush to the old one
@@ -292,8 +291,7 @@ int cast_server(void)
if (CASDEBUG>2)
count = ellCount (&prsrv_cast_client->addrq);
status = camessage(
prsrv_cast_client,&prsrv_cast_client->recv);
status = camessage ( prsrv_cast_client );
if(status == RSRV_OK){
if(prsrv_cast_client->recv.cnt !=
prsrv_cast_client->recv.stk){
+57 -64
View File
@@ -41,6 +41,7 @@
#include "asLib.h"
#include "dbAddr.h"
#include "dbNotify.h"
#define CA_MINOR_PROTOCOL_REVISION 9
#include "caProto.h"
#include "ellLib.h"
#include "epicsTime.h"
@@ -51,47 +52,38 @@
#define LOCAL static
/* a modified ca header with capacity for large arrays */
typedef struct caHdrLargeArray {
ca_uint32_t m_postsize; /* size of message extension */
ca_uint32_t m_count; /* operation data count */
ca_uint32_t m_cid; /* channel identifier */
ca_uint32_t m_available; /* protocol stub dependent */
ca_uint16_t m_dataType; /* operation data type */
ca_uint16_t m_cmmd; /* operation to be performed */
}caHdrLargeArray;
/*
* !! buf must be the first item in this structure !!
* This guarantees that buf will have 8 byte natural
* alignment
*
* Conversions:
* The contents of message_buffer has to be converted
* from network to host format and vice versa.
* For efficiency reasons, the caHdr structure that's common
* to all messages is converted only once:
* 1) from net to host just after receiving it in camessage()
* 2) from host to net in cas_send_msg()
*
* The remaining message_buffer content, however, is always
* in net format!
*
* The terminating unsigned long pad0 field is there to force the
* The terminating unsigned pad0 field is there to force the
* length of the message_buffer to be a multiple of 8 bytes.
* This is due to the sequential placing of two message_buffer
* structures (trans, rec) within the client structure.
* Eight-byte alignment is required by the Sparc 5 and other RISC
* processors.
*
* CAVEAT: This assumes the following:
* o an array of MAX_MSG_SIZE chars takes a multiple of 8 bytes.
* o four unsigned longs also take up a multiple of 8 bytes
* (usually 2).
* NOTE:
* o we should solve the above message alignment problems by
* allocating the message buffers
*
*/
enum messageBufferType { mbtUDP, mbtSmallTCP, mbtLargeTCP };
struct message_buffer {
char buf[MAX_MSG_SIZE];
unsigned long stk;
unsigned long maxstk;
unsigned long cnt;
unsigned long pad0; /* force 8 byte alignement */
char *buf;
unsigned stk;
unsigned maxstk;
unsigned cnt;
enum messageBufferType type;
};
struct client {
typedef struct client {
ELLNODE node;
struct message_buffer send;
struct message_buffer recv;
@@ -102,8 +94,8 @@ struct client {
ELLLIST addrq;
ELLLIST putNotifyQue;
struct sockaddr_in addr;
epicsTimeStamp time_at_last_send;
epicsTimeStamp time_at_last_recv;
epicsTimeStamp time_at_last_send;
epicsTimeStamp time_at_last_recv;
void *evuser;
char *pUserName;
char *pHostName;
@@ -112,8 +104,9 @@ struct client {
int proto;
epicsThreadId tid;
unsigned minor_version_number;
unsigned recvBytesToDrain;
char disconnect; /* disconnect detected */
};
} client;
/*
@@ -122,8 +115,8 @@ struct client {
typedef struct rsrv_put_notify {
ELLNODE node;
PUTNOTIFY dbPutNotify;
caHdr msg;
unsigned long valueSize; /* size of block pointed to by dbPutNotify */
caHdrLargeArray msg;
unsigned valueSize; /* size of block pointed to by dbPutNotify */
int busy; /* put notify in progress */
} RSRVPUTNOTIFY;
@@ -139,7 +132,7 @@ struct channel_in_use {
RSRVPUTNOTIFY *pPutNotify; /* potential active put notify */
const unsigned cid; /* client id */
const unsigned sid; /* server id */
epicsTimeStamp time_at_creation; /* for UDP timeout */
epicsTimeStamp time_at_creation; /* for UDP timeout */
struct dbAddr addr;
ASCLIENTPVT asClientPVT;
};
@@ -151,7 +144,7 @@ struct channel_in_use {
*/
struct event_ext {
ELLNODE node;
caHdr msg;
caHdrLargeArray msg;
struct channel_in_use *pciu;
struct event_block *pdbev; /* ptr to db event block */
unsigned size; /* for speed */
@@ -173,13 +166,10 @@ struct event_ext {
* for debug-level dependent messages:
*/
#ifdef DEBUG
# define DLOG(level, fmt, a1, a2, a3, a4, a5, a6) \
if (CASDEBUG > level) errlogPrintf (fmt, a1, a2, a3, a4, a5, a6)
# define DBLOCK(level, code) \
if (CASDEBUG > level) { code; }
# define DLOG(LEVEL,ARGSINPAREN) \
if (CASDEBUG > LEVEL) errlogPrintf ARGSINPAREN
#else
# define DLOG(level, fmt, a1, a2, a3, a4, a5, a6)
# define DBLOCK(level, code)
# define DLOG(LEVEL,ARGSINPAREN)
#endif
GLBLTYPE int CASDEBUG;
@@ -194,6 +184,9 @@ GLBLTYPE BUCKET *pCaBucket;
GLBLTYPE void *rsrvClientFreeList;
GLBLTYPE void *rsrvChanFreeList;
GLBLTYPE void *rsrvEventFreeList;
GLBLTYPE void *rsrvSmallBufFreeListTCP;
GLBLTYPE void *rsrvLargeBufFreeListTCP;
GLBLTYPE unsigned rsrvSizeofLargeBufTCP;
#define CAS_HASH_TABLE_SIZE 4096
@@ -202,37 +195,37 @@ GLBLTYPE int casSufficentSpaceInPool;
#define SEND_LOCK(CLIENT) epicsMutexMustLock((CLIENT)->lock)
#define SEND_UNLOCK(CLIENT) epicsMutexUnlock((CLIENT)->lock)
#define EXTMSGPTR(CLIENT)\
((caHdr *) &(CLIENT)->send.buf[(CLIENT)->send.stk])
/*
* ALLOC_MSG get a ptr to space in the buffer
* END_MSG push a message onto the buffer stack
*
*/
#define ALLOC_MSG(CLIENT, EXTSIZE) cas_alloc_msg (CLIENT, EXTSIZE)
#define END_MSG(CLIENT)\
EXTMSGPTR(CLIENT)->m_postsize = CA_MESSAGE_ALIGN(EXTMSGPTR(CLIENT)->m_postsize),\
(CLIENT)->send.stk += sizeof(caHdr) + EXTMSGPTR(CLIENT)->m_postsize
#define LOCK_CLIENTQ epicsMutexMustLock (clientQlock);
#define UNLOCK_CLIENTQ epicsMutexUnlock (clientQlock);
void camsgtask (struct client *client);
void cas_send_msg (struct client *pclient, int lock_needed);
caHdr *cas_alloc_msg (struct client *pclient, unsigned extsize);
int rsrv_online_notify_task (void);
void cac_send_heartbeat (void);
int cast_server (void);
struct client *create_base_client ();
int camessage (struct client *client,
struct message_buffer *recv);
void cas_send_heartbeat (struct client *pc);
void write_notify_reply (void *pArg);
int rsrvCheckPut (const struct channel_in_use *pciu);
struct client *create_client (SOCKET sock);
void destroy_client (struct client *client);
struct client *create_client ();
void destroy_client ( struct client * );
struct client *create_tcp_client ( SOCKET sock );
void destroy_tcp_client ( struct client * );
void casAttachThreadToClient ( struct client * );
int camessage ( struct client *client );
void write_notify_reply ( void *pArg );
int rsrvCheckPut ( const struct channel_in_use *pciu );
/*
* inclming protocol maintetnance
*/
void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size );
/*
* outgoing protocol maintenance
*/
void casExpandSendBuffer ( struct client *pClient, ca_uint32_t size );
int cas_copy_in_header (
struct client *pClient, ca_uint16_t response, ca_uint32_t payloadSize,
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
ca_uint32_t responseSpecific, void **pPayload );
void cas_set_header_cid ( struct client *pClient, ca_uint32_t );
void cas_commit_msg ( struct client *pClient, ca_uint32_t size );
/*
* !!KLUDGE!!