/*************************************************************************\ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* * Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd * * Author Jeffrey O. Hill * johill@lanl.gov * 505 665 1831 */ #include #include #include "epicsGuard.h" #include "epicsVersion.h" #include "errlog.h" #include "addrList.h" #define epicsExportSharedSymbols #define caServerGlobal #include "caServerI.h" #include "beaconTimer.h" #include "beaconAnomalyGovernor.h" #include "casStreamOS.h" #include "casIntfOS.h" // include a version string for POSIX systems static const char pVersionCAS[] = "@(#) " EPICS_VERSION_STRING ", CA Portable Server Library " "Date: Tue 2010-10-05 14:27:37 -0500"; caServerI::caServerI ( caServer & tool ) : adapter (tool), beaconTmr ( * new beaconTimer ( *this ) ), beaconAnomalyGov ( * new beaconAnomalyGovernor ( *this ) ), debugLevel ( 0u ), nEventsProcessed ( 0u ), nEventsPosted ( 0u ), ioInProgressCount ( 0u ) { assert ( & adapter != NULL ); // create predefined event types this->valueEvent = registerEvent ( "value" ); this->logEvent = registerEvent ( "log" ); this->alarmEvent = registerEvent ( "alarm" ); this->locateInterfaces (); if (this->intfList.count()==0u) { errMessage (S_cas_noInterface, "- CA server internals init unable to continue"); throw S_cas_noInterface; } return; } caServerI::~caServerI() { delete & this->beaconAnomalyGov; delete & this->beaconTmr; // delete all clients while ( casStrmClient * pClient = this->clientList.get() ) { delete pClient; } casIntfOS *pIF; while ( ( pIF = this->intfList.get() ) ) { delete pIF; } } void caServerI::destroyClient ( casStrmClient & client ) { { epicsGuard < epicsMutex > locker ( this->mutex ); this->clientList.remove ( client ); } delete & client; } void caServerI::connectCB ( casIntfOS & intf ) { casStreamOS * pClient = intf.newStreamClient ( *this, this->clientBufMemMgr ); if ( pClient ) { { epicsGuard < epicsMutex > locker ( this->mutex ); this->clientList.add ( *pClient ); } pClient->sendVersion (); pClient->flush (); } } void casVerifyFunc ( const char * pFile, unsigned line, const char * pExp ) { fprintf(stderr, "the expression \"%s\" didnt evaluate to boolean true \n", pExp); fprintf(stderr, "and therefore internal problems are suspected at line %u in \"%s\"\n", line, pFile); fprintf(stderr, "Please forward above text to johill@lanl.gov - thanks\n"); } void serverToolDebugFunc (const char *pFile, unsigned line, const char *pComment) { fprintf (stderr, "Bad server tool response detected at line %u in \"%s\" because \"%s\"\n", line, pFile, pComment); } caStatus caServerI::attachInterface ( const caNetAddr & addrIn, bool autoBeaconAddr, bool addConfigBeaconAddr) { try { casIntfOS * pIntf = new casIntfOS ( *this, this->clientBufMemMgr, addrIn, autoBeaconAddr, addConfigBeaconAddr ); { epicsGuard < epicsMutex > locker ( this->mutex ); this->intfList.add ( *pIntf ); } } catch ( ... ) { return S_cas_bindFail; } return S_cas_success; } void caServerI::sendBeacon ( ca_uint32_t beaconNo ) { epicsGuard < epicsMutex > locker ( this->mutex ); tsDLIter < casIntfOS > iter = this->intfList.firstIter (); while ( iter.valid () ) { iter->sendBeacon ( beaconNo ); iter++; } } void caServerI::generateBeaconAnomaly () { this->beaconAnomalyGov.start (); } void caServerI::destroyMonitor ( casMonitor & mon ) { mon.~casMonitor (); this->casMonitorFreeList.release ( & mon ); } void caServerI::updateEventsPostedCounter ( unsigned nNewPosts ) { epicsGuard < epicsMutex > guard ( this->diagnosticCountersMutex ); this->nEventsPosted += nNewPosts; } unsigned caServerI::subscriptionEventsPosted () const { epicsGuard < epicsMutex > guard ( this->diagnosticCountersMutex ); return this->nEventsPosted; } void caServerI::incrEventsProcessedCounter () { epicsGuard < epicsMutex > guard ( this->diagnosticCountersMutex ); this->nEventsProcessed ++; } unsigned caServerI::subscriptionEventsProcessed () const { epicsGuard < epicsMutex > guard ( this->diagnosticCountersMutex ); return this->nEventsProcessed; } void caServerI::show (unsigned level) const { int bytes_reserved; printf ( "Channel Access Server V%s\n", CA_VERSION_STRING ( CA_MINOR_PROTOCOL_REVISION ) ); printf ( "\trevision %s\n", pVersionCAS ); this->mutex.show(level); { epicsGuard < epicsMutex > locker ( this->mutex ); tsDLIterConst < casStrmClient > iterCl = this->clientList.firstIter (); while ( iterCl.valid () ) { iterCl->show ( level ); ++iterCl; } tsDLIterConst < casIntfOS > iterIF = this->intfList.firstIter (); while ( iterIF.valid () ) { iterIF->casIntfOS::show ( level ); ++iterIF; } } bytes_reserved = 0u; #if 0 bytes_reserved += sizeof(casClient) * ellCount(&this->freeClientQ); bytes_reserved += sizeof(casChannel) * ellCount(&this->freeChanQ); bytes_reserved += sizeof(casEventBlock) * ellCount(&this->freeEventQ); bytes_reserved += sizeof(casAsyncIIO) * ellCount(&this->freePendingIO); #endif if (level>=1) { printf( "There are currently %d bytes on the server's free list\n", bytes_reserved); #if 0 printf( "%d client(s), %d channel(s), %d event(s) (monitors), and %d IO blocks\n", ellCount(&this->freeClientQ), ellCount(&this->freeChanQ), ellCount(&this->freeEventQ), ellCount(&this->freePendingIO)); #endif printf( "The server's integer resource id conversion table:\n"); } return; } casMonitor & caServerI::casMonitorFactory ( casChannelI & chan, caResId clientId, const unsigned long count, const unsigned type, const casEventMask & mask, casMonitorCallbackInterface & cb ) { casMonitor * pMon = new ( this->casMonitorFreeList ) casMonitor ( clientId, chan, count, type, mask, cb ); return *pMon; } void caServerI::casMonitorDestroy ( casMonitor & cm ) { cm.~casMonitor (); this->casMonitorFreeList.release ( & cm ); } // // caServerI::dumpMsg() // // Debug aid - print the header part of a message. // // dp arg allowed to be null // // void caServerI::dumpMsg ( const char * pHostName, const char * pUserName, const caHdrLargeArray * mp, const void * /* dp */, const char * pFormat, ... ) { va_list theArgs; if ( pFormat ) { va_start ( theArgs, pFormat ); errlogPrintf ( "CAS: " ); errlogVprintf ( pFormat, theArgs ); va_end ( theArgs ); } fprintf ( stderr, "CAS Request: %s on %s: cmd=%u cid=%u typ=%u cnt=%u psz=%u avail=%x\n", pUserName, pHostName, mp->m_cmmd, mp->m_cid, mp->m_dataType, mp->m_count, mp->m_postsize, mp->m_available); //if ( mp->m_cmmd == CA_PROTO_WRITE && mp->m_dataType == DBR_STRING && dp ) { // errlogPrintf("CAS: The string written: %s \n", (char *)dp); //} } casEventRegistry::~casEventRegistry() { this->traverse ( &casEventMaskEntry::destroy ); }