This is Unofficial EPICS BASE Doxygen Site
cac.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /*
11  * L O S A L A M O S
12  * Los Alamos National Laboratory
13  * Los Alamos, New Mexico 87545
14  *
15  * Copyright, 1986, The Regents of the University of California.
16  *
17  * Author: Jeff Hill
18  *
19  */
20 
21 #define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
22 
23 #include <new>
24 #include <stdexcept>
25 #include <string> // vxWorks 6.0 requires this include
26 
27 #include "dbDefs.h"
28 #include "epicsGuard.h"
29 #include "epicsVersion.h"
30 #include "osiProcess.h"
31 #include "epicsSignal.h"
32 #include "envDefs.h"
33 #include "locationException.h"
34 #include "errlog.h"
35 #include "epicsExport.h"
36 
37 #include "addrList.h"
38 #include "iocinf.h"
39 #include "cac.h"
40 #include "inetAddrID.h"
41 #include "caServerID.h"
42 #include "virtualCircuit.h"
43 #include "syncGroup.h"
44 #include "nciu.h"
45 #include "autoPtrRecycle.h"
47 #include "udpiiu.h"
48 #include "bhe.h"
49 #include "net_convert.h"
50 #include "autoPtrFreeList.h"
51 #include "noopiiu.h"
52 
53 static const char pVersionCAC[] =
54  "@(#) " EPICS_VERSION_STRING
55  ", CA Client Library";
56 
57 // TCP response dispatch table
58 const cac::pProtoStubTCP cac::tcpJumpTableCAC [] =
59 {
60  &cac::versionAction,
61  &cac::eventRespAction,
62  &cac::badTCPRespAction,
63  &cac::readRespAction,
64  &cac::badTCPRespAction,
65  &cac::badTCPRespAction,
66  &cac::searchRespAction,
67  &cac::badTCPRespAction,
68  &cac::badTCPRespAction,
69  &cac::badTCPRespAction,
70  // legacy CA_PROTO_READ_SYNC used as an echo with legacy server
71  &cac::echoRespAction,
72  &cac::exceptionRespAction,
73  &cac::clearChannelRespAction,
74  &cac::badTCPRespAction,
75  &cac::badTCPRespAction,
76  &cac::readNotifyRespAction,
77  &cac::badTCPRespAction,
78  &cac::badTCPRespAction,
79  &cac::createChannelRespAction,
80  &cac::writeNotifyRespAction,
81  &cac::badTCPRespAction,
82  &cac::badTCPRespAction,
83  &cac::accessRightsRespAction,
84  &cac::echoRespAction,
85  &cac::badTCPRespAction,
86  &cac::badTCPRespAction,
87  &cac::verifyAndDisconnectChan,
88  &cac::verifyAndDisconnectChan
89 };
90 
91 // TCP exception dispatch table
92 const cac::pExcepProtoStubTCP cac::tcpExcepJumpTableCAC [] =
93 {
94  &cac::defaultExcep, // CA_PROTO_VERSION
95  &cac::eventAddExcep, // CA_PROTO_EVENT_ADD
96  &cac::defaultExcep, // CA_PROTO_EVENT_CANCEL
97  &cac::readExcep, // CA_PROTO_READ
98  &cac::writeExcep, // CA_PROTO_WRITE
99  &cac::defaultExcep, // CA_PROTO_SNAPSHOT
100  &cac::defaultExcep, // CA_PROTO_SEARCH
101  &cac::defaultExcep, // CA_PROTO_BUILD
102  &cac::defaultExcep, // CA_PROTO_EVENTS_OFF
103  &cac::defaultExcep, // CA_PROTO_EVENTS_ON
104  &cac::defaultExcep, // CA_PROTO_READ_SYNC
105  &cac::defaultExcep, // CA_PROTO_ERROR
106  &cac::defaultExcep, // CA_PROTO_CLEAR_CHANNEL
107  &cac::defaultExcep, // CA_PROTO_RSRV_IS_UP
108  &cac::defaultExcep, // CA_PROTO_NOT_FOUND
109  &cac::readNotifyExcep, // CA_PROTO_READ_NOTIFY
110  &cac::defaultExcep, // CA_PROTO_READ_BUILD
111  &cac::defaultExcep, // REPEATER_CONFIRM
112  &cac::defaultExcep, // CA_PROTO_CREATE_CHAN
113  &cac::writeNotifyExcep, // CA_PROTO_WRITE_NOTIFY
114  &cac::defaultExcep, // CA_PROTO_CLIENT_NAME
115  &cac::defaultExcep, // CA_PROTO_HOST_NAME
116  &cac::defaultExcep, // CA_PROTO_ACCESS_RIGHTS
117  &cac::defaultExcep, // CA_PROTO_ECHO
118  &cac::defaultExcep, // REPEATER_REGISTER
119  &cac::defaultExcep, // CA_PROTO_SIGNAL
120  &cac::defaultExcep, // CA_PROTO_CREATE_CH_FAIL
121  &cac::defaultExcep // CA_PROTO_SERVER_DISCONN
122 };
123 
124 //
125 // cac::cac ()
126 //
128  epicsMutex & mutualExclusionIn,
129  epicsMutex & callbackControlIn,
130  cacContextNotify & notifyIn ) :
131  _refLocalHostName ( localHostNameCache.getReference () ),
132  programBeginTime ( epicsTime::getCurrent() ),
133  connTMO ( CA_CONN_VERIFY_PERIOD ),
134  mutex ( mutualExclusionIn ),
135  cbMutex ( callbackControlIn ),
136  ipToAEngine ( ipAddrToAsciiEngine::allocate () ),
137  timerQueue ( epicsTimerQueueActive::allocate ( false,
138  lowestPriorityLevelAbove(epicsThreadGetPrioritySelf()) ) ),
139  pUserName ( 0 ),
140  pudpiiu ( 0 ),
141  tcpSmallRecvBufFreeList ( 0 ),
142  tcpLargeRecvBufFreeList ( 0 ),
143  notify ( notifyIn ),
144  initializingThreadsId ( epicsThreadGetIdSelf() ),
145  initializingThreadsPriority ( epicsThreadGetPrioritySelf() ),
146  maxRecvBytesTCP ( MAX_TCP ),
147  maxContigFrames ( contiguousMsgCountWhichTriggersFlowControl ),
148  beaconAnomalyCount ( 0u ),
149  iiuExistenceCount ( 0u ),
150  cacShutdownInProgress ( false )
151 {
152  if ( ! osiSockAttach () ) {
154  }
155 
156  try {
157  long status;
158 
159  /*
160  * Certain os, such as HPUX, do not unblock a socket system call
161  * when another thread asynchronously calls both shutdown() and
162  * close(). To solve this problem we need to employ OS specific
163  * mechanisms.
164  */
167 
168  {
169  char tmp[256];
170  size_t len;
171  osiGetUserNameReturn gunRet;
172 
173  gunRet = osiGetUserName ( tmp, sizeof (tmp) );
174  if ( gunRet != osiGetUserNameSuccess ) {
175  tmp[0] = '\0';
176  }
177  len = strlen ( tmp ) + 1;
178  this->pUserName = new char [ len ];
179  strncpy ( this->pUserName, tmp, len );
180  }
181 
182  this->_serverPort =
184  static_cast <unsigned short> (CA_SERVER_PORT) );
185 
186  status = envGetDoubleConfigParam ( &EPICS_CA_CONN_TMO, &this->connTMO );
187  if ( status ) {
188  this->connTMO = CA_CONN_VERIFY_PERIOD;
189  epicsGuard < epicsMutex > cbGuard ( this->cbMutex );
190  errlogPrintf ( "EPICS \"%s\" double fetch failed\n", EPICS_CA_CONN_TMO.name );
191  errlogPrintf ( "Defaulting \"%s\" = %f\n", EPICS_CA_CONN_TMO.name, this->connTMO );
192  }
193 
194  long maxBytesAsALong;
195  status = envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong );
196  if ( status || maxBytesAsALong < 0 ) {
197  errlogPrintf ( "cac: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" );
198  }
199  else {
200  /* allow room for the protocol header so that they get the array size they requested */
201  static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
202  ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong;
203  if ( maxBytes < 0xffffffff - headerSize ) {
204  maxBytes += headerSize;
205  }
206  else {
207  maxBytes = 0xffffffff;
208  }
209  if ( maxBytes < MAX_TCP ) {
210  errlogPrintf ( "cac: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP );
211  }
212  else {
213  this->maxRecvBytesTCP = maxBytes;
214  }
215  }
216  freeListInitPvt ( &this->tcpSmallRecvBufFreeList, MAX_TCP, 1 );
217  if ( ! this->tcpSmallRecvBufFreeList ) {
218  throw std::bad_alloc ();
219  }
220 
221  int autoMaxBytes;
223  autoMaxBytes = 1;
224 
225  if(!autoMaxBytes) {
226  freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 );
227  if ( ! this->tcpLargeRecvBufFreeList ) {
228  throw std::bad_alloc ();
229  }
230  }
231  unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes ();
232  if ( bufsPerArray > 1u ) {
233  maxContigFrames = bufsPerArray *
234  contiguousMsgCountWhichTriggersFlowControl;
235  }
236  }
237  catch ( ... ) {
238  osiSockRelease ();
239  delete [] this->pUserName;
240  freeListCleanup ( this->tcpSmallRecvBufFreeList );
241  if ( this->tcpLargeRecvBufFreeList ) {
242  freeListCleanup ( this->tcpLargeRecvBufFreeList );
243  }
244  this->timerQueue.release ();
245  throw;
246  }
247 
248  /*
249  * load user configured tcp name server address list,
250  * create virtual circuits, and add them to server table
251  */
252  ELLLIST dest, tmpList;
253 
254  ellInit ( & dest );
255  ellInit ( & tmpList );
256 
257  addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_NAME_SERVERS, this->_serverPort, false );
258  removeDuplicateAddresses ( &dest, &tmpList, 0 );
259 
260  epicsGuard < epicsMutex > guard ( this->mutex );
261 
262  while ( osiSockAddrNode *
263  pNode = reinterpret_cast < osiSockAddrNode * > ( ellGet ( & dest ) ) ) {
264  tcpiiu * piiu = NULL;
265  SearchDestTCP * pdst = new SearchDestTCP ( *this, pNode->addr );
266  this->registerSearchDest ( guard, * pdst );
267  /* Initially assume that servers listed in EPICS_CA_NAME_SERVERS support at least minor
268  * version 11. This causes tcpiiu to send the user and host name authentication
269  * messages. When the actual Version message is received from the server it will
270  * be overwrite this assumption.
271  */
272  bool newIIU = findOrCreateVirtCircuit (
273  guard, pNode->addr, cacChannel::priorityDefault,
274  piiu, 11, pdst );
275  free ( pNode );
276  if ( newIIU ) {
277  piiu->start ( guard );
278  }
279  }
280 }
281 
283 {
284  // this blocks until the UDP thread exits so that
285  // it will not sneak in any new clients
286  //
287  // lock intentionally not held here so that we dont deadlock
288  // waiting for the UDP thread to exit while it is waiting to
289  // get the lock.
290  {
291  epicsGuard < epicsMutex > cbGuard ( this->cbMutex );
292  epicsGuard < epicsMutex > guard ( this->mutex );
293  if ( this->pudpiiu ) {
294  this->pudpiiu->shutdown ( cbGuard, guard );
295 
296  // make sure no new tcp circuits are created
297  this->cacShutdownInProgress = true;
298 
299  //
300  // shutdown all tcp circuits
301  //
302  tsDLIter < tcpiiu > iter = this->circuitList.firstIter ();
303  while ( iter.valid() ) {
304  // this causes a clean shutdown to occur
305  iter->unlinkAllChannels ( cbGuard, guard );
306  iter++;
307  }
308  }
309  }
310 
311  //
312  // wait for all tcp threads to exit
313  //
314  // this will block for oustanding sends to go out so dont
315  // hold a lock while waiting
316  //
317  {
318  epicsGuard < epicsMutex > guard ( this->mutex );
319  while ( this->iiuExistenceCount > 0 ) {
320  epicsGuardRelease < epicsMutex > unguard ( guard );
321  this->iiuUninstall.wait ();
322  }
323  }
324 
325  if ( this->pudpiiu ) {
326  delete this->pudpiiu;
327  }
328 
329  freeListCleanup ( this->tcpSmallRecvBufFreeList );
330  if ( this->tcpLargeRecvBufFreeList ) {
331  freeListCleanup ( this->tcpLargeRecvBufFreeList );
332  }
333 
334  delete [] this->pUserName;
335 
336  tsSLList < bhe > tmpBeaconList;
337  this->beaconTable.removeAll ( tmpBeaconList );
338  while ( bhe * pBHE = tmpBeaconList.get() ) {
339  pBHE->~bhe ();
340  this->bheFreeList.release ( pBHE );
341  }
342 
343  this->timerQueue.release ();
344 
345  this->ipToAEngine.release ();
346 
347  // clean-up the list of un-notified msg objects
348  while ( msgForMultiplyDefinedPV * msg = this->msgMultiPVList.get() ) {
349  msg->~msgForMultiplyDefinedPV ();
350  this->mdpvFreeList.release ( msg );
351  }
352 
353  errlogFlush ();
354 
355  osiSockRelease ();
356 
357  // its ok for channels and subscriptions to still
358  // exist at this point. The user created them and
359  // its his responsibility to clean them up.
360 }
361 
362 unsigned cac::lowestPriorityLevelAbove ( unsigned priority )
363 {
364  unsigned abovePriority;
367  priority, & abovePriority );
368  if ( tbs != epicsThreadBooleanStatusSuccess ) {
369  abovePriority = priority;
370  }
371  return abovePriority;
372 }
373 
374 unsigned cac::highestPriorityLevelBelow ( unsigned priority )
375 {
376  unsigned belowPriority;
379  priority, & belowPriority );
380  if ( tbs != epicsThreadBooleanStatusSuccess ) {
381  belowPriority = priority;
382  }
383  return belowPriority;
384 }
385 
386 //
387 // set the push pending flag on all virtual circuits
388 //
390 {
391  guard.assertIdenticalMutex ( this->mutex );
392  tsDLIter < tcpiiu > iter = this->circuitList.firstIter ();
393  while ( iter.valid () ) {
394  iter->flushRequest ( guard );
395  iter++;
396  }
397 }
398 
401 {
402  guard.assertIdenticalMutex ( this->mutex );
403  return this->circuitList.count ();
404 }
405 
406 void cac::show (
407  epicsGuard < epicsMutex > & guard, unsigned level ) const
408 {
409  guard.assertIdenticalMutex ( this->mutex );
410 
411  ::printf ( "Channel Access Client Context at %p for user %s\n",
412  static_cast <const void *> ( this ), this->pUserName );
413  // this also supresses the "defined, but not used"
414  // warning message
415  ::printf ( "\trevision \"%s\"\n", pVersionCAC );
416 
417  if ( level > 0u ) {
418  this->serverTable.show ( level - 1u );
419  ::printf ( "\tconnection time out watchdog period %f\n", this->connTMO );
420  }
421 
422  if ( level > 1u ) {
423  if ( this->pudpiiu ) {
424  this->pudpiiu->show ( level - 2u );
425  }
426  }
427 
428  if ( level > 2u ) {
429  ::printf ( "Program begin time:\n");
430  this->programBeginTime.show ( level - 3u );
431  ::printf ( "Channel identifier hash table:\n" );
432  this->chanTable.show ( level - 3u );
433  ::printf ( "IO identifier hash table:\n" );
434  this->ioTable.show ( level - 3u );
435  ::printf ( "Beacon source identifier hash table:\n" );
436  this->beaconTable.show ( level - 3u );
437  ::printf ( "Timer queue:\n" );
438  this->timerQueue.show ( level - 3u );
439  ::printf ( "IP address to name conversion engine:\n" );
440  this->ipToAEngine.show ( level - 3u );
441  }
442 
443  if ( level > 3u ) {
444  ::printf ( "Default mutex:\n");
445  this->mutex.show ( level - 4u );
446  ::printf ( "mutex:\n" );
447  this->mutex.show ( level - 4u );
448  }
449 }
450 
451 /*
452  * cac::beaconNotify
453  */
454 void cac::beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime,
455  ca_uint32_t beaconNumber, unsigned protocolRevision )
456 {
457  epicsGuard < epicsMutex > guard ( this->mutex );
458 
459  if ( ! this->pudpiiu ) {
460  return;
461  }
462 
463  /*
464  * look for it in the hash table
465  */
466  bhe *pBHE = this->beaconTable.lookup ( addr );
467  if ( pBHE ) {
468  /*
469  * return if the beacon period has not changed significantly
470  */
471  if ( ! pBHE->updatePeriod ( guard, this->programBeginTime,
472  currentTime, beaconNumber, protocolRevision ) ) {
473  return;
474  }
475  }
476  else {
477  /*
478  * This is the first beacon seen from this server.
479  * Wait until 2nd beacon is seen before deciding
480  * if it is a new server (or just the first
481  * time that we have seen a server's beacon
482  * shortly after the program started up)
483  */
484  pBHE = new ( this->bheFreeList )
485  bhe ( this->mutex, currentTime, beaconNumber, addr );
486  if ( pBHE ) {
487  if ( this->beaconTable.add ( *pBHE ) < 0 ) {
488  pBHE->~bhe ();
489  this->bheFreeList.release ( pBHE );
490  }
491  }
492  return;
493  }
494 
495  this->beaconAnomalyCount++;
496 
497  this->pudpiiu->beaconAnomalyNotify ( guard );
498 
499 # ifdef DEBUG
500  {
501  char buf[128];
502  addr.name ( buf, sizeof ( buf ) );
503  ::printf ( "New server available: %s\n", buf );
504  }
505 # endif
506 }
507 
509  epicsGuard < epicsMutex > & guard, const char * pName,
511 {
512  guard.assertIdenticalMutex ( this->mutex );
513 
514  if ( pri > cacChannel::priorityMax ) {
515  throw cacChannel::badPriority ();
516  }
517 
518  if ( pName == 0 || pName[0] == '\0' ) {
519  throw cacChannel::badString ();
520  }
521 
522  if ( ! this->pudpiiu ) {
523  this->pudpiiu = new udpiiu (
524  guard, this->timerQueue, this->cbMutex,
525  this->mutex, this->notify, *this, this->_serverPort,
526  this->searchDestList );
527  }
528 
529  nciu * pNetChan = new ( this->channelFreeList )
530  nciu ( *this, noopIIU, chan, pName, pri );
531  this->chanTable.idAssignAdd ( *pNetChan );
532  return *pNetChan;
533 }
534 
537  unsigned priority, tcpiiu *& piiu, unsigned minorVersionNumber,
538  SearchDestTCP * pSearchDest )
539 {
540  guard.assertIdenticalMutex ( this->mutex );
541  bool newIIU = false;
542 
543  if ( piiu ) {
544  if ( ! piiu->alive ( guard ) ) {
545  return newIIU;
546  }
547  }
548  else {
549  try {
551  this->freeListVirtualCircuit,
552  new ( this->freeListVirtualCircuit ) tcpiiu (
553  *this, this->mutex, this->cbMutex, this->notify, this->connTMO,
554  this->timerQueue, addr, this->comBufMemMgr, minorVersionNumber,
555  this->ipToAEngine, priority, pSearchDest ) );
556 
557  bhe * pBHE = this->beaconTable.lookup ( addr.ia );
558  if ( ! pBHE ) {
559  pBHE = new ( this->bheFreeList )
560  bhe ( this->mutex, epicsTime (), 0u, addr.ia );
561  if ( this->beaconTable.add ( *pBHE ) < 0 ) {
562  return newIIU;
563  }
564  }
565  this->serverTable.add ( *pnewiiu );
566  this->circuitList.add ( *pnewiiu );
567  this->iiuExistenceCount++;
568  pBHE->registerIIU ( guard, *pnewiiu );
569  piiu = pnewiiu.release ();
570  newIIU = true;
571  }
572  catch ( std :: exception & except ) {
573  errlogPrintf (
574  "CAC: exception during virtual circuit creation \"%s\"\n",
575  except.what () );
576  return newIIU;
577  }
578  catch ( ... ) {
579  errlogPrintf (
580  "CAC: Nonstandard exception during virtual circuit creation\n" );
581  return newIIU;
582  }
583  }
584  return newIIU;
585 }
586 
588  unsigned cid, unsigned sid,
590  unsigned minorVersionNumber, const osiSockAddr & addr,
591  const epicsTime & currentTime )
592 {
593  if ( addr.sa.sa_family != AF_INET ) {
594  return;
595  }
596 
597  epicsGuard < epicsMutex > guard ( this->mutex );
598 
599  /*
600  * Do not open new circuits while the cac is shutting down
601  */
602  if ( this->cacShutdownInProgress ) {
603  return;
604  }
605 
606  /*
607  * ignore search replies for deleted channels
608  */
609  nciu * pChan = this->chanTable.lookup ( cid );
610  if ( ! pChan ) {
611  return;
612  }
613 
614  /*
615  * Ignore duplicate search replies
616  */
617  osiSockAddr chanAddr = pChan->getPIIU(guard)->getNetworkAddress (guard);
618 
619  if ( chanAddr.sa.sa_family != AF_UNSPEC ) {
620  if ( ! sockAddrAreIdentical ( &addr, &chanAddr ) ) {
621  char acc[64];
622  pChan->getPIIU(guard)->getHostName ( guard, acc, sizeof ( acc ) );
623  msgForMultiplyDefinedPV * pMsg = new ( this->mdpvFreeList )
624  msgForMultiplyDefinedPV ( this->ipToAEngine,
625  *this, pChan->pName ( guard ), acc );
626  // cac keeps a list of these objects for proper clean-up in ~cac
627  this->msgMultiPVList.add ( *pMsg );
628  // It is possible for the ioInitiate call below to
629  // call the callback directly if queue quota is exceeded.
630  // This callback takes the callback lock and therefore we
631  // must release the primary mutex here to avoid a lock
632  // hierarchy inversion.
633  epicsGuardRelease < epicsMutex > unguard ( guard );
634  pMsg->ioInitiate ( addr );
635  }
636  return;
637  }
638 
639  caServerID servID ( addr.ia, pChan->getPriority(guard) );
640  tcpiiu * piiu = this->serverTable.lookup ( servID );
641 
642  bool newIIU = findOrCreateVirtCircuit (
643  guard, addr,
644  pChan->getPriority(guard), piiu, minorVersionNumber );
645 
646  // must occur before moving to new iiu
648  guard, *pChan, currentTime );
649  if ( piiu ) {
650  piiu->installChannel (
651  guard, *pChan, sid, typeCode, count );
652 
653  if ( newIIU ) {
654  piiu->start ( guard );
655  }
656  }
657 }
658 
661  nciu & chan )
662 {
663  guard.assertIdenticalMutex ( this->mutex );
664 
665  // uninstall channel so that recv threads
666  // will not start a new callback for this channel's IO.
667  if ( this->chanTable.remove ( chan ) != & chan ) {
668  throw std::logic_error ( "Invalid channel identifier" );
669  }
670  chan.~nciu ();
671  this->channelFreeList.release ( & chan );
672 }
673 
677  nciu & chan, tsDLList < baseNMIU > & ioList )
678 {
679  cbGuard.assertIdenticalMutex ( this->cbMutex );
680  guard.assertIdenticalMutex ( this->mutex );
681  char buf[128];
682  chan.getHostName ( guard, buf, sizeof ( buf ) );
683 
684  tsDLIter < baseNMIU > pNetIO = ioList.firstIter();
685  while ( pNetIO.valid () ) {
686  tsDLIter < baseNMIU > pNext = pNetIO;
687  pNext++;
688  if ( ! pNetIO->isSubscription() ) {
689  this->ioTable.remove ( pNetIO->getId () );
690  }
691  pNetIO->exception ( guard, *this, ECA_DISCONN, buf );
692  pNetIO = pNext;
693  }
694 }
695 
697  epicsGuard < epicsMutex > & callbackControl,
698  const char * pformat, ... ) const
699 {
700  va_list theArgs;
701  va_start ( theArgs, pformat );
702  int status = this->varArgsPrintFormated ( callbackControl, pformat, theArgs );
703  va_end ( theArgs );
704  return status;
705 }
706 
709  unsigned type, arrayElementCount nElem, const void * pValue, cacWriteNotify & notifyIn )
710 {
711  guard.assertIdenticalMutex ( this->mutex );
713  guard, this->ioTable, *this,
714  netWriteNotifyIO::factory ( this->freeListWriteNotifyIO, icni, notifyIn ) );
715  this->ioTable.idAssignAdd ( *pIO );
716  chan.getPIIU(guard)->writeNotifyRequest (
717  guard, chan, *pIO, type, nElem, pValue );
718  return *pIO.release();
719 }
720 
723  unsigned type, arrayElementCount nElem, cacReadNotify & notifyIn )
724 {
725  guard.assertIdenticalMutex ( this->mutex );
727  guard, this->ioTable, *this,
728  netReadNotifyIO::factory ( this->freeListReadNotifyIO, icni, notifyIn ) );
729  this->ioTable.idAssignAdd ( *pIO );
730  chan.getPIIU(guard)->readNotifyRequest ( guard, chan, *pIO, type, nElem );
731  return *pIO.release();
732 }
733 
735  CallbackGuard & callbackGuard,
737  const cacChannel::ioid & idIn, nciu & chan )
738 {
739  guard.assertIdenticalMutex ( this->mutex );
740 
741  baseNMIU * pIO = this->ioTable.remove ( idIn );
742  if ( pIO ) {
743  class netSubscription * pSubscr = pIO->isSubscription ();
744  if ( pSubscr ) {
745  pSubscr->unsubscribeIfRequired ( guard, chan );
746  }
747 
748  // this uninstalls from the list and destroys the IO
749  pIO->exception ( guard, *this,
750  ECA_CHANDESTROY, chan.pName ( guard ) );
751  return true;
752  }
753  return false;
754 }
755 
758  const cacChannel::ioid & idIn, unsigned level ) const
759 {
760  baseNMIU * pmiu = this->ioTable.lookup ( idIn );
761  if ( pmiu ) {
762  pmiu->show ( guard, level );
763  }
764 }
765 
766 void cac::ioExceptionNotify (
767  unsigned idIn, int status, const char * pContext,
768  unsigned type, arrayElementCount count )
769 {
770  epicsGuard < epicsMutex > guard ( this->mutex );
771  baseNMIU * pmiu = this->ioTable.lookup ( idIn );
772  if ( pmiu ) {
773  pmiu->exception ( guard, *this, status, pContext, type, count );
774  }
775 }
776 
777 void cac::ioExceptionNotifyAndUninstall (
778  unsigned idIn, int status, const char * pContext,
779  unsigned type, arrayElementCount count )
780 {
781  epicsGuard < epicsMutex > guard ( this->mutex );
782  baseNMIU * pmiu = this->ioTable.remove ( idIn );
783  if ( pmiu ) {
784  pmiu->exception ( guard, *this, status, pContext, type, count );
785  }
786 }
787 
788 void cac::recycleReadNotifyIO (
790 {
791  guard.assertIdenticalMutex ( this->mutex );
792  this->freeListReadNotifyIO.release ( & io );
793 }
794 
795 void cac::recycleWriteNotifyIO (
797 {
798  guard.assertIdenticalMutex ( this->mutex );
799  this->freeListWriteNotifyIO.release ( & io );
800 }
801 
802 void cac::recycleSubscription (
804 {
805  guard.assertIdenticalMutex ( this->mutex );
806  this->freeListSubscription.release ( & io );
807 }
808 
811  nciu & chan, privateInterfaceForIO & privChan,
812  unsigned type,
813  arrayElementCount nElem, unsigned mask,
814  cacStateNotify & notifyIn,
815  bool chanIsInstalled )
816 {
817  guard.assertIdenticalMutex ( this->mutex );
819  guard, this->ioTable, *this,
820  netSubscription::factory ( this->freeListSubscription,
821  privChan, type, nElem, mask, notifyIn ) );
822  this->ioTable.idAssignAdd ( *pIO );
823  if ( chanIsInstalled ) {
824  pIO->subscribeIfRequired ( guard, chan );
825  }
826  return *pIO.release ();
827 }
828 
829 bool cac::versionAction ( callbackManager &, tcpiiu & iiu,
830  const epicsTime &, const caHdrLargeArray & msg, void * )
831 {
832  iiu.versionRespNotify ( msg );
833  return true;
834 }
835 
836 bool cac::echoRespAction (
837  callbackManager & mgr, tcpiiu & iiu,
838  const epicsTime & /* current */, const caHdrLargeArray &, void * )
839 {
840  iiu.probeResponseNotify ( mgr.cbGuard );
841  return true;
842 }
843 
844 bool cac::writeNotifyRespAction (
845  callbackManager &, tcpiiu &,
846  const epicsTime &, const caHdrLargeArray & hdr, void * )
847 {
848  epicsGuard < epicsMutex > guard ( this->mutex );
849  baseNMIU * pmiu = this->ioTable.remove ( hdr.m_available );
850  if ( pmiu ) {
851  if ( hdr.m_cid == ECA_NORMAL ) {
852  pmiu->completion ( guard, *this );
853  }
854  else {
855  pmiu->exception ( guard, *this,
856  hdr.m_cid, "write notify request rejected" );
857  }
858  }
859  return true;
860 }
861 
862 bool cac::readNotifyRespAction ( callbackManager &, tcpiiu & iiu,
863  const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy )
864 {
865  epicsGuard < epicsMutex > guard ( this->mutex );
866 
867  /*
868  * the channel id field is abused for
869  * read notify status starting with CA V4.1
870  */
871  int caStatus;
872  if ( iiu.ca_v41_ok ( guard ) ) {
873  caStatus = hdr.m_cid;
874  }
875  else {
876  caStatus = ECA_NORMAL;
877  }
878 
879  baseNMIU * pmiu = this->ioTable.remove ( hdr.m_available );
880  //
881  // The IO destroy routines take the call back mutex
882  // when uninstalling and deleting the baseNMIU so there is
883  // no need to worry here about the baseNMIU being deleted while
884  // it is in use here.
885  //
886  if ( pmiu ) {
887  // if its a circuit-becomes-responsive subscription update
888  // then we need to reinstall the IO into the table
889  netSubscription * pSubscr = pmiu->isSubscription ();
890  if ( pSubscr ) {
891  // this does *not* assign a new resource id
892  this->ioTable.add ( *pmiu );
893  }
894  if ( caStatus == ECA_NORMAL ) {
895  /*
896  * convert the data buffer from net
897  * format to host format
898  */
899  caStatus = caNetConvert (
900  hdr.m_dataType, pMsgBdy, pMsgBdy, false, hdr.m_count );
901  }
902  if ( caStatus == ECA_NORMAL ) {
903  pmiu->completion ( guard, *this,
904  hdr.m_dataType, hdr.m_count, pMsgBdy );
905  }
906  else {
907  pmiu->exception ( guard, *this,
908  caStatus, "read failed",
909  hdr.m_dataType, hdr.m_count );
910  }
911  }
912  return true;
913 }
914 
915 bool cac::searchRespAction ( callbackManager &, tcpiiu & iiu,
916  const epicsTime & currentTime, const caHdrLargeArray & msg,
917  void * /* pMsgBdy */ )
918 {
919  assert ( this->pudpiiu );
920  iiu.searchRespNotify ( currentTime, msg );
921  return true;
922 }
923 
924 bool cac::eventRespAction ( callbackManager &, tcpiiu &iiu,
925  const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy )
926 {
927  int caStatus;
928 
929  /*
930  * m_postsize = 0 used to be a subscription cancel confirmation,
931  * but is now a noop because the IO block is immediately deleted
932  */
933  if ( ! hdr.m_postsize ) {
934  return true;
935  }
936 
937  epicsGuard < epicsMutex > guard ( this->mutex );
938 
939  /*
940  * the channel id field is abused for
941  * read notify status starting with CA V4.1
942  */
943  if ( iiu.ca_v41_ok ( guard ) ) {
944  caStatus = hdr.m_cid;
945  }
946  else {
947  caStatus = ECA_NORMAL;
948  }
949 
950  //
951  // The IO destroy routines take the call back mutex
952  // when uninstalling and deleting the baseNMIU so there is
953  // no need to worry here about the baseNMIU being deleted while
954  // it is in use here.
955  //
956  baseNMIU * pmiu = this->ioTable.lookup ( hdr.m_available );
957  if ( pmiu ) {
958  /*
959  * convert the data buffer from net format to host format
960  */
961  if ( caStatus == ECA_NORMAL ) {
962  caStatus = caNetConvert (
963  hdr.m_dataType, pMsgBdy, pMsgBdy, false, hdr.m_count );
964  }
965  if ( caStatus == ECA_NORMAL ) {
966  pmiu->completion ( guard, *this,
967  hdr.m_dataType, hdr.m_count, pMsgBdy );
968  }
969  else {
970  pmiu->exception ( guard, *this, caStatus,
971  "subscription update read failed",
972  hdr.m_dataType, hdr.m_count );
973  }
974  }
975  return true;
976 }
977 
978 bool cac::readRespAction ( callbackManager &, tcpiiu &,
979  const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy )
980 {
981  epicsGuard < epicsMutex > guard ( this->mutex );
982  baseNMIU * pmiu = this->ioTable.remove ( hdr.m_available );
983  //
984  // The IO destroy routines take the call back mutex
985  // when uninstalling and deleting the baseNMIU so there is
986  // no need to worry here about the baseNMIU being deleted while
987  // it is in use here.
988  //
989  if ( pmiu ) {
990  pmiu->completion ( guard, *this,
991  hdr.m_dataType, hdr.m_count, pMsgBdy );
992  }
993  return true;
994 }
995 
996 bool cac::clearChannelRespAction ( callbackManager &, tcpiiu &,
997  const epicsTime &, const caHdrLargeArray &, void * /* pMsgBody */ )
998 {
999  return true; // currently a noop
1000 }
1001 
1002 bool cac::defaultExcep (
1003  callbackManager &, tcpiiu & iiu,
1004  const caHdrLargeArray &, const char * pCtx, unsigned status )
1005 {
1006  epicsGuard < epicsMutex > guard ( this->mutex );
1007  char buf[512];
1008  char hostName[64];
1009  iiu.getHostName ( guard, hostName, sizeof ( hostName ) );
1010  sprintf ( buf, "host=%s ctx=%.400s", hostName, pCtx );
1011  this->notify.exception ( guard, status, buf, 0, 0u );
1012  return true;
1013 }
1014 
1015 void cac::exception (
1017  epicsGuard < epicsMutex > & guard, int status,
1018  const char * pContext, const char * pFileName, unsigned lineNo )
1019 {
1020  cbGuard.assertIdenticalMutex ( this->cbMutex );
1021  guard.assertIdenticalMutex ( this->mutex );
1022  this->notify.exception ( guard, status, pContext,
1023  pFileName, lineNo );
1024 }
1025 
1026 bool cac::eventAddExcep (
1027  callbackManager &, tcpiiu &,
1028  const caHdrLargeArray &hdr,
1029  const char *pCtx, unsigned status )
1030 {
1031  this->ioExceptionNotify ( hdr.m_available, status, pCtx,
1032  hdr.m_dataType, hdr.m_count );
1033  return true;
1034 }
1035 
1036 bool cac::readExcep ( callbackManager &, tcpiiu &,
1037  const caHdrLargeArray & hdr,
1038  const char * pCtx, unsigned status )
1039 {
1040  this->ioExceptionNotifyAndUninstall ( hdr.m_available,
1041  status, pCtx, hdr.m_dataType, hdr.m_count );
1042  return true;
1043 }
1044 
1045 bool cac::writeExcep (
1046  callbackManager & mgr,
1047  tcpiiu &, const caHdrLargeArray & hdr,
1048  const char * pCtx, unsigned status )
1049 {
1050  epicsGuard < epicsMutex > guard ( this->mutex );
1051  nciu * pChan = this->chanTable.lookup ( hdr.m_available );
1052  if ( pChan ) {
1053  pChan->writeException ( mgr.cbGuard, guard, status, pCtx,
1054  hdr.m_dataType, hdr.m_count );
1055  }
1056  return true;
1057 }
1058 
1059 bool cac::readNotifyExcep ( callbackManager &, tcpiiu &,
1060  const caHdrLargeArray &hdr,
1061  const char *pCtx, unsigned status )
1062 {
1063  this->ioExceptionNotifyAndUninstall ( hdr.m_available,
1064  status, pCtx, hdr.m_dataType, hdr.m_count );
1065  return true;
1066 }
1067 
1068 bool cac::writeNotifyExcep ( callbackManager &, tcpiiu &,
1069  const caHdrLargeArray &hdr,
1070  const char *pCtx, unsigned status )
1071 {
1072  this->ioExceptionNotifyAndUninstall ( hdr.m_available,
1073  status, pCtx, hdr.m_dataType, hdr.m_count );
1074  return true;
1075 }
1076 
1077 bool cac::exceptionRespAction ( callbackManager & cbMutexIn, tcpiiu & iiu,
1078  const epicsTime &, const caHdrLargeArray & hdr, void * pMsgBdy )
1079 {
1080  const caHdr * pReq = reinterpret_cast < const caHdr * > ( pMsgBdy );
1081  unsigned bytesSoFar = sizeof ( *pReq );
1082  if ( hdr.m_postsize < bytesSoFar ) {
1083  return false;
1084  }
1085  caHdrLargeArray req;
1092  const ca_uint32_t * pLW = reinterpret_cast < const ca_uint32_t * > ( pReq + 1 );
1093  if ( req.m_postsize == 0xffff ) {
1094  static const unsigned annexSize =
1095  sizeof ( req.m_postsize ) + sizeof ( req.m_count );
1096  bytesSoFar += annexSize;
1097  if ( hdr.m_postsize < bytesSoFar ) {
1098  return false;
1099  }
1102  pLW += 2u;
1103  }
1104 
1105  // execute the exception message
1106  pExcepProtoStubTCP pStub;
1107  if ( hdr.m_cmmd >= NELEMENTS ( cac::tcpExcepJumpTableCAC ) ) {
1108  pStub = &cac::defaultExcep;
1109  }
1110  else {
1111  pStub = cac::tcpExcepJumpTableCAC [req.m_cmmd];
1112  }
1113  const char *pCtx = reinterpret_cast < const char * > ( pLW );
1114  return ( this->*pStub ) ( cbMutexIn, iiu, req, pCtx, hdr.m_available );
1115 }
1116 
1117 bool cac::accessRightsRespAction (
1118  callbackManager & mgr, tcpiiu &,
1119  const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ )
1120 {
1121  epicsGuard < epicsMutex > guard ( this->mutex );
1122  nciu * pChan = this->chanTable.lookup ( hdr.m_cid );
1123  if ( pChan ) {
1124  unsigned ar = hdr.m_available;
1125  caAccessRights accessRights (
1126  ( ar & CA_PROTO_ACCESS_RIGHT_READ ) ? true : false,
1127  ( ar & CA_PROTO_ACCESS_RIGHT_WRITE ) ? true : false);
1128  pChan->accessRightsStateChange ( accessRights, mgr.cbGuard, guard );
1129  }
1130 
1131  return true;
1132 }
1133 
1134 bool cac::createChannelRespAction (
1135  callbackManager & mgr, tcpiiu & iiu,
1136  const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ )
1137 {
1138  epicsGuard < epicsMutex > guard ( this->mutex );
1139  nciu * pChan = this->chanTable.lookup ( hdr.m_cid );
1140  if ( pChan ) {
1141  unsigned sidTmp;
1142  if ( iiu.ca_v44_ok ( guard ) ) {
1143  sidTmp = hdr.m_available;
1144  }
1145  else {
1146  sidTmp = pChan->getSID (guard);
1147  }
1148  bool wasExpected = iiu.connectNotify ( guard, *pChan );
1149  if ( wasExpected ) {
1150  pChan->connect ( hdr.m_dataType, hdr.m_count, sidTmp,
1151  mgr.cbGuard, guard );
1152  }
1153  else {
1154  errlogPrintf (
1155  "CA Client Library: Ignored duplicate create channel "
1156  "response from CA server?\n" );
1157  }
1158  }
1159  else if ( iiu.ca_v44_ok ( guard ) ) {
1160  // this indicates a claim response for a resource that does
1161  // not exist in the client - so just remove it from the server
1162  iiu.clearChannelRequest ( guard, hdr.m_available, hdr.m_cid );
1163  }
1164 
1165  return true;
1166 }
1167 
1168 bool cac::verifyAndDisconnectChan (
1169  callbackManager & mgr, tcpiiu &,
1170  const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ )
1171 {
1172  epicsGuard < epicsMutex > guard ( this->mutex );
1173  nciu * pChan = this->chanTable.lookup ( hdr.m_cid );
1174  if ( ! pChan ) {
1175  return true;
1176  }
1177  this->disconnectChannel ( mgr.cbGuard, guard, *pChan );
1178  return true;
1179 }
1180 
1181 void cac::disconnectChannel (
1182  epicsGuard < epicsMutex > & cbGuard,
1183  epicsGuard < epicsMutex > & guard, nciu & chan )
1184 {
1185  guard.assertIdenticalMutex ( this->mutex );
1186  assert ( this->pudpiiu );
1187  chan.disconnectAllIO ( cbGuard, guard );
1188  chan.getPIIU(guard)->uninstallChan ( guard, chan );
1189  this->pudpiiu->installDisconnectedChannel ( guard, chan );
1190  chan.unresponsiveCircuitNotify ( cbGuard, guard );
1191 }
1192 
1193 bool cac::badTCPRespAction ( callbackManager &, tcpiiu & iiu,
1194  const epicsTime &, const caHdrLargeArray & hdr, void * /* pMsgBody */ )
1195 {
1196  epicsGuard < epicsMutex > guard ( this->mutex );
1197  char hostName[64];
1198  iiu.getHostName ( guard, hostName, sizeof ( hostName ) );
1199  errlogPrintf ( "CAC: Undecipherable TCP message ( bad response type %u ) from %s\n",
1200  hdr.m_cmmd, hostName );
1201  return false;
1202 }
1203 
1205  const epicsTime & currentTime, caHdrLargeArray & hdr, char * pMshBody )
1206 {
1207  // execute the response message
1208  pProtoStubTCP pStub;
1209  if ( hdr.m_cmmd >= NELEMENTS ( cac::tcpJumpTableCAC ) ) {
1210  pStub = &cac::badTCPRespAction;
1211  }
1212  else {
1213  pStub = cac::tcpJumpTableCAC [hdr.m_cmmd];
1214  }
1215  return ( this->*pStub ) ( mgr, iiu, currentTime, hdr, pMshBody );
1216 }
1217 
1219  epicsGuard < epicsMutex > & guard ) const
1220 {
1221  guard.assertIdenticalMutex ( this->mutex );
1222  this->chanTable.verify ();
1223  this->ioTable.verify ();
1224  this->beaconTable.verify ();
1225 }
1226 
1227 void cac::destroyIIU ( tcpiiu & iiu )
1228 {
1229  {
1230  callbackManager mgr ( this->notify, this->cbMutex );
1231  epicsGuard < epicsMutex > guard ( this->mutex );
1232 
1233  if ( iiu.channelCount ( guard ) ) {
1234  char hostNameTmp[64];
1235  iiu.getHostName ( guard, hostNameTmp, sizeof ( hostNameTmp ) );
1236  genLocalExcep ( mgr.cbGuard, guard, *this, ECA_DISCONN, hostNameTmp );
1237  }
1238  osiSockAddr addr = iiu.getNetworkAddress ( guard );
1239  if ( addr.sa.sa_family == AF_INET ) {
1240  inetAddrID tmp ( addr.ia );
1241  bhe * pBHE = this->beaconTable.lookup ( tmp );
1242  if ( pBHE ) {
1243  pBHE->unregisterIIU ( guard, iiu );
1244  }
1245  }
1246 
1247  assert ( this->pudpiiu );
1248  iiu.disconnectAllChannels ( mgr.cbGuard, guard, *this->pudpiiu );
1249 
1250  this->serverTable.remove ( iiu );
1251  this->circuitList.remove ( iiu );
1252  }
1253 
1254  // this destroys a timer that takes the primary mutex
1255  // so we must not hold the primary mutex here
1256  //
1257  // this waits for send/recv threads to exit
1258  // this also uses the cac free lists so cac must wait
1259  // for this to finish before it shuts down
1260 
1261  iiu.~tcpiiu ();
1262 
1263  {
1264  epicsGuard < epicsMutex > guard ( this->mutex );
1265  this->freeListVirtualCircuit.release ( & iiu );
1266  this->iiuExistenceCount--;
1267  // signal iiu uninstall event so that cac can properly shut down
1268  this->iiuUninstall.signal();
1269  }
1270  // do not touch "this" after lock is released above
1271 }
1272 
1274  epicsGuard < epicsMutex > & guard,
1275  const nciu & chan ) const
1276 {
1277  const netiiu * pIIU = chan.getConstPIIU ( guard );
1278  if ( pIIU ) {
1279  osiSockAddr addr = pIIU->getNetworkAddress ( guard );
1280  if ( addr.sa.sa_family == AF_INET ) {
1281  inetAddrID tmp ( addr.ia );
1282  bhe *pBHE = this->beaconTable.lookup ( tmp );
1283  if ( pBHE ) {
1284  return pBHE->period ( guard );
1285  }
1286  }
1287  }
1288  return - DBL_MAX;
1289 }
1290 
1292  epicsGuard < epicsMutex > & guard,
1293  nciu & chan, netiiu * & piiu )
1294 {
1295  guard.assertIdenticalMutex ( this->mutex );
1296  assert ( this->pudpiiu );
1297  this->pudpiiu->installNewChannel ( guard, chan, piiu );
1298 }
1299 
1301 {
1302  return this->freeList.allocate ( size );
1303 }
1304 
1305 void cacComBufMemoryManager::release ( void * pCadaver )
1306 {
1307  this->freeList.release ( pCadaver );
1308 }
1309 
1310 void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
1311  const char * pChannelName, const char * pAcc, const char * pRej )
1312 {
1313  char buf[256];
1314  sprintf ( buf, "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s",
1315  pChannelName, pAcc, pRej );
1316  {
1317  callbackManager mgr ( this->notify, this->cbMutex );
1318  epicsGuard < epicsMutex > guard ( this->mutex );
1319  this->exception ( mgr.cbGuard, guard, ECA_DBLCHNL, buf, __FILE__, __LINE__ );
1320 
1321  // remove from the list under lock
1322  this->msgMultiPVList.remove ( mfmdpv );
1323  }
1324  // delete msg object
1325  mfmdpv.~msgForMultiplyDefinedPV ();
1326  this->mdpvFreeList.release ( & mfmdpv );
1327 }
1328 
1330  epicsGuard < epicsMutex > & guard,
1331  SearchDest & req )
1332 {
1333  guard.assertIdenticalMutex ( this->mutex );
1334  this->searchDestList.add ( req );
1335 }
epicsSingleton< localHostName > localHostNameCache
LIBCA_API void epicsStdCall removeDuplicateAddresses(struct ELLLIST *pDestList, ELLLIST *pSrcList, int silent)
Definition: iocinf.cpp:123
void errlogFlush(void)
Definition: errlog.c:529
void destroyIIU(tcpiiu &iiu)
Definition: cac.cpp:1227
void disconnectAllChannels(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard, class udpiiu &)
Definition: tcpiiu.cpp:1806
bool ca_v44_ok(epicsGuard< epicsMutex > &) const
#define MAX_TCP
Definition: caProto.h:63
void beaconAnomalyNotify(epicsGuard< epicsMutex > &guard)
Definition: udpiiu.cpp:1200
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
virtual void show(unsigned level) const =0
void selfTest(epicsGuard< epicsMutex > &) const
Definition: cac.cpp:1218
epicsThreadBooleanStatus
Definition: epicsThread.h:93
void add(T &item)
Definition: tsDLList.h:313
void show(unsigned int level) const
Definition: timerQueue.cpp:214
LIBCOM_API void epicsStdCall epicsSignalInstallSigPipeIgnore(void)
Definition: osdSignal.cpp:17
char * name
Name of the parameter.
Definition: envDefs.h:42
osiSockAddr getNetworkAddress(epicsGuard< epicsMutex > &) const
Definition: tcpiiu.cpp:1769
void osiSockRelease()
Definition: osdSock.c:62
struct sockaddr sa
Definition: osiSock.h:158
ca_uint32_t m_postsize
int add(T &res)
Definition: resourceLib.h:643
static netWriteNotifyIO * factory(tsFreeList< class netWriteNotifyIO, 1024, epicsMutexNOOP > &, privateInterfaceForIO &, cacWriteNotify &)
Definition: netIO.h:284
void subscribeIfRequired(epicsGuard< epicsMutex > &guard, nciu &chan)
LIBCA_API int epicsStdCall addAddrToChannelAccessAddressList(struct ELLLIST *pList, const ENV_PARAM *pEnv, unsigned short port, int ignoreNonDefaultPort)
Definition: iocinf.cpp:74
int caNetConvert(unsigned type, const void *pSrc, void *pDest, int hton, arrayElementCount count)
Definition: convert.cpp:1420
void exception epicsGuard< epicsMutex > epicsGuard< epicsMutex > int status
Definition: cac.h:164
unsigned getHostName(epicsGuard< epicsMutex > &, char *pBuf, unsigned bufLen) const
Definition: nciu.cpp:398
Definition: netIO.h:44
void flushRequest(epicsGuard< epicsMutex > &)
Definition: tcpiiu.cpp:2038
ca_uint32_t m_available
Definition: caProto.h:166
struct sockaddr_in ia
Definition: osiSock.h:157
void connect(unsigned nativeType, unsigned nativeCount, unsigned sid, epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: nciu.cpp:114
Routines to get and set EPICS environment parameters.
tsDLIterConst< T > firstIter() const
Definition: tsDLList.h:459
void unresponsiveCircuitNotify(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: nciu.cpp:160
static netSubscription * factory(tsFreeList< class netSubscription, 1024, epicsMutexNOOP > &, class privateInterfaceForIO &, unsigned type, arrayElementCount count, unsigned mask, cacStateNotify &)
Definition: netIO.h:231
const char * pName(epicsGuard< epicsMutex > &) const
Definition: nciu.cpp:226
#define printf
Definition: epicsStdio.h:41
void exception epicsGuard< epicsMutex > epicsGuard< epicsMutex > & guard
Definition: cac.h:164
static const priLev priorityMax
Definition: cacIO.h:166
void unlinkAllChannels(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: tcpiiu.cpp:1869
void ioShow(epicsGuard< epicsMutex > &guard, const cacChannel::ioid &id, unsigned level) const
Definition: cac.cpp:756
pvd::StructureConstPtr type
virtual ~cac()
Definition: cac.cpp:282
~nciu()
Definition: nciu.cpp:69
unsigned int ca_uint32_t
Definition: caProto.h:76
ELLNODE * ellGet(ELLLIST *pList)
Deletes and returns the first node from a list.
Definition: ellLib.c:147
LIBCOM_API const ENV_PARAM EPICS_CA_MAX_ARRAY_BYTES
LIBCA_API bool updatePeriod(epicsGuard< epicsMutex > &, const epicsTime &programBeginTime, const epicsTime &currentTime, ca_uint32_t beaconNumber, unsigned protocolRevision)
Definition: bhe.cpp:124
void assertIdenticalMutex(const T &) const
Definition: epicsGuard.h:80
void * allocate(size_t)
Definition: cac.cpp:1300
LIBCOM_API const ENV_PARAM EPICS_CA_NAME_SERVERS
#define NULL
Definition: catime.c:38
void start(epicsGuard< epicsMutex > &)
Definition: tcpiiu.cpp:819
ca_uint16_t m_dataType
#define CA_SERVER_PORT
Definition: caProto.h:53
void exception epicsGuard< epicsMutex > epicsGuard< epicsMutex > int const char * pContext
Definition: cac.h:164
LIBCOM_API void epicsStdCall freeListInitPvt(void **ppvt, int size, int nmalloc)
Definition: freeListLib.c:44
unsigned count() const
Definition: tsDLList.h:181
virtual osiSockAddr getNetworkAddress(epicsGuard< epicsMutex > &) const =0
Definition: netiiu.cpp:118
cacChannel & createChannel(epicsGuard< epicsMutex > &guard, const char *pChannelName, cacChannelNotify &, cacChannel::priLev)
Definition: cac.cpp:508
virtual void readNotifyRequest(epicsGuard< epicsMutex > &, nciu &, netReadNotifyIO &, unsigned type, arrayElementCount nElem)=0
Definition: netiiu.cpp:64
const T getId() const
Definition: resourceLib.h:1021
unsigned short ca_uint16_t
Definition: caProto.h:75
unsigned priLev
Definition: cacIO.h:165
bool valid() const
Definition: tsDLList.h:607
T * lookup(const ID &idIn) const
Definition: resourceLib.h:342
Miscellaneous macro definitions.
virtual unsigned getHostName(epicsGuard< epicsMutex > &, char *pBuf, unsigned bufLength) const =0
Definition: netiiu.cpp:93
#define ECA_DISCONN
Definition: caerr.h:101
LIBCA_API void registerIIU(epicsGuard< epicsMutex > &, tcpiiu &)
Definition: bhe.cpp:314
static unsigned highestPriorityLevelBelow(unsigned priority)
Definition: cac.cpp:374
LIBCA_API ~bhe()
Definition: bhe.cpp:62
virtual void release()=0
void installNewChannel(epicsGuard< epicsMutex > &, nciu &, netiiu *&)
Definition: udpiiu.cpp:1255
void installDisconnectedChannel(epicsGuard< epicsMutex > &, nciu &)
Definition: udpiiu.cpp:1262
#define CA_PROTO_ACCESS_RIGHT_READ
Definition: caProto.h:143
void exception epicsGuard< epicsMutex > epicsGuard< epicsMutex > int const char const char unsigned lineNo
Definition: cac.h:164
ca_uint16_t m_cmmd
Definition: caProto.h:161
LIBCOM_API void epicsStdCall freeListCleanup(void *pvt)
Definition: freeListLib.c:152
LIBCOM_API long epicsStdCall envGetDoubleConfigParam(const ENV_PARAM *pParam, double *pDouble)
Get value of a double configuration parameter.
Definition: envSubr.c:191
LIBCOM_API const ENV_PARAM EPICS_CA_SERVER_PORT
void release(void *)
Definition: bhe.cpp:349
unsigned ioid
Definition: cacIO.h:173
ca_uint32_t m_count
void writeException(epicsGuard< epicsMutex > &, epicsGuard< epicsMutex > &, int status, const char *pContext, unsigned type, arrayElementCount count)
Definition: nciu.h:327
int varArgsPrintFormated(epicsGuard< epicsMutex > &callbackControl, const char *pformat, va_list args) const
Definition: cac.h:363
#define ECA_NORMAL
Definition: caerr.h:77
bool executeResponse(callbackManager &, tcpiiu &, const epicsTime &currentTime, caHdrLargeArray &, char *pMsgBody)
Definition: cac.cpp:1204
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadLowestPriorityLevelAbove(unsigned int priority, unsigned *pPriorityJustAbove)
Definition: osdThread.c:757
void show(unsigned level) const
Definition: udpiiu.cpp:1143
netiiu * getPIIU(epicsGuard< epicsMutex > &)
Definition: nciu.h:321
LIBCOM_API long epicsStdCall envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool)
Get value of a boolean configuration parameter.
Definition: envSubr.c:325
void idAssignAdd(ITEM &item)
Definition: resourceLib.h:964
bool connectNotify(epicsGuard< epicsMutex > &, nciu &chan)
Definition: tcpiiu.cpp:1958
void removeAll(tsSLList< T > &destination)
Definition: resourceLib.h:327
epicsMutex mutex
Definition: pvAccess.cpp:71
cacChannel::priLev getPriority(epicsGuard< epicsMutex > &) const
Definition: nciu.h:348
virtual void uninstallChanDueToSuccessfulSearchResponse(epicsGuard< epicsMutex > &, nciu &, const class epicsTime &currentTime)=0
Definition: netiiu.cpp:159
ca_uint32_t m_cid
Definition: caProto.h:165
bool alive(epicsGuard< epicsMutex > &) const
char * allocate(unsigned int n)
Definition: antelope.c:230
LIBCOM_API unsigned short epicsStdCall envGetInetPortConfigParam(const ENV_PARAM *pEnv, unsigned short defaultPort)
Get value of a port number configuration parameter.
Definition: envSubr.c:398
void searchRespNotify(const epicsTime &, const caHdrLargeArray &)
Definition: tcpiiu.cpp:2193
void initiateConnect(epicsGuard< epicsMutex > &, nciu &, netiiu *&)
Definition: cac.cpp:1291
const netiiu * getConstPIIU(epicsGuard< epicsMutex > &) const
Definition: nciu.h:337
void shutdown(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: udpiiu.cpp:332
virtual void uninstallChan(epicsGuard< epicsMutex > &, nciu &)=0
Definition: netiiu.cpp:147
Definition: bhe.h:45
void registerSearchDest(epicsGuard< epicsMutex > &, SearchDest &req)
Definition: cac.cpp:1329
void release(void *)
Definition: cac.cpp:1305
void transferChanToVirtCircuit(unsigned cid, unsigned sid, ca_uint16_t typeCode, arrayElementCount count, unsigned minorVersionNumber, const osiSockAddr &, const epicsTime &currentTime)
Definition: cac.cpp:587
ca_uint16_t m_postsize
Definition: caProto.h:162
void exception epicsGuard< epicsMutex > & cbGuard
Definition: cac.h:164
bool destroyIO(CallbackGuard &callbackGuard, epicsGuard< epicsMutex > &mutualExclusionGuard, const cacChannel::ioid &idIn, nciu &chan)
Definition: cac.cpp:734
void flush(epicsGuard< epicsMutex > &guard)
Definition: cac.cpp:389
ca_uint16_t m_dataType
Definition: caProto.h:163
#define NELEMENTS(A)
Definition: aToIPAddr.c:21
void destroyChannel(epicsGuard< epicsMutex > &, nciu &)
Definition: cac.cpp:659
void ioInitiate(const osiSockAddr &rej)
LIBCOM_API void epicsStdCall epicsSignalInstallSigAlarmIgnore(void)
Definition: osdSignal.cpp:18
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
double beaconPeriod(epicsGuard< epicsMutex > &, const nciu &chan) const
Definition: cac.cpp:1273
bool ca_v41_ok(epicsGuard< epicsMutex > &) const
~tcpiiu()
Definition: tcpiiu.cpp:1014
T * get()
Definition: tsSLList.h:220
struct ca_hdr caHdr
ca_uint16_t m_count
Definition: caProto.h:164
epicsGuard< epicsMutex > cbGuard
Definition: cac.h:94
LIBCA_API void unregisterIIU(epicsGuard< epicsMutex > &, tcpiiu &)
Definition: bhe.cpp:321
ca_uint32_t m_cid
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadHighestPriorityLevelBelow(unsigned int priority, unsigned *pPriorityJustBelow)
Definition: osdThread.c:740
virtual class netSubscription * isSubscription()=0
T * remove(const ID &idIn)
Definition: resourceLib.h:297
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
Definition: osdThread.c:707
unsigned long arrayElementCount
Definition: cacIO.h:57
bool findOrCreateVirtCircuit(epicsGuard< epicsMutex > &, const osiSockAddr &, unsigned, tcpiiu *&, unsigned, SearchDestTCP *pSearchDest=NULL)
Definition: cac.cpp:535
T * get()
Definition: tsDLList.h:261
#define CA_PROTO_ACCESS_RIGHT_WRITE
Definition: caProto.h:144
void beaconNotify(const inetAddrID &addr, const epicsTime &currentTime, ca_uint32_t beaconNumber, unsigned protocolRevision)
Definition: cac.cpp:454
#define ECA_DBLCHNL
Definition: caerr.h:102
void unsubscribeIfRequired(epicsGuard< epicsMutex > &guard, nciu &chan)
void disconnectAllIO(epicsGuard< epicsMutex > &, epicsGuard< epicsMutex > &)
Definition: nciu.cpp:558
void show(unsigned level) const
Definition: resourceLib.h:371
LIBCOM_API long epicsStdCall envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong)
Get value of a long configuration parameter.
Definition: envSubr.c:303
LIBCOM_API osiGetUserNameReturn epicsStdCall osiGetUserName(char *pBuf, unsigned bufSizeIn)
Definition: osdProcess.c:33
#define ECA_CHANDESTROY
Definition: caerr.h:132
int(* pProtoStubTCP)(caHdrLargeArray *mp, void *pPayload, struct client *client)
Definition: camessage.c:2315
virtual void show(unsigned level) const =0
void show(epicsGuard< epicsMutex > &, unsigned level) const
Definition: cac.cpp:406
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
#define genLocalExcep(CBGUARD, GUARD, CAC, STAT, PCTX)
Definition: iocinf.h:66
virtual void completion(epicsGuard< epicsMutex > &, cacRecycle &)=0
void release(void *p)
Definition: tsFreeList.h:176
netSubscription & subscriptionRequest(epicsGuard< epicsMutex > &, nciu &, privateInterfaceForIO &, unsigned type, arrayElementCount nElem, unsigned mask, cacStateNotify &, bool channelIsInstalled)
Definition: cac.cpp:809
ca_uint16_t m_cmmd
Definition: udpiiu.h:79
osiGetUserNameReturn
Definition: osiProcess.h:25
static unsigned capacityBytes()
Definition: comBuf.h:171
int osiSockAttach()
Definition: osdSock.c:54
void exception epicsGuard< epicsMutex > epicsGuard< epicsMutex > int const char const char * pFileName
Definition: cac.h:164
static unsigned lowestPriorityLevelAbove(unsigned priority)
Definition: cac.cpp:362
void remove(T &item)
Definition: tsDLList.h:219
LIBCOM_API const ENV_PARAM EPICS_CA_CONN_TMO
ca_uint32_t m_available
unsigned channelCount(epicsGuard< epicsMutex > &)
Definition: tcpiiu.cpp:2113
OS-independent routines for ignoring Posix signals.
LIBCA_API double period(epicsGuard< epicsMutex > &) const
Definition: bhe.cpp:302
void clearChannelRequest(epicsGuard< epicsMutex > &, ca_uint32_t sid, ca_uint32_t cid)
Definition: tcpiiu.cpp:1536
List header type.
Definition: ellLib.h:56
void disconnectAllIO(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard, nciu &, tsDLList< baseNMIU > &ioList)
Definition: cac.cpp:674
Definition: netiiu.h:37
#define throwWithLocation(parm)
void probeResponseNotify(epicsGuard< epicsMutex > &)
unsigned circuitCount(epicsGuard< epicsMutex > &) const
Definition: cac.cpp:399
LIBCOM_API const ENV_PARAM EPICS_CA_AUTO_ARRAY_BYTES
void verify() const
Definition: resourceLib.h:432
netReadNotifyIO & readNotifyRequest(epicsGuard< epicsMutex > &, nciu &, privateInterfaceForIO &, unsigned type, arrayElementCount nElem, cacReadNotify &)
Definition: cac.cpp:721
void name(char *pBuf, unsigned bufSize) const
Definition: inetAddrID.h:64
int epicsStdCall sockAddrAreIdentical(const osiSockAddr *plhs, const osiSockAddr *prhs)
Definition: osiSock.c:35
unsigned getHostName(epicsGuard< epicsMutex > &, char *pBuf, unsigned bufLength) const
Definition: tcpiiu.cpp:1791
ca_uint32_t getSID(epicsGuard< epicsMutex > &) const
Definition: nciu.h:291
static netReadNotifyIO * factory(tsFreeList< class netReadNotifyIO, 1024, epicsMutexNOOP > &, privateInterfaceForIO &, cacReadNotify &)
Definition: netIO.h:263
int printFormated(epicsGuard< epicsMutex > &callbackControl, const char *pformat,...) const
Definition: cac.cpp:696
#define false
Definition: flexdef.h:85
static const priLev priorityDefault
Definition: cacIO.h:168
noopiiu noopIIU
Definition: noopiiu.cpp:28
cac(epicsMutex &mutualExclusion, epicsMutex &callbackControl, cacContextNotify &)
Definition: cac.cpp:127
void versionRespNotify(const caHdrLargeArray &)
Definition: tcpiiu.cpp:2188
Definition: nciu.h:127
void accessRightsStateChange(const caAccessRights &, epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: nciu.cpp:196
Exporting IOC objects.
netWriteNotifyIO & writeNotifyRequest(epicsGuard< epicsMutex > &, nciu &, privateInterfaceForIO &, unsigned type, arrayElementCount nElem, const void *pValue, cacWriteNotify &)
Definition: cac.cpp:707
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810
virtual void writeNotifyRequest(epicsGuard< epicsMutex > &, nciu &, netWriteNotifyIO &, unsigned type, arrayElementCount nElem, const void *pValue)=0
Definition: netiiu.cpp:56