⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gatevc.cc

📁 EPICS CA gateway, base on channel access protocol
💻 CC
📖 第 1 页 / 共 3 页
字号:
/*************************************************************************\* 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 + -