many changes
This commit is contained in:
@@ -30,8 +30,6 @@
|
||||
|
||||
epicsThreadPrivateId caClientContextId;
|
||||
|
||||
epicsThreadPrivateId cacRecursionLock;
|
||||
|
||||
static epicsThreadOnceId caClientContextIdOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
extern "C" void ca_client_exit_handler ()
|
||||
@@ -56,8 +54,6 @@ extern "C" void ca_init_client_context ( void * )
|
||||
*/
|
||||
int fetchClientContext ( cac **ppcac )
|
||||
{
|
||||
int status;
|
||||
|
||||
if ( caClientContextId == 0 ) {
|
||||
epicsThreadOnce ( &caClientContextIdOnce, ca_init_client_context, 0 );
|
||||
if ( caClientContextId == 0 ) {
|
||||
@@ -65,6 +61,7 @@ int fetchClientContext ( cac **ppcac )
|
||||
}
|
||||
}
|
||||
|
||||
int status;
|
||||
*ppcac = ( cac * ) epicsThreadPrivateGet ( caClientContextId );
|
||||
if ( *ppcac ) {
|
||||
status = ECA_NORMAL;
|
||||
@@ -229,10 +226,8 @@ extern "C" int epicsShareAPI ca_search_and_connect (
|
||||
const char *name_str, chid *chanptr,
|
||||
caCh *conn_func, void *puser )
|
||||
{
|
||||
int caStatus;
|
||||
cac *pcac;
|
||||
|
||||
caStatus = fetchClientContext ( &pcac );
|
||||
int caStatus = fetchClientContext ( &pcac );
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -267,7 +262,23 @@ extern "C" int epicsShareAPI ca_search_and_connect (
|
||||
extern "C" int epicsShareAPI ca_array_get ( chtype type,
|
||||
unsigned long count, chid pChan, void *pValue )
|
||||
{
|
||||
return pChan->read ( type, count, pValue );
|
||||
cac *pcac;
|
||||
int caStatus = fetchClientContext ( &pcac );
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
|
||||
getCopy *pNotify = new getCopy ( *pcac, type, count, pValue );
|
||||
if ( ! pNotify ) {
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
|
||||
int status = pChan->read ( type, count, *pNotify );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
pNotify->release ();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -352,9 +363,7 @@ extern "C" int epicsShareAPI ca_replace_access_rights_event ( chid pChan, caArh
|
||||
extern "C" int epicsShareAPI ca_add_exception_event ( caExceptionHandler *pfunc, void *arg )
|
||||
{
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
caStatus = fetchClientContext ( &pcac );
|
||||
int caStatus = fetchClientContext ( &pcac );
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -425,23 +434,11 @@ extern "C" int epicsShareAPI ca_add_masked_array_event (
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* ca_clear_event ()
|
||||
*
|
||||
* Cancel an outstanding event for a channel.
|
||||
*
|
||||
* NOTE: returns before operation completes in the server
|
||||
* (and the client).
|
||||
* This is a good reason not to allow them to make the monix
|
||||
* block as part of a larger structure.
|
||||
* Nevertheless the caller is gauranteed that his specified
|
||||
* event is disabled and therefore will not run (from this source)
|
||||
* after leaving this routine.
|
||||
*
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_clear_event ( evid pMon )
|
||||
{
|
||||
pMon->destroy ();
|
||||
pMon->cancel ();
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
@@ -455,24 +452,36 @@ extern "C" chid epicsShareAPI ca_evid_to_chid ( evid pMon )
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_clear_channel ( chid pChan )
|
||||
{
|
||||
pChan->destroy ();
|
||||
delete pChan;
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_pend ()
|
||||
* ca_pend_event ()
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_pend (ca_real timeout, int early)
|
||||
extern "C" int epicsShareAPI ca_pend_event (ca_real timeout)
|
||||
{
|
||||
cac *pcac;
|
||||
int status;
|
||||
|
||||
status = fetchClientContext ( &pcac );
|
||||
int status = fetchClientContext ( &pcac );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return pcac->pend ( timeout, early );
|
||||
return pcac->pendEvent ( timeout );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_pend_io ()
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_pend_io (ca_real timeout)
|
||||
{
|
||||
cac *pcac;
|
||||
int status = fetchClientContext ( &pcac );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return pcac->pendIO ( timeout );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -480,10 +489,8 @@ extern "C" int epicsShareAPI ca_pend (ca_real timeout, int early)
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_flush_io ()
|
||||
{
|
||||
int caStatus;
|
||||
cac *pcac;
|
||||
|
||||
caStatus = fetchClientContext (&pcac);
|
||||
int caStatus = fetchClientContext (&pcac);
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -498,10 +505,8 @@ extern "C" int epicsShareAPI ca_flush_io ()
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_test_io ()
|
||||
{
|
||||
int caStatus;
|
||||
cac *pcac;
|
||||
|
||||
caStatus = fetchClientContext ( &pcac );
|
||||
int caStatus = fetchClientContext ( &pcac );
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -622,9 +627,7 @@ extern "C" void epicsShareAPI ca_signal_formated ( long ca_status, const char *p
|
||||
extern "C" int epicsShareAPI ca_add_fd_registration (CAFDHANDLER *func, void *arg)
|
||||
{
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
caStatus = fetchClientContext ( &pcac );
|
||||
int caStatus = fetchClientContext ( &pcac );
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -672,10 +675,8 @@ extern "C" const char * epicsShareAPI ca_version()
|
||||
*/
|
||||
extern "C" int epicsShareAPI ca_replace_printf_handler (caPrintfFunc *ca_printf_func)
|
||||
{
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
caStatus = fetchClientContext (&pcac);
|
||||
cac *pcac;
|
||||
int caStatus = fetchClientContext (&pcac);
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -769,8 +770,7 @@ extern "C" epicsShareFunc void * epicsShareAPI ca_puser (chid pChan)
|
||||
*/
|
||||
extern "C" epicsShareFunc unsigned epicsShareAPI ca_read_access (chid pChan)
|
||||
{
|
||||
caar ar = pChan->accessRights ();
|
||||
if ( ar.read_access ) {
|
||||
if ( pChan->accessRights ().read_access ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -783,8 +783,7 @@ extern "C" epicsShareFunc unsigned epicsShareAPI ca_read_access (chid pChan)
|
||||
*/
|
||||
extern "C" epicsShareFunc unsigned epicsShareAPI ca_write_access (chid pChan)
|
||||
{
|
||||
caar ar = pChan->accessRights ();
|
||||
if ( ar.write_access ) {
|
||||
if ( pChan->accessRights ().write_access ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -819,9 +818,7 @@ extern "C" epicsShareFunc double epicsShareAPI ca_beacon_period ( chid pChan )
|
||||
extern "C" unsigned epicsShareAPI ca_get_ioc_connection_count ()
|
||||
{
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
caStatus = fetchClientContext (&pcac);
|
||||
int caStatus = fetchClientContext (&pcac);
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
@@ -839,9 +836,7 @@ extern "C" epicsShareFunc int epicsShareAPI ca_channel_status ( epicsThreadId /*
|
||||
extern "C" epicsShareFunc int epicsShareAPI ca_client_status ( unsigned level )
|
||||
{
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
caStatus = fetchClientContext ( &pcac );
|
||||
int caStatus = fetchClientContext ( &pcac );
|
||||
if ( caStatus != ECA_NORMAL ) {
|
||||
return caStatus;
|
||||
}
|
||||
|
||||
193
src/ca/cac.cpp
193
src/ca/cac.cpp
@@ -19,25 +19,9 @@
|
||||
#include "bhe_IL.h"
|
||||
#include "tcpiiu_IL.h"
|
||||
#include "nciu_IL.h"
|
||||
#include "ioCounter_IL.h"
|
||||
#include "comQueSend_IL.h"
|
||||
#include "recvProcessThread_IL.h"
|
||||
|
||||
extern "C" void cacRecursionLockExitHandler ()
|
||||
{
|
||||
if ( cacRecursionLock ) {
|
||||
epicsThreadPrivateDelete ( cacRecursionLock );
|
||||
cacRecursionLock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void cacInitRecursionLock ( void * )
|
||||
{
|
||||
cacRecursionLock = epicsThreadPrivateCreate ();
|
||||
if ( cacRecursionLock ) {
|
||||
atexit ( cacRecursionLockExitHandler );
|
||||
}
|
||||
}
|
||||
#include "netiiu_IL.h"
|
||||
|
||||
//
|
||||
// cac::cac ()
|
||||
@@ -59,12 +43,6 @@ cac::cac ( bool enablePreemptiveCallbackIn ) :
|
||||
static epicsThreadOnceId once = EPICS_THREAD_ONCE_INIT;
|
||||
unsigned abovePriority;
|
||||
|
||||
epicsThreadOnce ( &once, cacInitRecursionLock, 0 );
|
||||
|
||||
if ( cacRecursionLock == 0 ) {
|
||||
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
|
||||
}
|
||||
|
||||
if ( ! osiSockAttach () ) {
|
||||
throwWithLocation ( caErrorCode (ECA_INTERNAL) );
|
||||
}
|
||||
@@ -312,7 +290,7 @@ void cac::show ( unsigned level ) const
|
||||
if ( this->pudpiiu ) {
|
||||
this->pudpiiu->show ( level - 2u );
|
||||
}
|
||||
this->showOutstandingIO ( level - 2u );
|
||||
this->ioCounter.show ( level - 2u );
|
||||
}
|
||||
|
||||
if ( level > 2u ) {
|
||||
@@ -437,103 +415,78 @@ void cac::beaconNotify ( const inetAddrID &addr )
|
||||
# endif
|
||||
}
|
||||
|
||||
int cac::pend ( double timeout, int early )
|
||||
int cac::pendIO ( const double &timeout )
|
||||
{
|
||||
int status;
|
||||
void *p;
|
||||
|
||||
/*
|
||||
* dont allow recursion
|
||||
*/
|
||||
p = epicsThreadPrivateGet ( cacRecursionLock );
|
||||
if ( p ) {
|
||||
// prevent recursion nightmares by disabling calls to
|
||||
// pendIO () from within a CA callback
|
||||
if ( this->pRecvProcThread->isCurrentThread () ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
epicsThreadPrivateSet ( cacRecursionLock, &cacRecursionLock );
|
||||
|
||||
this->enableCallbackPreemption ();
|
||||
|
||||
status = this->pendPrivate ( timeout, early );
|
||||
this->flush ();
|
||||
|
||||
int status = ECA_NORMAL;
|
||||
epicsTime beg_time = epicsTime::getCurrent ();
|
||||
double remaining;
|
||||
if ( timeout == 0.0 ) {
|
||||
remaining = 60.0;
|
||||
}
|
||||
else{
|
||||
remaining = timeout;
|
||||
}
|
||||
while ( this->ioCounter.currentCount () > 0 ) {
|
||||
if ( remaining < CAC_SIGNIFICANT_SELECT_DELAY ) {
|
||||
status = ECA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
this->ioCounter.waitForCompletion ( remaining );
|
||||
if ( timeout != 0.0 ) {
|
||||
double delay = epicsTime::getCurrent () - beg_time;
|
||||
remaining = timeout - delay;
|
||||
}
|
||||
}
|
||||
|
||||
this->ioCounter.cleanUp ();
|
||||
if ( this->pudpiiu ) {
|
||||
this->pudpiiu->connectTimeoutNotify ();
|
||||
}
|
||||
|
||||
this->disableCallbackPreemption ();
|
||||
|
||||
epicsThreadPrivateSet ( cacRecursionLock, NULL );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* cac::pendPrivate ()
|
||||
*/
|
||||
int cac::pendPrivate (double timeout, int early)
|
||||
int cac::pendEvent ( const double &timeout )
|
||||
{
|
||||
epicsTime cur_time;
|
||||
epicsTime beg_time;
|
||||
double delay;
|
||||
// prevent recursion nightmares by disabling calls to
|
||||
// pendIO () from within a CA callback
|
||||
if ( this->pRecvProcThread->isCurrentThread () ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
this->enableCallbackPreemption ();
|
||||
|
||||
this->flush ();
|
||||
|
||||
if ( this->currentOutstandingIOCount () == 0u && early ) {
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
if ( timeout < 0.0 ) {
|
||||
if ( early ) {
|
||||
this->cleanUpOutstandingIO ();
|
||||
if ( this->pudpiiu ) {
|
||||
this->pudpiiu->connectTimeoutNotify ();
|
||||
}
|
||||
}
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
beg_time = cur_time = epicsTime::getCurrent ();
|
||||
|
||||
delay = 0.0;
|
||||
while ( true ) {
|
||||
ca_real remaining;
|
||||
|
||||
if ( timeout == 0.0 ) {
|
||||
remaining = 60.0;
|
||||
}
|
||||
else{
|
||||
remaining = timeout - delay;
|
||||
|
||||
/*
|
||||
* If we are not waiting for any significant delay
|
||||
* then force the delay to zero so that we avoid
|
||||
* scheduling delays (which can be substantial
|
||||
* on some os)
|
||||
*/
|
||||
if ( remaining <= CAC_SIGNIFICANT_SELECT_DELAY ) {
|
||||
if ( early ) {
|
||||
this->cleanUpOutstandingIO ();
|
||||
if ( this->pudpiiu ) {
|
||||
this->pudpiiu->connectTimeoutNotify ();
|
||||
}
|
||||
}
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
this->waitForCompletionOfIO ( remaining );
|
||||
|
||||
if ( this->currentOutstandingIOCount () == 0 && early ) {
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
cur_time = epicsTime::getCurrent ();
|
||||
|
||||
if ( timeout != 0.0 ) {
|
||||
delay = cur_time - beg_time;
|
||||
if ( timeout == 0.0 ) {
|
||||
while ( true ) {
|
||||
epicsThreadSleep ( 60.0 );
|
||||
}
|
||||
}
|
||||
else if ( timeout >= CAC_SIGNIFICANT_SELECT_DELAY ) {
|
||||
epicsThreadSleep ( timeout );
|
||||
}
|
||||
|
||||
this->disableCallbackPreemption ();
|
||||
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
bool cac::ioComplete () const
|
||||
{
|
||||
if ( this->currentOutstandingIOCount () == 0u ) {
|
||||
if ( this->ioCounter.currentCount () == 0u ) {
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
@@ -550,7 +503,7 @@ void cac::accessRightsNotify ( unsigned id, const caar &ar )
|
||||
}
|
||||
}
|
||||
|
||||
void cac::connectChannel ( bool v44Ok, unsigned id,
|
||||
bool cac::connectChannel ( bool v44Ok, unsigned id,
|
||||
unsigned nativeType, unsigned long nativeCount, unsigned sid )
|
||||
{
|
||||
epicsAutoMutex autoMutex ( this->defaultMutex );
|
||||
@@ -564,16 +517,24 @@ void cac::connectChannel ( bool v44Ok, unsigned id,
|
||||
sidTmp = pChan->getSID ();
|
||||
}
|
||||
pChan->connect ( nativeType, nativeCount, sidTmp );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// this is to only be used by early protocol revisions
|
||||
void cac::connectChannel ( unsigned id )
|
||||
bool cac::connectChannel ( unsigned id )
|
||||
{
|
||||
epicsAutoMutex autoMutex ( this->defaultMutex );
|
||||
nciu * pChan = this->chanTable.lookup ( id );
|
||||
if ( pChan ) {
|
||||
pChan->connect ();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,9 +596,9 @@ cacChannelIO * cac::createChannelIO ( const char *pName, cacChannelNotify &chan
|
||||
{
|
||||
cacChannelIO *pIO;
|
||||
|
||||
pIO = this->services.createChannelIO ( pName, *this, chan );
|
||||
pIO = this->services.createChannelIO ( pName, chan );
|
||||
if ( ! pIO ) {
|
||||
pIO = cacGlobalServiceList.createChannelIO ( pName, *this, chan );
|
||||
pIO = cacGlobalServiceList.createChannelIO ( pName, chan );
|
||||
if ( ! pIO ) {
|
||||
if ( ! this->pudpiiu || ! this->pSearchTmr ) {
|
||||
if ( ! this->setupUDP () ) {
|
||||
@@ -647,7 +608,7 @@ cacChannelIO * cac::createChannelIO ( const char *pName, cacChannelNotify &chan
|
||||
nciu *pNetChan = new nciu ( *this, limboIIU, chan, pName );
|
||||
if ( pNetChan ) {
|
||||
if ( ! pNetChan->fullyConstructed () ) {
|
||||
pNetChan->destroy ();
|
||||
delete static_cast < cacChannelIO * > ( pNetChan );
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
@@ -662,7 +623,7 @@ cacChannelIO * cac::createChannelIO ( const char *pName, cacChannelNotify &chan
|
||||
return pIO;
|
||||
}
|
||||
|
||||
void cac::installNetworkChannel ( nciu &chan, netiiu *&piiu )
|
||||
void cac::installNetworkChannel ( nciu & chan, netiiu * & piiu )
|
||||
{
|
||||
epicsAutoMutex autoMutex ( this->defaultMutex );
|
||||
this->chanTable.add ( chan );
|
||||
@@ -787,14 +748,14 @@ void cac::replaceErrLogHandler ( caPrintfFunc *ca_printf_func )
|
||||
}
|
||||
}
|
||||
|
||||
void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
bool cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
unsigned typeCode, unsigned long count,
|
||||
unsigned minorVersionNumber, const osiSockAddr &addr )
|
||||
{
|
||||
unsigned retrySeqNumber;
|
||||
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -808,7 +769,7 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
*/
|
||||
chan = this->chanTable.lookup ( cid );
|
||||
if ( ! chan ) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
retrySeqNumber = chan->getRetrySeqNo ();
|
||||
@@ -817,7 +778,7 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
* Ignore duplicate search replies
|
||||
*/
|
||||
if ( chan->isAttachedToVirtaulCircuit ( addr ) ) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -829,7 +790,7 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
piiu = pBHE->getIIU ();
|
||||
if ( piiu ) {
|
||||
if ( ! piiu->alive () ) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -838,11 +799,11 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
if ( pBHE ) {
|
||||
if ( this->beaconTable.add ( *pBHE ) < 0 ) {
|
||||
pBHE->destroy ();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
piiu = 0;
|
||||
}
|
||||
@@ -852,7 +813,7 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
if ( ! piiu ) {
|
||||
piiu = new tcpiiu ( *this, this->connTMO, *this->pTimerQueue );
|
||||
if ( ! piiu ) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ( piiu->fullyConstructed () ) {
|
||||
@@ -861,12 +822,12 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
*pBHE, this->ipToAEngine ) ) {
|
||||
this->iiuList.remove ( *piiu );
|
||||
this->iiuListLimbo.add ( *piiu );
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete piiu;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,7 +849,7 @@ void cac::lookupChannelAndTransferToTCP ( unsigned cid, unsigned sid,
|
||||
this->pSearchTmr->notifySearchResponse ( retrySeqNumber );
|
||||
}
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
void cac::uninstallChannel ( nciu & chan )
|
||||
|
||||
Reference in New Issue
Block a user