📄 lopcser.cpp
字号:
/**************************************************************************
* *
* Light OPC Server development library *
* *
* Copyright (c) 2000 by Timofei Bondarenko, Kostya Volovich *
*
Main part of LightOPCServer
**************************************************************************/
#include <wchar.h> /* swprintf() */
#include <stdio.h> /* sprintf() */
#include <errno.h>
#include "privopc.h"
//#include "connpnt.h"
#if 0
#include <malloc.h>
#define LO_HEAPCHECK(pp) { int hc; if (_HEAPOK != (hc = _heapchk())) \
UL_ERROR((LOGID, "heapchk() %d %p %s %d", hc, pp, __FILE__, __LINE__)); }
#else
#define LO_HEAPCHECK(pp)
#endif
static const struct
{
char build[10];
char date[32];
} identify =
#define sh(v,x) ('0' + (v >> x & 15))
#define stri(v) sh(v,28),sh(v,24),sh(v,20),sh(v,16),sh(v,12),sh(v,8),sh(v,4),sh(v,0)
{ { '\r', '\n', stri(LIGHTOPC_H) }, " " __DATE__ " " __TIME__ " sign @\r\n" };
/*********************************** LightOPCServer:: stuff **************************/
#define ifATTACHED (1<< 0)
#define ifLKALL (1<< 1)
#define ifLKBROWSE (1<< 2)
#define ifLKASYNC (1<< 3)
#define ifLKREMOVE (1<< 4)
#define ifREQQUEUE (1<< 5)
#define ifRETQUEUE (1<< 7)
#define ifOBJTRACK (1<< 8)
//#define ifLKVALUES (1<<4)
#if ifATTACHED & loDf_BOTHMODEL
#error LightOPCGroup::initphase flags conflict
#endif
int LightOPCServer::lock_state(const char *msg, const IID *riid_nostrict)
{
LO_HEAPCHECK(this);
UL_DEBUG((LOGID, "Entering <%s>...", msg? msg: ""));
if (loIS_VALID(this))
{
if (!otrk.ot_stopped || riid_nostrict && (!shuttingdown ||
#if LO_USE_FREEMARSHALL
IsEqualIID(*riid_nostrict, IID_IMarshal) ||
#endif
IsEqualIID(*riid_nostrict, IID_IUnknown) ) )
{
InterlockedIncrement(&RefCount);
return 0;
}
}
if (riid_nostrict)
{
char ifa[40];
UL_NOTICE((LOG_SR("Server::<%s> interface %s closed: va=%d st=%d sd=%d rc=%d"),
msg? msg: "", loTranslateIID(ifa, sizeof(ifa), riid_nostrict),
loIS_VALID(this), otrk.ot_stopped, shuttingdown, RefCount));
}
else UL_WARNING((LOG_SR("Server::<%s> interface closed"), msg? msg: ""));
return -1;
}
static lw_thrrettype run_client_scheduler(void *cli)
{
UL_NOTICE((LOGID, "client_scheduler(%p) starting...", cli));
if (cli /*loIS_VALID(cli)*/)
((LightOPCServer*)cli)->client_scheduler();
/* when "self-stopping" is actual loIS_VALID() will return 0 */
UL_TRACE((LOGID, "client_scheduler(%p) exiting...", cli));
lw_RETURN;
}
LightOPCServer::LightOPCServer()
{
iam = 0;
initphase = 0;
glGrowList_init(&grl);
ldFlags = 0;
access_mode = loAM_RDWR;
qi_chain = 0;
se = 0;
release_handle = 0;
release_handle_arg = 0;
unique_GroupName = 0;
unique_GroupHandle = 0;
loStringBuf_init(&browsepos);
serv_next = 0; serv_key = 0;
shuttingdown = 0;
otrk.ot_stopped = 0;
#if LO_USE_FREEMARSHALL
freemarsh = 0;
#endif
#if LO_USE_BOTHMODEL
ole_initialized = 0;
lml_rd_lock = lw_rw_timedrdlock;
lml_wr_lock = lw_rw_timedwrlock;
#endif
/* IUnknown implementation */
RefCount = 0;
/* IOPCCommon implementation */
client_name[1] = identify.build[8];
memset(&ctxt, 0, sizeof(ctxt));
/* ctxt.cta.vc_lcid = 0;
ctxt.cta.vc_tfl = 0; *//* VariantChangeType() flags:
VARIANT_ALPHABOOL | VARIANT_LOCALBOOL |
VARIANT_NOUSEROVERRIDE | VARIANT_NOVALUEPROP */
memset(client_name, 0, sizeof(client_name));
// *client_name = '-';
sprintf(client_name, "[%03X:%03X]", 0xffff & (unsigned)GetCurrentProcessId(),
0xffff & (unsigned)this);
/* IConnectionPoint methods */
loShutdownConn_init(&shutdown_conn);
/* OPCSERVERSTATUS */
memset(&ostatus, 0, sizeof(ostatus));
ostatus.dwBandWidth = 0xffffffff;
bandwidth_time = 0;
iam = this; /****/
}
int LightOPCServer::initialize(loService *serv, int ld_flags,
const loVendorInfo *vi)
{
int err = 0;
if (!loIS_VALID(this) || se ||
ostatus.szVendorInfo || initphase) return EINVAL;
if (!loSERVICE_OK(serv)) { err = EINVAL; goto Fail; }
se = serv;
ctxt.cactx = se->cactx;
// ctxt.cactx.ca_cli = this;
ldFlags = ld_flags | se->driver.ldFlags;
if (ld_flags & loDf_FREEMODEL) ldFlags &= ~loDf_BOTHMODEL;
#if LO_USE_BOTHMODEL
if (ldFlags & loDf_BOTHMODEL)
{
lml_rd_lock = lw_rw_timedrdlock_lml;
lml_wr_lock = lw_rw_timedwrlock_lml;
}
#endif
if (vi)
{
ostatus.wMajorVersion = vi->lviMajor;
ostatus.wMinorVersion = vi->lviMinor;
ostatus.wBuildNumber = vi->lviBuild;
ostatus.wReserved = vi->lviReserv;
if (vi->lviInfo &&
!(ostatus.szVendorInfo = loMWstrdup(vi->lviInfo)))
{ err = ENOMEM; goto Fail; }
}
se->driver.ldCurrentTime(&ctxt.cactx, &ostatus.ftStartTime);
ostatus.dwServerState = OPC_STATUS_NOCONFIG;
if (err = lw_rwlock_init(&lk_all, 0)) goto Fail;
initphase |= ifLKALL;
if (err = lw_rwlock_init(&lk_remove, 0)) goto Fail;
initphase |= ifLKREMOVE;
if (err = lw_mutex_init(&lk_browse, 0)) goto Fail;
initphase |= ifLKBROWSE;
if (err = loQueueBcast_init(&q_ret, ldFlags & loDf_BOTHMODEL)) goto Fail;
initphase |= ifRETQUEUE;
if (err = loQueueAsync_init(&q_req, &async, se->driver.ldQueueMax)) goto Fail;
initphase |= ifREQQUEUE;
if (err = loThrControl_init(&async)) goto Fail;
initphase |= ifLKASYNC;
#if LO_USE_OBJTRACK
if (err = lw_rmutex_init(&otrk.ot_lk, 0)) goto Fail;
initphase |= ifOBJTRACK;
#endif
#if LO_USE_FREEMARSHALL
if (/*se->driver.*/ldFlags & loDf_FREEMARSH)
CoCreateFreeThreadedMarshaler((IOPCServer*)this, &freemarsh);
UL_DEBUG((LOGID, "LightOPCServer( free marsh %p)",freemarsh));
/* there are nothing bad if it fails */
#endif
/* final step */
// iam = this;
Fail:
UL_TRACE((LOGID, "%!e LightOPCServer(%ls)", err, loWnul(ostatus.szVendorInfo)));
return err;
}
void LightOPCServer::selfdestroy(void)
{
#if 0
void (*rh)(void *, loService *, loClient *) = release_handle; release_handle = 0;
void *rha = release_handle_arg; release_handle_arg = 0;
loService *service = se;
loClient *client = (loClient*)this;
delete this;
if (rh) rh(rha, service, client); /* When we should call release_handle() ? */
#else
delete this;
#endif
}
#define loDf_ALL (loDf_DWG | loDf_NOFORCE | loDf_EE_SFALSE |\
loDf_FREEMARSH|loDf_BOTHMODEL|loDf_FREEMODEL)
int loClientCreate_agg(loService *se, loClient **cli,
IUnknown *outer, IUnknown **inner,
int ldFlags,
const loVendorInfo *vi,
void (*release_handle)(void *, loService *, loClient *),
void *release_handle_arg)
{
int rv = 0;
LightOPCServer *srv;
if (cli) *cli = 0;
if (inner) *inner = 0;
if (!cli || (ldFlags & ~loDf_ALL)) return EINVAL;
if (!loSERVICE_OK(se)) return EBADF;
/******************************************************************/
class LightOPCServer_aggregator: public LightOPCServer
{
public:
class LightOPCServer_delegator: public IUnknown
{
public:
LightOPCServer *inner;
STDMETHOD_ (ULONG, AddRef)(void) { return inner->LightOPCServer::AddRef(); }
STDMETHOD_ (ULONG, Release)(void) { return inner->LightOPCServer::Release(); }
STDMETHOD (QueryInterface)(REFIID riid, void **ppv)
{
if (IsEqualIID(riid, IID_IUnknown))
{ *ppv = (void*)this; AddRef(); return S_OK; }
return inner->LightOPCServer::QueryInterface(riid, ppv);
}
} delegator;
IUnknown *outer;
STDMETHOD_ (ULONG, AddRef)(void) { return outer->AddRef(); }
STDMETHOD_ (ULONG, Release)(void) { return outer->Release(); }
STDMETHOD (QueryInterface)(REFIID riid, void **ppv)
{ return outer->QueryInterface(riid, ppv); }
LightOPCServer_aggregator(IUnknown *Outer)
{ delegator.inner = this; outer = Outer; }
} *agg = 0;
/******************************************************************/
if (outer)
{
if (!inner) return EINVAL;
agg = new LightOPCServer_aggregator(outer);
if (srv = agg) agg->delegator.AddRef();
else return ENOMEM;
}
else if (srv = new LightOPCServer) srv->AddRef();
else return ENOMEM;
if ((rv = srv->initialize(se, ldFlags, vi)))
{
UL_ERROR((LOGID, "%!e loClientCreate()::initialize(%p) FAILED", rv, srv));
}
else if ((rv = srv->attach())/* && loIS_VALID(srv)*/)
{
UL_ERROR((LOGID, "%!e loClientCreate()::attach(%p) FAILED", rv, srv));
}
else
{
srv->release_handle = release_handle;
srv->release_handle_arg = release_handle_arg;
srv->ctxt.cactx.ca_cli_arg = release_handle_arg;
srv->ctxt.cactx.ca_cli = srv;
*cli = srv;
if (agg) *inner = &agg->delegator;
return 0; /*** Success ***/
}
//srv->Release(); /* Release doesn't check for initialize() faults*/
delete srv;
return rv;
}
int loClientCreate(loService *se, loClient **cli, int ldFlags,
const loVendorInfo *vi,
void (*release_handle)(void *, loService *, loClient *),
void *release_handle_arg)
{
return loClientCreate_agg(se, cli, NULL, NULL,
ldFlags, vi,
release_handle, release_handle_arg);
}
int loClientChain(loClient *cli,
HRESULT (*qi_chain)(void *rha, loService *, loClient *,
const IID *, LPVOID *),
void (*release_handle)(void *rha, loService *, loClient *),
void *release_handle_arg)
{
if (!loIS_VALID(cli)) return EBADF;
cli->qi_chain = qi_chain;
cli->ctxt.cactx.ca_cli_arg = release_handle_arg;
cli->release_handle_arg = release_handle_arg;
cli->release_handle = release_handle;
return 0;
}
int loClientAccessMode(loService *se, loClient *cli, int accmode)
{
int rv = EBADF;
if (accmode != loAM_RDWR &&
(accmode & ~(loAM_RDONLY_OP | loAM_RDONLY_ADD | loAM_RDONLY_BROWSE |
loAM_NOREAD_DEV | loAM_ERREAD_DEV))) return EINVAL;
if (loSERVICE_OK(se))
{
lw_mutex_lock(&se->lkList);
if (!se->shutdown)
{
LightOPCServer *los = (LightOPCServer*)se->servlist;
for(rv = ENOENT; los; los = los->serv_next)
if (!cli || los == cli)
{
los->access_mode = accmode;
rv = 0;
}
}
lw_mutex_unlock(&se->lkList);
}
return rv;
}
LightOPCServer::~LightOPCServer()
{
iam = 0;
if (!otrk.ot_stopped) otrk.ot_stopped = 1;
UL_TRACE((LOG_SR("~LightOPCServer(%ls)"), loWnul(ostatus.szVendorInfo)));
LO_HEAPCHECK(this);
if (initphase & ifLKASYNC)
{
loThrControl_stop(&async);
loQueueBcast_abort(&q_ret);
loQueueAsync_clear(&q_req);
}
if (grl.gl_count)
UL_WARNING((LOG_SR("Still unreleased %d groups"), grl.gl_count));
if (shutdown_conn.request)
UL_WARNING((LOG_SR("Unsafe Shutdown notification aborted")));
// loShutdownConn_call(&shutdown_conn);
loShutdownConn_clear(&shutdown_conn);
if (initphase & ifATTACHED)
{
loQueueBcast_abort(&q_ret);
/* clear_all(); - performed in detach() */
detach(); initphase &= ~ifATTACHED;
}
if ((initphase & ifOBJTRACK) && otrk.ot_disconnect_all(1))
UL_WARNING((LOG_SR("Some Enumerators left unreleased")));
#if LO_USE_FREEMARSHALL
if (freemarsh) { freemarsh->Release(); freemarsh = 0; }
#endif
if (initphase & ifRETQUEUE)
{
loQueueBcast_destroy(&q_ret); initphase &= ~ifRETQUEUE;
}
if (initphase & ifREQQUEUE)
{
loQueueAsync_destroy(&q_req); initphase &= ~ifREQQUEUE;
}
if (initphase & ifLKASYNC)
{
loThrControl_destroy(&async); initphase &= ~ifLKASYNC;
}
if (initphase & ifLKALL)
{
lw_rwlock_destroy(&lk_all); initphase &= ~ifLKALL;
}
if (initphase & ifLKREMOVE)
{
lw_rwlock_destroy(&lk_remove); initphase &= ~ifLKREMOVE;
}
if (initphase & ifLKBROWSE)
{
lw_mutex_destroy(&lk_browse); initphase &= ~ifLKBROWSE;
}
#if LO_USE_OBJTRACK
if (initphase & ifOBJTRACK)
{
lw_rmutex_destroy(&otrk.ot_lk); initphase &= ~ifOBJTRACK;
}
#endif
del_all();
loStringBuf_clear(&browsepos);
if (ostatus.szVendorInfo) freeX(ostatus.szVendorInfo), ostatus.szVendorInfo = 0;
#if LO_USE_BOTHMODEL
if (ole_initialized)
UL_ERROR((LOGID, "OLE didn't uninitialized!"));
#endif
if (initphase)
UL_ERROR((LOGID, "Left unreleased: 0x%X", initphase));
loShutdownConn_clear(&shutdown_conn);
glGrowList_clear(&grl);
if (release_handle) release_handle(release_handle_arg, se, (loClient*)this),
release_handle = 0;
LO_HEAPCHECK(this);
}
void LightOPCServer::clear_all(void)
{
// if (initphase & ifLKBROWSE)
{
lw_mutex_lock(&lk_browse);
loStringBuf_clear(&browsepos);
lw_mutex_unlock(&lk_browse);
}
// else if (br_position) freeX(br_position), br_position = 0, br_size = 0;
loQueueAsync_clear(&q_req);
loQueueBcast_abort(&q_ret);
// if (initphase & ifLKALL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -