📄 gatevc.cc
字号:
/*************************************************************************\* Copyright (c) 2002 The University of Chicago, as Operator of Argonne* National Laboratory.* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron-* Strahlung mbH (BESSY).* Copyright (c) 2002 The Regents of the University of California, as* Operator of Los Alamos National Laboratory.* This file is distributed subject to a Software License Agreement found* in the file LICENSE that is included with this distribution. \*************************************************************************//*+********************************************************************* * * File: gateVc.cc * Project: CA Proxy Gateway * * Descr.: VC = Server tool side (upper half) of Proxy Gateway * Variable. Handles all CAS related stuff: * - Satisfies CA Server API * - Keeps graphic enum, value and ALH data * - Keeps queues for async read and write operations * * Author(s): J. Kowalkowski, J. Anderson, K. Evans (APS) * R. Lange (BESSY) * *********************************************************************-*/#define DEBUG_STATE 0#define DEBUG_VC_DELETE 0#define DEBUG_GDD 0#define DEBUG_EVENT_DATA 0#define DEBUG_ENUM 0#define DEBUG_TIMESTAMP 0#define DEBUG_RTYP 0#define DEBUG_DELAY 0#define DEBUG_ACCESS 0#define DEBUG_SLIDER 0#include <stdio.h>#include <string.h>#include <time.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef WIN32#else# include <unistd.h>#endif#include <gdd.h>#include <gddApps.h>#include <dbMapper.h>#include "gateResources.h"#include "gateServer.h"#include "gateVc.h"#include "gatePv.h"#include "gateAs.h"// Static initializationsunsigned long gateVcData::nextID=0;// ---------------------------- utilities ------------------------------------void heading(const char *funcname, const char *pvname){// if(strcmp(pvname,"evans:perf:c3.SCAN")) return; fflush(stderr); printf("\n[%s] %s %s\n",timeStamp(),funcname,pvname); fflush(stdout);}void dumpdd(int step, const char *desc, const char * /*name*/, const gdd *dd){// if(strcmp(name,"evans:perf:c3.SCAN")) return; fflush(stderr); printf("(%d) ***********************************************************\n", step); if (!dd) { printf("%-25s ===== no gdd here (NULL pointer) =====\n", desc); } else { printf("%-25s at=%d[%s] pt=%d[%s]\n", desc, dd->applicationType(), gddApplicationTypeTable::AppTable().getName(dd->applicationType()), dd->primitiveType(), aitName[dd->primitiveType()] ); fflush(stdout); dd->dump(); fflush(stderr); } fflush(stdout);}// ------------------------gateChan// gateChan has the common part of a casChannel, primarily access// security. gateVcChan is derived for specific use with gateVcData// and gateStatChan is derived for specific use with gateStat.// casPv is set in the constructor to the incoming casPv. The// derived-class constructor adds the derived gateChan to the// chan_list in the casPv. casPv is set to NULL when the casPv// removes it from its chan_list in the casPv destructor. This// prevents anyone, including the server, from calling removeChan when// the casPv is gone.// The caller must provide storage for user and host in asAddClient in// gateAsClient::gateAsClient. We assume this storage is in the// server and just keep pointers to it.gateChan::gateChan(const casCtx &ctx, casPV *casPvIn, gateAsEntry *asentry, const char * const userIn, const char * const hostIn) : casChannel(ctx), casPv(casPvIn), user(userIn), host(hostIn){ asclient=new gateAsClient(asentry,user,host); if(asclient) asclient->setUserFunction(post_rights,this);}gateChan::~gateChan(void){ deleteAsClient();}#ifdef SUPPORT_OWNER_CHANGE// Virtual function from casChannel, not called from Gateway. It is a// security hole to support this, and it is no longer implemented in// base.void gateChan::setOwner(const char* const u, const char* const h){ asclient->changeInfo(u,h);}#endif// Access security userFunc that calls postAccessRightsEvent in the// server. The server then notifies its clients. With MEDM, for// example, if there is no write access, it would then display a// circle with a bar. The values of read and write access are not// stored in the server, but rather readAcess() or writeAcccess() is// called before each operation.void gateChan::post_rights(void* userPvt){#if DEBUG_ACCESS printf("gateChan::post_rights:\n");#endif gateChan *pChan = (gateChan *)userPvt; // Do not post the event if the casPv is NULL, which means the // gateChan has been removed from the gateVcData::chan_list which // means the gateChan is not relevant anymore, even though it may // not yet have been destroyed. Actually, post_rights should not // be called if casPv is NULL since the asclient should also have // been destroyed in that event, but it is a safety feature. if(pChan && pChan->getCasPv()) { pChan->postAccessRightsEvent(); }}void gateChan::report(FILE *fp){ fprintf(fp," %s@%s (%s access)\n",getUser(),getHost(), readAccess()?(writeAccess()?"read/write":"read only"):"no");}void gateChan::resetAsClient(gateAsEntry *asentry){#if DEBUG_ACCESS printf("gateChan::addAsClient asentry=%p asclient=%p\n", asentry,asclient);#endif if(asclient) { delete asclient; asclient=NULL; } // Don't do anything else if the casPv is NULL, indicating it is // being destroyed or if the asentry is NULL if(!casPv || !asentry) return; asclient=new gateAsClient(asentry,user,host); if(asclient) { asclient->setUserFunction(post_rights,this); }#if DEBUG_ACCESS printf("user=%s host=%s asentry=%p asclient=%p\n", user,host,asclient); report(stdout);#endif // Notify the server. postAccessRightsEvent() just causes the // server to notify its clients. The access is not stored in the // server, but rather readAcess() or writeAcccess() is called // before each operation. postAccessRightsEvent();}void gateChan::deleteAsClient(void){ if(asclient) { delete asclient; asclient = NULL; }}// ------------------------gateVcChangateVcChan::gateVcChan(const casCtx &ctx, casPV *casPvIn, gateAsEntry *asentry, const char * const user, const char * const host) : gateChan(ctx,casPvIn,asentry,user,host){ gateVcData *vc=(gateVcData *)casPv; if(vc) vc->addChan(this);}gateVcChan::~gateVcChan(void){ gateVcData *vc=(gateVcData *)casPv; if(vc) vc->removeChan(this);}// This is a new virtual write in CAS that knows the casChannel. The// casPV::write() is not called if this one is implemented. This// write calls a new, overloaded gateVcData::write() that has the// gateChan as an argument to do what used to be done in the virtual// gateVcData::write().caStatus gateVcChan::write(const casCtx &ctx, const gdd &value){ gateVcData *vc=(gateVcData *)casPv; // Trap writes if(asclient && asclient->clientPvt()->trapMask) { FILE *fp=global_resources->getPutlogFp(); if(fp) { fprintf(fp,"%s %s@%s %s\n", timeStamp(), user?user:"Unknown", host?host:"Unknown", vc && vc->getName()?vc->getName():"Unknown"); fflush(fp); } } // Call the non-virtual-function write() in the gateVcData if(vc) return vc->write(ctx,value,*this); else return S_casApp_noSupport;}// Called from the server to determine access before each readbool gateVcChan::readAccess(void) const{ gateVcData *vc=(gateVcData *)casPv;#if DEBUG_ACCESS && 0 printf("gateVcChan::readAccess: %s asclient=%p ret=%d\n", vc?vc->getName():"NULL VC",asclient, (asclient && asclient->readAccess() && vc && vc->readAccess())?1:0);#endif return (asclient && asclient->readAccess() && vc && vc->readAccess())? true:false;}// Called from the server to determine access before each writebool gateVcChan::writeAccess(void) const{ gateVcData *vc=(gateVcData *)casPv;#if DEBUG_ACCESS && 0 printf("gateVcChan::writeAccess: %s asclient=%p ret=%d\n", vc?vc->getName():"NULL VC",asclient, (asclient && asclient->writeAccess() && vc && vc->writeAccess())?1:0);#endif return (asclient && asclient->writeAccess() && vc && vc->writeAccess())? true:false;}// ------------------------gateVcDatagateVcData::gateVcData(gateServer* m,const char* name) : casPV(*m), pv(NULL), vcID(nextID++),#if 0 event_count(0),#endif read_access(aitTrue),#if 0 //KE: Unused time_last_trans(0), time_last_alh_trans(0),#endif status(0), asentry(NULL), pv_state(gateVcClear), mrg(m), pv_name(strDup(name)), in_list_flag(0), prev_post_value_changes(0), post_value_changes(0), pending_write(NULL), pv_data(NULL), event_data(NULL){ gateDebug2(5,"gateVcData(gateServer=%p,name=%s)\n",(void *)m,name); select_mask|=(mrg->alarmEventMask()| mrg->valueEventMask()| mrg->logEventMask()); alh_mask|=mrg->alarmEventMask(); // Important Note: The exist test should have been performed for this // PV already, which means that the gatePvData exists and is connected // at this point, so it should be present on the pv list if(mrg->pvFind(pv_name,pv)==0) { // Activate could possibly perform get for pv_data and event_data // before returning here. Be sure to mark this state connecting // so that everything works out OK in this situation. setState(gateVcConnect); asentry=pv->getEntry(); if(pv->activate(this)==0) { mrg->vcAdd(pv_name,*this); markInList(); // set state to gateVcConnect used to be here } else status=1; } else status=1;#ifdef STAT_PVS mrg->setStat(statVcTotal,++mrg->total_vc);#endif}gateVcData::~gateVcData(void){#if DEBUG_VC_DELETE printf("gateVcData::~gateVcData %s\n",pv?pv->name():"NULL");#endif gateDebug0(5,"~gateVcData()\n"); gateVcData* x; if(in_list_flag) mrg->vcDelete(pv_name,x);// Clean up the pending write. The server library destroys the// asynchronous io before destroying the casPV which results in// calling this destructor. For this reason we do not have to worry// about it. Moreover, it will cause a core dump if we call// pending_write->postIOCompletion(S_casApp_canceledAsyncIO) here,// because the asynchronous io is gone. Just null the pointer. if(pending_write) pending_write=NULL; if(pv_data) { pv_data->unreference(); pv_data=NULL; } if(event_data) { event_data->unreference(); event_data=NULL; } delete [] pv_name; pv_name="Error"; if (pv) pv->setVC(NULL); // Clear the chan_list to insure the gateChan's do not call the // gateVcData to remove them after the gateVcData is // gone. removeChan also sets the pChan->vc to NULL, the only // really necessary thing to do. gateVcChan *pChan; while((pChan=chan_list.first())) { removeChan(pChan); pChan->deleteAsClient(); } // Clear the async io lists to insure the gateAsyncX's do not try // to remove themselves from the lists after the gateVcData and // the lists are gone. removeFromQueue sets the pointer to the // list in the gateAsyncX to NULL. gateAsyncW* asyncw; while((asyncw=wio.first())) { asyncw->removeFromQueue(); } gateAsyncR* asyncr; while((asyncr=rio.first())) { asyncr->removeFromQueue(); } while((asyncr=alhRio.first())) { asyncr->removeFromQueue(); }#ifdef STAT_PVS mrg->setStat(statVcTotal,--mrg->total_vc);#endif}const char* gateVcData::getName() const{ return name();}// This is called whenever CAS want to destroy your casPV, usually// because all clients have disconnectedvoid gateVcData::destroy(void){ gateDebug0(1,"gateVcData::destroy()\n");#if DEBUG_VC_DELETE printf("gateVcData::destroy %s\n",pv?pv->name():"NULL");#endif vcRemove(); casPV::destroy();}casChannel* gateVcData::createChannel(const casCtx &ctx, const char * const user, const char * const host){ gateDebug0(5,"gateVcData::createChannel()\n"); gateVcChan* chan = new gateVcChan(ctx,this,asentry,user,host); return chan;}void gateVcData::report(FILE *fp){ fprintf(fp,"%-30s event rate = %5.2f\n",pv_name,pv->eventRate()); tsDLIter<gateVcChan> iter=chan_list.firstIter(); while(iter.valid()) { iter->report(fp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -