This is Unofficial EPICS BASE Doxygen Site
udpiiu.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  *
12  * L O S A L A M O S
13  * Los Alamos National Laboratory
14  * Los Alamos, New Mexico 87545
15  *
16  * Copyright, 1986, The Regents of the University of California.
17  *
18  * Author: Jeff Hill
19  */
20 
21 #ifdef _MSC_VER
22 # pragma warning(disable:4355)
23 #endif
24 
25 #define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
26 
27 #include "envDefs.h"
28 #include "dbDefs.h"
29 #include "osiProcess.h"
30 #include "osiWireFormat.h"
31 #include "epicsAlgorithm.h"
32 #include "errlog.h"
33 #include "locationException.h"
34 
35 #include "addrList.h"
36 #include "caerr.h" // for ECA_NOSEARCHADDR
37 #include "udpiiu.h"
38 #include "iocinf.h"
39 #include "inetAddrID.h"
40 #include "cac.h"
42 
43 // UDP protocol dispatch table
44 const udpiiu::pProtoStubUDP udpiiu::udpJumpTableCAC [] =
45 {
46  &udpiiu::versionAction,
47  &udpiiu::badUDPRespAction,
48  &udpiiu::badUDPRespAction,
49  &udpiiu::badUDPRespAction,
50  &udpiiu::badUDPRespAction,
51  &udpiiu::badUDPRespAction,
52  &udpiiu::searchRespAction,
53  &udpiiu::badUDPRespAction,
54  &udpiiu::badUDPRespAction,
55  &udpiiu::badUDPRespAction,
56  &udpiiu::badUDPRespAction,
57  &udpiiu::exceptionRespAction,
58  &udpiiu::badUDPRespAction,
59  &udpiiu::beaconAction,
60  &udpiiu::notHereRespAction,
61  &udpiiu::badUDPRespAction,
62  &udpiiu::badUDPRespAction,
63  &udpiiu::repeaterAckAction,
64 };
65 
66 
67 static
68 double getMaxPeriod()
69 {
70  double maxPeriod = maxSearchPeriodDefault;
71 
73  long longStatus = envGetDoubleConfigParam (
74  & EPICS_CA_MAX_SEARCH_PERIOD, & maxPeriod );
75  if ( ! longStatus ) {
76  if ( maxPeriod < maxSearchPeriodLowerLimit ) {
77  epicsPrintf ( "\"%s\" out of range (low)\n",
79  maxPeriod = maxSearchPeriodLowerLimit;
80  epicsPrintf ( "Setting \"%s\" = %f seconds\n",
81  EPICS_CA_MAX_SEARCH_PERIOD.name, maxPeriod );
82  }
83  }
84  else {
85  epicsPrintf ( "EPICS \"%s\" wasnt a real number\n",
87  epicsPrintf ( "Setting \"%s\" = %f seconds\n",
88  EPICS_CA_MAX_SEARCH_PERIOD.name, maxPeriod );
89  }
90  }
91 
92  return maxPeriod;
93 }
94 
95 static
96 unsigned getNTimers(double maxPeriod)
97 {
98  unsigned nTimers = static_cast < unsigned > ( 1.0 + log ( maxPeriod / minRoundTripEstimate ) / log ( 2.0 ) );
99 
100  if ( nTimers > channelNode::getMaxSearchTimerCount () ) {
102  epicsPrintf ( "\"%s\" out of range (high)\n",
104  epicsPrintf ( "Setting \"%s\" = %f seconds\n",
106  (1<<(nTimers-1)) * minRoundTripEstimate );
107  }
108 
109  return nTimers;
110 }
111 
112 //
113 // udpiiu::udpiiu ()
114 //
116  epicsGuard < epicsMutex > & cacGuard,
117  epicsTimerQueueActive & timerQueue,
118  epicsMutex & cbMutexIn,
119  epicsMutex & cacMutexIn,
120  cacContextNotify & ctxNotifyIn,
121  cac & cac,
122  unsigned port,
123  tsDLList < SearchDest > & searchDestListIn ) :
124  recvThread ( *this, ctxNotifyIn, cbMutexIn, "CAC-UDP",
126  cac::lowestPriorityLevelAbove (
127  cac::lowestPriorityLevelAbove (
128  cac.getInitializingThreadsPriority () ) ) ),
129  m_repeaterTimerNotify ( *this ),
130  repeaterSubscribeTmr (
131  m_repeaterTimerNotify, timerQueue, cbMutexIn, ctxNotifyIn ),
132  govTmr ( *this, timerQueue, cacMutexIn ),
133  maxPeriod ( getMaxPeriod() ),
134  rtteMean ( minRoundTripEstimate ),
135  rtteMeanDev ( 0 ),
136  cacRef ( cac ),
137  cbMutex ( cbMutexIn ),
138  cacMutex ( cacMutexIn ),
139  nTimers ( getNTimers(maxPeriod) ),
140  ppSearchTmr ( nTimers ),
141  nBytesInXmitBuf ( 0 ),
142  beaconAnomalyTimerIndex ( 0 ),
143  sequenceNumber ( 0 ),
144  lastReceivedSeqNo ( 0 ),
145  sock ( 0 ),
146  repeaterPort ( 0 ),
147  serverPort ( port ),
148  localPort ( 0 ),
149  shutdownCmd ( false ),
150  lastReceivedSeqNoIsValid ( false )
151 {
152  cacGuard.assertIdenticalMutex ( cacMutex );
153 
154  double powerOfTwo = log ( beaconAnomalySearchPeriod / minRoundTripEstimate ) / log ( 2.0 );
155  this->beaconAnomalyTimerIndex = static_cast < unsigned > ( powerOfTwo + 1.0 );
156  if ( this->beaconAnomalyTimerIndex >= this->nTimers ) {
157  this->beaconAnomalyTimerIndex = this->nTimers - 1;
158  }
159 
160  for ( unsigned i = 0; i < this->nTimers; i++ ) {
161  this->ppSearchTmr[i].reset (
162  new searchTimer ( *this, timerQueue, i, cacMutexIn,
163  i > this->beaconAnomalyTimerIndex ) );
164  }
165 
166  this->repeaterPort =
168  static_cast <unsigned short> (CA_REPEATER_PORT) );
169 
170  this->sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
171  if ( this->sock == INVALID_SOCKET ) {
172  char sockErrBuf[64];
174  sockErrBuf, sizeof ( sockErrBuf ) );
175  errlogPrintf ("CAC: unable to create datagram socket because = \"%s\"\n",
176  sockErrBuf );
178  }
179 
180 #ifdef IP_ADD_MEMBERSHIP
181  {
182  osiSockOptMcastLoop_t flag = 1;
183  if ( setsockopt ( this->sock, IPPROTO_IP, IP_MULTICAST_LOOP,
184  (char *) &flag, sizeof ( flag ) ) == -1 ) {
185  char sockErrBuf[64];
187  sockErrBuf, sizeof ( sockErrBuf ) );
188  errlogPrintf("CAC: failed to set mcast loopback\n");
189  }
190  }
191 #endif
192 
193 #ifdef IP_MULTICAST_TTL
194  {
196  long val;
198  val =1;
199  ttl = val;
200  if ( setsockopt(this->sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl))) {
201  char sockErrBuf[64];
203  sockErrBuf, sizeof ( sockErrBuf ) );
204  errlogPrintf("CAC: failed to set mcast ttl %d\n", ttl);
205  }
206  }
207 #endif
208 
209  int boolValue = true;
210  int status = setsockopt ( this->sock, SOL_SOCKET, SO_BROADCAST,
211  (char *) &boolValue, sizeof ( boolValue ) );
212  if ( status < 0 ) {
213  char sockErrBuf[64];
215  sockErrBuf, sizeof ( sockErrBuf ) );
216  errlogPrintf ("CAC: IP broadcasting enable failed because = \"%s\"\n",
217  sockErrBuf );
218  }
219 
220 #if 0
221  {
222  /*
223  * some concern that vxWorks will run out of mBuf's
224  * if this change is made joh 11-10-98
225  *
226  * bump up the UDP recv buffer
227  */
228  int size = 1u<<15u;
229  status = setsockopt ( this->sock, SOL_SOCKET, SO_RCVBUF,
230  (char *)&size, sizeof (size) );
231  if (status<0) {
232  char sockErrBuf[64];
233  epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
234  errlogPrintf ( "CAC: unable to set socket option SO_RCVBUF because \"%s\"\n",
235  sockErrBuf );
236  }
237  }
238 #endif
239 
240  // force a bind to an unconstrained address so we can obtain
241  // the local port number below
242  static const unsigned short PORT_ANY = 0u;
243  osiSockAddr addr;
244  memset ( (char *)&addr, 0 , sizeof (addr) );
245  addr.ia.sin_family = AF_INET;
246  addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
247  addr.ia.sin_port = htons ( PORT_ANY );
248  status = bind (this->sock, &addr.sa, sizeof (addr) );
249  if ( status < 0 ) {
250  char sockErrBuf[64];
252  sockErrBuf, sizeof ( sockErrBuf ) );
253  epicsSocketDestroy (this->sock);
254  errlogPrintf ( "CAC: unable to bind to an unconstrained address because = \"%s\"\n",
255  sockErrBuf );
257  }
258 
259  {
260  osiSockAddr tmpAddr;
261  osiSocklen_t saddr_length = sizeof ( tmpAddr );
262  status = getsockname ( this->sock, &tmpAddr.sa, &saddr_length );
263  if ( status < 0 ) {
264  char sockErrBuf[64];
266  sockErrBuf, sizeof ( sockErrBuf ) );
267  epicsSocketDestroy ( this->sock );
268  errlogPrintf ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf );
270  }
271  if ( tmpAddr.sa.sa_family != AF_INET) {
272  epicsSocketDestroy ( this->sock );
273  errlogPrintf ( "CAC: UDP socket was not inet addr family\n" );
275  }
276  this->localPort = ntohs ( tmpAddr.ia.sin_port );
277  }
278 
279  /*
280  * load user and auto configured
281  * broadcast address list
282  */
283  ELLLIST dest;
284  ellInit ( & dest );
285  configureChannelAccessAddressList ( & dest, this->sock, this->serverPort );
286  while ( osiSockAddrNode *
287  pNode = reinterpret_cast < osiSockAddrNode * > ( ellGet ( & dest ) ) ) {
288  SearchDestUDP & searchDest = *
289  new SearchDestUDP ( pNode->addr, *this );
290  _searchDestList.add ( searchDest );
291  free ( pNode );
292  }
293 
294  /* add list of tcp name service addresses */
295  _searchDestList.add ( searchDestListIn );
296 
297  caStartRepeaterIfNotInstalled ( this->repeaterPort );
298 
299  this->pushVersionMsg ();
300 
301  // start timers and receive thread
302  for ( unsigned j =0; j < this->nTimers; j++ ) {
303  this->ppSearchTmr[j]->start ( cacGuard );
304  }
305  this->govTmr.start ();
306  this->repeaterSubscribeTmr.start ();
307  this->recvThread.start ();
308 }
309 
310 /*
311  * udpiiu::~udpiiu ()
312  */
314 {
315  {
316  epicsGuard < epicsMutex > cbGuard ( this->cbMutex );
317  epicsGuard < epicsMutex > guard ( this->cacMutex );
318  this->shutdown ( cbGuard, guard );
319  }
320 
321  tsDLIter < SearchDest > iter ( _searchDestList.firstIter () );
322  while ( iter.valid () )
323  {
324  SearchDest & curr ( *iter );
325  iter++;
326  delete & curr;
327  }
328 
329  epicsSocketDestroy ( this->sock );
330 }
331 
333  epicsGuard < epicsMutex > & cbGuard,
334  epicsGuard < epicsMutex > & guard )
335 {
336  // stop all of the timers
337  this->repeaterSubscribeTmr.shutdown ( cbGuard, guard );
338  this->govTmr.shutdown ( cbGuard, guard );
339  for ( unsigned i =0; i < this->nTimers; i++ ) {
340  this->ppSearchTmr[i]->shutdown ( cbGuard, guard );
341  }
342 
343  {
344  this->shutdownCmd = true;
345  epicsGuardRelease < epicsMutex > unguard ( guard );
346  {
347  epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard );
348 
349  if ( ! this->recvThread.exitWait ( 0.0 ) ) {
350  unsigned tries = 0u;
351 
352  this->wakeupMsg ();
353 
354  // wait for recv threads to exit
355  double shutdownDelay = 1.0;
356  while ( ! this->recvThread.exitWait ( shutdownDelay ) ) {
357  this->wakeupMsg ();
358  if ( shutdownDelay < 16.0 ) {
359  shutdownDelay += shutdownDelay;
360  }
361  if ( ++tries > 3 ) {
362  fprintf ( stderr, "cac: timing out waiting for UDP thread shutdown\n" );
363  }
364  }
365  }
366  }
367  }
368 }
369 
371  udpiiu & iiuIn, cacContextNotify & ctxNotifyIn, epicsMutex & cbMutexIn,
372  const char * pName, unsigned stackSize, unsigned priority ) :
373  iiu ( iiuIn ), cbMutex ( cbMutexIn ), ctxNotify ( ctxNotifyIn ),
374  thread ( *this, pName, stackSize, priority ) {}
375 
377 {
378 }
379 
381 {
382  this->thread.start ();
383 }
384 
385 bool udpRecvThread::exitWait ( double delay )
386 {
387  return this->thread.exitWait ( delay );
388 }
389 
390 void udpRecvThread::show ( unsigned /* level */ ) const
391 {
392 }
393 
394 void udpRecvThread::run ()
395 {
397 
398  if ( this->iiu._searchDestList.count () == 0 ) {
399  callbackManager mgr ( this->ctxNotify, this->cbMutex );
400  epicsGuard < epicsMutex > guard ( this->iiu.cacMutex );
401  genLocalExcep ( mgr.cbGuard, guard,
402  this->iiu.cacRef, ECA_NOSEARCHADDR, NULL );
403  }
404 
405  do {
406  osiSockAddr src;
407  osiSocklen_t src_size = sizeof ( src );
408  int status = recvfrom ( this->iiu.sock,
409  this->iiu.recvBuf, sizeof ( this->iiu.recvBuf ), 0,
410  & src.sa, & src_size );
411 
412  if ( status <= 0 ) {
413 
414  if ( status < 0 ) {
415  int errnoCpy = SOCKERRNO;
416  if (
417  errnoCpy != SOCK_EINTR &&
418  errnoCpy != SOCK_SHUTDOWN &&
419  errnoCpy != SOCK_ENOTSOCK &&
420  errnoCpy != SOCK_EBADF &&
421  // Avoid spurious ECONNREFUSED bug in linux
422  errnoCpy != SOCK_ECONNREFUSED &&
423  // Avoid ECONNRESET from disconnected socket bug
424  // in windows
425  errnoCpy != SOCK_ECONNRESET ) {
426 
427  char sockErrBuf[64];
429  sockErrBuf, sizeof ( sockErrBuf ) );
430  errlogPrintf ( "CAC: UDP recv error was \"%s\"\n",
431  sockErrBuf );
432  }
433  }
434  }
435  else if ( status > 0 ) {
436  this->iiu.postMsg ( src, this->iiu.recvBuf,
437  (arrayElementCount) status, epicsTime::getCurrent() );
438  }
439 
440  } while ( ! this->iiu.shutdownCmd );
441 }
442 
443 /* for sunpro compiler */
444 udpiiu::M_repeaterTimerNotify::~M_repeaterTimerNotify ()
445 {
446 }
447 
448 /*
449  * udpiiu::M_repeaterTimerNotify::repeaterRegistrationMessage ()
450  *
451  * register with the repeater
452  */
453 void udpiiu :: M_repeaterTimerNotify :: repeaterRegistrationMessage ( unsigned attemptNumber )
454 {
455  epicsGuard < epicsMutex > cbGuard ( m_udpiiu.cacMutex );
456  caRepeaterRegistrationMessage ( m_udpiiu.sock, m_udpiiu.repeaterPort, attemptNumber );
457 }
458 
459 /*
460  * caRepeaterRegistrationMessage ()
461  *
462  * register with the repeater
463  */
464 void epicsStdCall caRepeaterRegistrationMessage (
465  SOCKET sock, unsigned repeaterPort, unsigned attemptNumber )
466 {
467  osiSockAddr saddr;
468  caHdr msg;
469  int status;
470  int len;
471 
472  assert ( repeaterPort <= USHRT_MAX );
473  unsigned short port = static_cast <unsigned short> ( repeaterPort );
474 
475  /*
476  * In 3.13 beta 11 and before the CA repeater calls local_addr()
477  * to determine a local address and does not allow registration
478  * messages originating from other addresses. In these
479  * releases local_addr() returned the address of the first enabled
480  * interface found, and this address may or may not have been the loop
481  * back address. Starting with 3.13 beta 12 local_addr() was
482  * changed to always return the address of the first enabled
483  * non-loopback interface because a valid non-loopback local
484  * address is required in the beacon messages. Therefore, to
485  * guarantee compatibility with past versions of the repeater
486  * we alternate between the address returned by local_addr()
487  * and the loopback address here.
488  *
489  * CA repeaters in R3.13 beta 12 and higher allow
490  * either the loopback address or the address returned
491  * by local address (the first non-loopback address found)
492  */
493  if ( attemptNumber & 1 ) {
494  saddr = osiLocalAddr ( sock );
495  if ( saddr.sa.sa_family != AF_INET ) {
496  /*
497  * use the loop back address to communicate with the CA repeater
498  * if this os does not have interface query capabilities
499  *
500  * this will only work with 3.13 beta 12 CA repeaters or later
501  */
502  saddr.ia.sin_family = AF_INET;
503  saddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
504  saddr.ia.sin_port = htons ( port );
505  }
506  else {
507  saddr.ia.sin_port = htons ( port );
508  }
509  }
510  else {
511  saddr.ia.sin_family = AF_INET;
512  saddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
513  saddr.ia.sin_port = htons ( port );
514  }
515 
516  memset ( (char *) &msg, 0, sizeof (msg) );
518  msg.m_available = saddr.ia.sin_addr.s_addr;
519 
520  /*
521  * Intentionally sending a zero length message here
522  * until most CA repeater daemons have been restarted
523  * (and only then will they accept the above protocol)
524  * (repeaters began accepting this protocol
525  * starting with EPICS 3.12)
526  */
527 # if defined ( DOES_NOT_ACCEPT_ZERO_LENGTH_UDP )
528  len = sizeof (msg);
529 # else
530  len = 0;
531 # endif
532 
533  status = sendto ( sock, (char *) &msg, len, 0,
534  &saddr.sa, sizeof ( saddr ) );
535  if ( status < 0 ) {
536  int errnoCpy = SOCKERRNO;
537  /*
538  * Different OS return different codes when the repeater isnt running.
539  * Its ok to supress these messages because I print another warning message
540  * if we time out registerring with the repeater.
541  *
542  * Linux returns SOCK_ECONNREFUSED
543  * Windows 2000 returns SOCK_ECONNRESET
544  */
545  if ( errnoCpy != SOCK_EINTR &&
546  errnoCpy != SOCK_ECONNREFUSED &&
547  errnoCpy != SOCK_ECONNRESET ) {
548  char sockErrBuf[64];
550  sockErrBuf, sizeof ( sockErrBuf ) );
551  fprintf ( stderr, "error sending registration message to CA repeater daemon was \"%s\"\n",
552  sockErrBuf );
553  }
554  }
555 }
556 
557 /*
558  * caStartRepeaterIfNotInstalled ()
559  *
560  * Test for the repeater already installed
561  *
562  * NOTE: potential race condition here can result
563  * in two copies of the repeater being spawned
564  * however the repeater detects this, prints a message,
565  * and lets the other task start the repeater.
566  *
567  * QUESTION: is there a better way to test for a port in use?
568  * ANSWER: none that I can find.
569  *
570  * Problems with checking for the repeater installed
571  * by attempting to bind a socket to its address
572  * and port.
573  *
574  * 1) Closed socket may not release the bound port
575  * before the repeater wakes up and tries to grab it.
576  * Attempting to bind the open socket to another port
577  * also does not work.
578  *
579  * 072392 - problem solved by using SO_REUSEADDR
580  */
581 void epicsStdCall caStartRepeaterIfNotInstalled ( unsigned repeaterPort )
582 {
583  bool installed = false;
584  int status;
585  SOCKET tmpSock;
586  union {
587  struct sockaddr_in ia;
588  struct sockaddr sa;
589  } bd;
590 
591  if ( repeaterPort > 0xffff ) {
592  fprintf ( stderr, "caStartRepeaterIfNotInstalled () : strange repeater port specified\n" );
593  return;
594  }
595 
596  tmpSock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
597  if ( tmpSock != INVALID_SOCKET ) {
598  ca_uint16_t port = static_cast < ca_uint16_t > ( repeaterPort );
599  memset ( (char *) &bd, 0, sizeof ( bd ) );
600  bd.ia.sin_family = AF_INET;
601  bd.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
602  bd.ia.sin_port = htons ( port );
603  status = bind ( tmpSock, &bd.sa, sizeof ( bd ) );
604  if ( status < 0 ) {
605  if ( SOCKERRNO == SOCK_EADDRINUSE ) {
606  installed = true;
607  }
608  else {
609  fprintf ( stderr, "caStartRepeaterIfNotInstalled () : bind failed\n" );
610  }
611  }
612  }
613 
614  /*
615  * turn on reuse only after the test so that
616  * this works on kernels that support multicast
617  */
619 
620  epicsSocketDestroy ( tmpSock );
621 
622  if ( ! installed ) {
623 
624  /*
625  * This is not called if the repeater is known to be
626  * already running. (in the event of a race condition
627  * the 2nd repeater exits when unable to attach to the
628  * repeater's port)
629  */
631  osiSpawnDetachedProcess ( "CA Repeater", "caRepeater" );
632  if ( osptr == osiSpawnDetachedProcessNoSupport ) {
633  epicsThreadId tid;
634 
635  tid = epicsThreadCreate ( "CAC-repeater", epicsThreadPriorityLow,
637  if ( tid == 0 ) {
638  fprintf ( stderr, "caStartRepeaterIfNotInstalled : unable to create CA repeater daemon thread\n" );
639  }
640  }
641  else if ( osptr == osiSpawnDetachedProcessFail ) {
642  fprintf ( stderr, "caStartRepeaterIfNotInstalled (): unable to start CA repeater daemon detached process\n" );
643  }
644  }
645 }
646 
647 bool udpiiu::badUDPRespAction (
648  const caHdr &msg, const osiSockAddr &netAddr, const epicsTime &currentTime )
649 {
650  char buf[64];
651  sockAddrToDottedIP ( &netAddr.sa, buf, sizeof ( buf ) );
652  char date[64];
653  currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
654  errlogPrintf ( "CAC: Undecipherable ( bad msg code %u ) UDP message from %s at %s\n",
655  msg.m_cmmd, buf, date );
656  return false;
657 }
658 
659 bool udpiiu::versionAction (
660  const caHdr & hdr, const osiSockAddr &, const epicsTime & /* currentTime */ )
661 {
662  epicsGuard < epicsMutex > guard ( this->cacMutex );
663 
664  // update the round trip time estimate
665  if ( hdr.m_dataType & sequenceNoIsValid ) {
666  this->lastReceivedSeqNo = hdr.m_cid;
667  this->lastReceivedSeqNoIsValid = true;
668  }
669 
670  return true;
671 }
672 
673 bool udpiiu :: searchRespAction (
674  const caHdr & msg, const osiSockAddr & addr,
675  const epicsTime & currentTime )
676 {
677  /*
678  * we dont currently know what to do with channel's
679  * found to be at non-IP type addresses
680  */
681  if ( addr.sa.sa_family != AF_INET ) {
682  return true;
683  }
684 
685  /*
686  * Starting with CA V4.1 the minor version number
687  * is appended to the end of each UDP search reply.
688  * This value is ignored by earlier clients.
689  */
690  ca_uint32_t minorVersion;
691  if ( msg.m_postsize >= sizeof ( minorVersion ) ){
692  /*
693  * care is taken here not to break gcc 3.2 aggressive alias
694  * analysis rules
695  */
696  const ca_uint8_t * pPayLoad =
697  reinterpret_cast < const ca_uint8_t *> ( & msg + 1 );
698  unsigned byte0 = pPayLoad[0];
699  unsigned byte1 = pPayLoad[1];
700  minorVersion = ( byte0 << 8u ) | byte1;
701  }
702  else {
703  minorVersion = CA_UKN_MINOR_VERSION;
704  }
705 
706  /*
707  * the type field is abused to carry the port number
708  * so that we can have multiple servers on one host
709  */
710  osiSockAddr serverAddr;
711  serverAddr.ia.sin_family = AF_INET;
712  if ( CA_V48 ( minorVersion ) ) {
713  if ( msg.m_cid != INADDR_BROADCAST ) {
714  serverAddr.ia.sin_addr.s_addr = htonl ( msg.m_cid );
715  }
716  else {
717  serverAddr.ia.sin_addr = addr.ia.sin_addr;
718  }
719  serverAddr.ia.sin_port = htons ( msg.m_dataType );
720  }
721  else if ( CA_V45 (minorVersion) ) {
722  serverAddr.ia.sin_port = htons ( msg.m_dataType );
723  serverAddr.ia.sin_addr = addr.ia.sin_addr;
724  }
725  else {
726  serverAddr.ia.sin_port = htons ( this->serverPort );
727  serverAddr.ia.sin_addr = addr.ia.sin_addr;
728  }
729 
730  if ( CA_V42 ( minorVersion ) ) {
731  cacRef.transferChanToVirtCircuit
732  ( msg.m_available, msg.m_cid, 0xffff,
733  0, minorVersion, serverAddr, currentTime );
734  }
735  else {
736  cacRef.transferChanToVirtCircuit
737  ( msg.m_available, msg.m_cid, msg.m_dataType,
738  msg.m_count, minorVersion, serverAddr, currentTime );
739  }
740 
741  return true;
742 }
743 
744 bool udpiiu::beaconAction (
745  const caHdr & msg,
746  const osiSockAddr & net_addr, const epicsTime & currentTime )
747 {
748  struct sockaddr_in ina;
749 
750  memset(&ina, 0, sizeof(struct sockaddr_in));
751 
752  if ( net_addr.sa.sa_family != AF_INET ) {
753  return false;
754  }
755 
756  /*
757  * this allows a fan-out server to potentially
758  * insert the true address of the CA server
759  *
760  * old servers:
761  * 1) set this field to one of the ip addresses of the host _or_
762  * 2) set this field to INADDR_ANY
763  * new servers:
764  * always set this field to INADDR_ANY
765  *
766  * clients always assume that if this
767  * field is set to something that isnt INADDR_ANY
768  * then it is the overriding IP address of the server.
769  */
770  ina.sin_family = AF_INET;
771  ina.sin_addr.s_addr = htonl ( msg.m_available );
772  if ( msg.m_count != 0 ) {
773  ina.sin_port = htons ( msg.m_count );
774  }
775  else {
776  /*
777  * old servers dont supply this and the
778  * default port must be assumed
779  */
780  ina.sin_port = htons ( this->serverPort );
781  }
782  unsigned protocolRevision = msg.m_dataType;
783  ca_uint32_t beaconNumber = msg.m_cid;
784 
785  this->cacRef.beaconNotify ( ina, currentTime,
786  beaconNumber, protocolRevision );
787 
788  return true;
789 }
790 
791 bool udpiiu::repeaterAckAction (
792  const caHdr &,
793  const osiSockAddr &, const epicsTime &)
794 {
795  this->repeaterSubscribeTmr.confirmNotify ();
796  return true;
797 }
798 
799 bool udpiiu::notHereRespAction (
800  const caHdr &,
801  const osiSockAddr &, const epicsTime & )
802 {
803  return true;
804 }
805 
806 bool udpiiu::exceptionRespAction (
807  const caHdr &msg,
808  const osiSockAddr & net_addr, const epicsTime & currentTime )
809 {
810  const caHdr &reqMsg = * ( &msg + 1 );
811  char name[64];
812  sockAddrToDottedIP ( &net_addr.sa, name, sizeof ( name ) );
813  char date[64];
814  currentTime.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
815 
816  if ( msg.m_postsize > sizeof ( caHdr ) ){
817  errlogPrintf (
818  "error condition \"%s\" detected by %s with context \"%s\" at %s\n",
819  ca_message ( msg.m_available ),
820  name, reinterpret_cast <const char *> ( &reqMsg + 1 ), date );
821  }
822  else{
823  errlogPrintf (
824  "error condition \"%s\" detected by %s at %s\n",
825  ca_message ( msg.m_available ), name, date );
826  }
827 
828  return true;
829 }
830 
831 void udpiiu::postMsg (
832  const osiSockAddr & net_addr,
833  char * pInBuf, arrayElementCount blockSize,
834  const epicsTime & currentTime )
835 {
836  caHdr *pCurMsg;
837 
838  this->lastReceivedSeqNoIsValid = false;
839  this->lastReceivedSeqNo = 0u;
840 
841  while ( blockSize ) {
842  arrayElementCount size;
843 
844  if ( blockSize < sizeof ( *pCurMsg ) ) {
845  char buf[64];
846  sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) );
847  errlogPrintf (
848  "%s: Undecipherable (too small) UDP msg from %s ignored\n",
849  __FILE__, buf );
850  return;
851  }
852 
853  pCurMsg = reinterpret_cast < caHdr * > ( pInBuf );
854 
855  /*
856  * fix endian of bytes
857  */
858  pCurMsg->m_postsize = AlignedWireRef < epicsUInt16 > ( pCurMsg->m_postsize );
859  pCurMsg->m_cmmd = AlignedWireRef < epicsUInt16 > ( pCurMsg->m_cmmd );
860  pCurMsg->m_dataType = AlignedWireRef < epicsUInt16 > ( pCurMsg->m_dataType );
861  pCurMsg->m_count = AlignedWireRef < epicsUInt16 > ( pCurMsg->m_count );
863  pCurMsg->m_cid = AlignedWireRef < epicsUInt32 > ( pCurMsg->m_cid );
864 
865 #if 0
866  printf ( "UDP Cmd=%3d Type=%3d Count=%4d Size=%4d",
867  pCurMsg->m_cmmd,
868  pCurMsg->m_dataType,
869  pCurMsg->m_count,
870  pCurMsg->m_postsize );
871  printf (" Avail=%8x Cid=%6d\n",
872  pCurMsg->m_available,
873  pCurMsg->m_cid );
874 #endif
875 
876  size = pCurMsg->m_postsize + sizeof ( *pCurMsg );
877 
878  /*
879  * dont allow msg body extending beyond frame boundary
880  */
881  if ( size > blockSize ) {
882  char buf[64];
883  sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) );
884  errlogPrintf (
885  "%s: Undecipherable (payload too small) UDP msg from %s ignored\n",
886  __FILE__, buf );
887  return;
888  }
889 
890  /*
891  * execute the response message
892  */
893  pProtoStubUDP pStub;
894  if ( pCurMsg->m_cmmd < NELEMENTS ( udpJumpTableCAC ) ) {
895  pStub = udpJumpTableCAC [pCurMsg->m_cmmd];
896  }
897  else {
898  pStub = &udpiiu::badUDPRespAction;
899  }
900  bool success = ( this->*pStub ) ( *pCurMsg, net_addr, currentTime );
901  if ( ! success ) {
902  char buf[256];
903  sockAddrToDottedIP ( &net_addr.sa, buf, sizeof ( buf ) );
904  errlogPrintf ( "CAC: Undecipherable UDP message from %s\n", buf );
905  return;
906  }
907 
908  blockSize -= size;
909  pInBuf += size;;
910  }
911 }
912 
913 bool udpiiu::pushVersionMsg ()
914 {
915  epicsGuard < epicsMutex > guard ( this->cacMutex );
916 
917  this->sequenceNumber++;
918 
919  caHdr msg;
924  AlignedWireRef < epicsUInt32 > ( msg.m_cid ) = this->sequenceNumber; // sequence number
925 
926  return this->pushDatagramMsg ( guard, msg, 0, 0 );
927 }
928 
929 bool udpiiu::pushDatagramMsg ( epicsGuard < epicsMutex > & guard,
930  const caHdr & msg, const void * pExt, ca_uint16_t extsize )
931 {
932  guard.assertIdenticalMutex ( this->cacMutex );
933 
934  ca_uint16_t alignedExtSize = static_cast <ca_uint16_t> (CA_MESSAGE_ALIGN ( extsize ));
935  arrayElementCount msgsize = sizeof ( caHdr ) + alignedExtSize;
936 
937  /* fail out if max message size exceeded */
938  if ( msgsize >= sizeof ( this->xmitBuf ) - 7 ) {
939  return false;
940  }
941 
942  if ( msgsize + this->nBytesInXmitBuf > sizeof ( this->xmitBuf ) ) {
943  return false;
944  }
945 
946  caHdr * pbufmsg = ( caHdr * ) &this->xmitBuf[this->nBytesInXmitBuf];
947  *pbufmsg = msg;
948  if ( extsize && pExt ) {
949  memcpy ( pbufmsg + 1, pExt, extsize );
950  if ( extsize != alignedExtSize ) {
951  char *pDest = (char *) ( pbufmsg + 1 );
952  memset ( pDest + extsize, '\0', alignedExtSize - extsize );
953  }
954  }
955  AlignedWireRef < epicsUInt16 > ( pbufmsg->m_postsize ) = alignedExtSize;
956  this->nBytesInXmitBuf += msgsize;
957 
958  return true;
959 }
960 
961 udpiiu :: SearchDestUDP :: SearchDestUDP (
962  const osiSockAddr & destAddr, udpiiu & udpiiuIn ) :
963  _lastError (0u), _destAddr ( destAddr ), _udpiiu ( udpiiuIn )
964 {
965 }
966 
967 void udpiiu :: SearchDestUDP :: searchRequest (
968  epicsGuard < epicsMutex > & guard, const char * pBuf, size_t bufSize )
969 {
970  guard.assertIdenticalMutex ( _udpiiu.cacMutex );
971  assert ( bufSize <= INT_MAX );
972  int bufSizeAsInt = static_cast < int > ( bufSize );
973  while ( true ) {
974  // This const_cast is needed for vxWorks:
975  int status = sendto ( _udpiiu.sock, const_cast<char *>(pBuf), bufSizeAsInt, 0,
976  & _destAddr.sa, sizeof ( _destAddr.sa ) );
977  if ( status == bufSizeAsInt ) {
978  if ( _lastError ) {
979  char buf[64];
980  sockAddrToDottedIP ( &_destAddr.sa, buf, sizeof ( buf ) );
981  errlogPrintf (
982  "CAC: ok sending UDP msg to %s\n", buf);
983  }
984  _lastError = 0;
985  break;
986  }
987  if ( status >= 0 ) {
988  errlogPrintf ( "CAC: UDP sendto () call returned strange xmit count?\n" );
989  break;
990  }
991  else {
992  int localErrno = SOCKERRNO;
993 
994  if ( localErrno == SOCK_EINTR ) {
995  if ( _udpiiu.shutdownCmd ) {
996  break;
997  }
998  else {
999  continue;
1000  }
1001  }
1002  else if ( localErrno == SOCK_SHUTDOWN ) {
1003  break;
1004  }
1005  else if ( localErrno == SOCK_ENOTSOCK ) {
1006  break;
1007  }
1008  else if ( localErrno == SOCK_EBADF ) {
1009  break;
1010  }
1011  else if ( localErrno == _lastError) {
1012  break;
1013  } else {
1014  char sockErrBuf[64];
1016  sockErrBuf, sizeof ( sockErrBuf ) );
1017  char buf[64];
1018  sockAddrToDottedIP ( &_destAddr.sa, buf, sizeof ( buf ) );
1019  errlogPrintf (
1020  "CAC: error = \"%s\" sending UDP msg to %s\n",
1021  sockErrBuf, buf);
1022 
1023  _lastError = localErrno;
1024  break;
1025  }
1026  }
1027  }
1028 }
1029 
1030 void udpiiu :: SearchDestUDP :: show (
1031  epicsGuard < epicsMutex > & guard, unsigned level ) const
1032 {
1033  guard.assertIdenticalMutex ( _udpiiu.cacMutex );
1034  char buf[64];
1035  sockAddrToDottedIP ( &_destAddr.sa, buf, sizeof ( buf ) );
1036  :: printf ( "UDP Search destination \"%s\"\n", buf );
1037 }
1038 
1039 udpiiu :: SearchRespCallback :: SearchRespCallback ( udpiiu & udpiiuIn ) :
1040  _udpiiu ( udpiiuIn )
1041 {
1042 }
1043 
1044 void udpiiu :: SearchRespCallback :: notify (
1045  const caHdr & msg, const void * pPayloadUntyped,
1046  const osiSockAddr & addr, const epicsTime & currentTime )
1047 {
1048  /*
1049  * we dont currently know what to do with channel's
1050  * found to be at non-IP type addresses
1051  */
1052  if ( addr.sa.sa_family != AF_INET ) {
1053  return;
1054  }
1055 
1056  /*
1057  * Starting with CA V4.1 the minor version number
1058  * is appended to the end of each search reply.
1059  * This value is ignored by earlier clients.
1060  */
1061  ca_uint32_t minorVersion;
1062  if ( msg.m_postsize >= sizeof ( minorVersion ) ){
1063  /*
1064  * care is taken here not to break gcc 3.2 aggressive alias
1065  * analysis rules
1066  */
1067  const ca_uint8_t * pPayLoad = reinterpret_cast < const ca_uint8_t *> ( pPayloadUntyped );
1068  unsigned byte0 = pPayLoad[0];
1069  unsigned byte1 = pPayLoad[1];
1070  minorVersion = ( byte0 << 8u ) | byte1;
1071  }
1072  else {
1073  minorVersion = CA_UKN_MINOR_VERSION;
1074  }
1075 
1076  /*
1077  * the type field is abused to carry the port number
1078  * so that we can have multiple servers on one host
1079  */
1080  osiSockAddr serverAddr;
1081  serverAddr.ia.sin_family = AF_INET;
1082  if ( CA_V48 ( minorVersion ) ) {
1083  if ( msg.m_cid != INADDR_BROADCAST ) {
1084  serverAddr.ia.sin_addr.s_addr = htonl ( msg.m_cid );
1085  }
1086  else {
1087  serverAddr.ia.sin_addr = addr.ia.sin_addr;
1088  }
1089  serverAddr.ia.sin_port = htons ( msg.m_dataType );
1090  }
1091  else if ( CA_V45 (minorVersion) ) {
1092  serverAddr.ia.sin_port = htons ( msg.m_dataType );
1093  serverAddr.ia.sin_addr = addr.ia.sin_addr;
1094  }
1095  else {
1096  serverAddr.ia.sin_port = htons ( _udpiiu.serverPort );
1097  serverAddr.ia.sin_addr = addr.ia.sin_addr;
1098  }
1099 
1100  if ( CA_V42 ( minorVersion ) ) {
1101  _udpiiu.cacRef.transferChanToVirtCircuit
1102  ( msg.m_available, msg.m_cid, 0xffff,
1103  0, minorVersion, serverAddr, currentTime );
1104  }
1105  else {
1106  _udpiiu.cacRef.transferChanToVirtCircuit
1107  ( msg.m_available, msg.m_cid, msg.m_dataType,
1108  msg.m_count, minorVersion, serverAddr, currentTime );
1109  }
1110 }
1111 
1112 void udpiiu :: SearchRespCallback :: show (
1113  epicsGuard < epicsMutex > & guard, unsigned level ) const
1114 {
1115  guard.assertIdenticalMutex ( _udpiiu.cacMutex );
1116  ::printf ( "udpiiu :: SearchRespCallback\n" );
1117 }
1118 
1119 bool udpiiu :: datagramFlush (
1120  epicsGuard < epicsMutex > & guard, const epicsTime & currentTime )
1121 {
1122  guard.assertIdenticalMutex ( cacMutex );
1123 
1124  // dont send the version header by itself
1125  if ( this->nBytesInXmitBuf <= sizeof ( caHdr ) ) {
1126  return false;
1127  }
1128 
1129  tsDLIter < SearchDest > iter ( _searchDestList.firstIter () );
1130  while ( iter.valid () )
1131  {
1132  iter->searchRequest ( guard, this->xmitBuf, this->nBytesInXmitBuf );
1133  iter++;
1134  }
1135 
1136  this->nBytesInXmitBuf = 0u;
1137 
1138  this->pushVersionMsg ();
1139 
1140  return true;
1141 }
1142 
1143 void udpiiu :: show ( unsigned level ) const
1144 {
1145  epicsGuard < epicsMutex > guard ( this->cacMutex );
1146 
1147  ::printf ( "Datagram IO circuit (and disconnected channel repository)\n");
1148  if ( level > 1u ) {
1149  ::printf ("\trepeater port %u\n", this->repeaterPort );
1150  ::printf ("\tdefault server port %u\n", this->serverPort );
1151  ::printf ( "Search Destination List with %u items\n",
1152  _searchDestList.count () );
1153  if ( level > 2u ) {
1155  _searchDestList.firstIter () );
1156  while ( iter.valid () )
1157  {
1158  iter->show ( guard, level - 2 );
1159  iter++;
1160  }
1161  }
1162  }
1163  if ( level > 2u ) {
1164  ::printf ("\tsocket identifier %d\n", int(this->sock) );
1165  ::printf ("\tbytes in xmit buffer %u\n", this->nBytesInXmitBuf );
1166  ::printf ("\tshut down command bool %u\n", this->shutdownCmd );
1167  ::printf ( "\trecv thread exit signal:\n" );
1168  this->recvThread.show ( level - 2u );
1169  this->repeaterSubscribeTmr.show ( level - 2u );
1170  this->govTmr.show ( level - 2u );
1171  }
1172  if ( level > 3u ) {
1173  for ( unsigned i =0; i < this->nTimers; i++ ) {
1174  this->ppSearchTmr[i]->show ( level - 3u );
1175  }
1176  }
1177 }
1178 
1179 bool udpiiu::wakeupMsg ()
1180 {
1181  caHdr msg;
1188 
1189  osiSockAddr addr;
1190  addr.ia.sin_family = AF_INET;
1191  addr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
1192  addr.ia.sin_port = htons ( this->localPort );
1193 
1194  // send a wakeup msg so the UDP recv thread will exit
1195  int status = sendto ( this->sock, reinterpret_cast < char * > ( &msg ),
1196  sizeof (msg), 0, &addr.sa, sizeof ( addr.sa ) );
1197  return status == sizeof (msg);
1198 }
1199 
1201  epicsGuard < epicsMutex > & cacGuard )
1202 {
1203  for ( unsigned i = this->beaconAnomalyTimerIndex+1u;
1204  i < this->nTimers; i++ ) {
1205  this->ppSearchTmr[i]->moveChannels ( cacGuard,
1206  *this->ppSearchTmr[this->beaconAnomalyTimerIndex] );
1207  }
1208 }
1209 
1210 void udpiiu::uninstallChanDueToSuccessfulSearchResponse (
1211  epicsGuard < epicsMutex > & guard, nciu & chan,
1212  const epicsTime & currentTime )
1213 {
1214  channelNode::channelState chanState =
1215  chan.channelNode::listMember;
1216  if ( chanState == channelNode::cs_disconnGov ) {
1217  this->govTmr.uninstallChan ( guard, chan );
1218  }
1219  else {
1220  this->ppSearchTmr[ chan.getSearchTimerIndex ( guard ) ]->
1221  uninstallChanDueToSuccessfulSearchResponse (
1222  guard, chan, this->lastReceivedSeqNo,
1223  this->lastReceivedSeqNoIsValid, currentTime );
1224  }
1225 }
1226 
1227 void udpiiu::uninstallChan (
1228  epicsGuard < epicsMutex > & guard, nciu & chan )
1229 {
1230  channelNode::channelState chanState =
1231  chan.channelNode::listMember;
1232  if ( chanState == channelNode::cs_disconnGov ) {
1233  this->govTmr.uninstallChan ( guard, chan );
1234  }
1235  else {
1236  this->ppSearchTmr[ chan.getSearchTimerIndex ( guard ) ]->
1237  uninstallChan ( guard, chan );
1238  }
1239 }
1240 
1241 bool udpiiu::searchMsg (
1243  const char * pName, unsigned nameLength )
1244 {
1245  caHdr msg;
1251  return this->pushDatagramMsg (
1252  guard, msg, pName, (ca_uint16_t) nameLength );
1253 }
1254 
1256  epicsGuard < epicsMutex > & guard, nciu & chan, netiiu * & piiu )
1257 {
1258  piiu = this;
1259  this->ppSearchTmr[0]->installChannel ( guard, chan );
1260 }
1261 
1263  epicsGuard < epicsMutex > & guard, nciu & chan )
1264 {
1265  chan.setServerAddressUnknown ( *this, guard );
1266  this->govTmr.installChan ( guard, chan );
1267 }
1268 
1269 void udpiiu::noSearchRespNotify (
1270  epicsGuard < epicsMutex > & guard, nciu & chan, unsigned index )
1271 {
1272  const unsigned nTimersMinusOne = this->nTimers - 1;
1273  if ( index < nTimersMinusOne ) {
1274  index++;
1275  }
1276  else {
1277  index = nTimersMinusOne;
1278  }
1279  this->ppSearchTmr[index]->installChannel ( guard, chan );
1280 }
1281 
1282 void udpiiu::boostChannel (
1283  epicsGuard < epicsMutex > & guard, nciu & chan )
1284 {
1285  this->ppSearchTmr[this->beaconAnomalyTimerIndex]->
1286  installChannel ( guard, chan );
1287 }
1288 
1289 void udpiiu::govExpireNotify (
1290  epicsGuard < epicsMutex > & guard, nciu & chan )
1291 {
1292  this->ppSearchTmr[0]->installChannel ( guard, chan );
1293 }
1294 
1295 int udpiiu :: M_repeaterTimerNotify :: printFormated (
1296  epicsGuard < epicsMutex > & cbGuard,
1297  const char * pformat, ... )
1298 {
1299  va_list theArgs;
1300  int status;
1301 
1302  va_start ( theArgs, pformat );
1303 
1304  status = m_udpiiu.cacRef.varArgsPrintFormated ( cbGuard, pformat, theArgs );
1305 
1306  va_end ( theArgs );
1307 
1308  return status;
1309 }
1310 
1311 void udpiiu::updateRTTE ( epicsGuard < epicsMutex > & guard, double measured )
1312 {
1313  guard.assertIdenticalMutex ( this->cacMutex );
1314  if ( measured > maxRoundTripEstimate ) {
1315  measured = maxRoundTripEstimate;
1316  }
1317  if ( measured < minRoundTripEstimate ) {
1318  measured = minRoundTripEstimate;
1319  }
1320  double error = measured - this->rtteMean;
1321  this->rtteMean += 0.125 * error;
1322  if ( error < 0.0 ) {
1323  error = - error;
1324  }
1325  this->rtteMeanDev = this->rtteMeanDev + .25 * ( error - this->rtteMeanDev );
1326 }
1327 
1328 double udpiiu::getRTTE ( epicsGuard < epicsMutex > & guard ) const
1329 {
1330  guard.assertIdenticalMutex ( this->cacMutex );
1331  return this->rtteMean + 4 * this->rtteMeanDev;
1332 }
1333 
1334 unsigned udpiiu::getHostName (
1335  epicsGuard < epicsMutex > & cacGuard,
1336  char *pBuf, unsigned bufLength ) const throw ()
1337 {
1338  return netiiu::getHostName ( cacGuard, pBuf, bufLength );
1339 }
1340 
1341 const char * udpiiu::pHostName (
1342  epicsGuard < epicsMutex > & cacGuard ) const throw ()
1343 {
1344  return netiiu::pHostName ( cacGuard );
1345 }
1346 
1347 bool udpiiu::ca_v42_ok (
1348  epicsGuard < epicsMutex > & cacGuard ) const
1349 {
1350  return netiiu::ca_v42_ok ( cacGuard );
1351 }
1352 
1353 bool udpiiu::ca_v41_ok (
1354  epicsGuard < epicsMutex > & cacGuard ) const
1355 {
1356  return netiiu::ca_v41_ok ( cacGuard );
1357 }
1358 
1359 void udpiiu::writeRequest (
1360  epicsGuard < epicsMutex > & guard,
1361  nciu & chan, unsigned type,
1362  arrayElementCount nElem, const void * pValue )
1363 {
1364  netiiu::writeRequest ( guard, chan, type, nElem, pValue );
1365 }
1366 
1367 void udpiiu::writeNotifyRequest (
1368  epicsGuard < epicsMutex > & guard, nciu & chan,
1369  netWriteNotifyIO & io, unsigned type,
1370  arrayElementCount nElem, const void *pValue )
1371 {
1372  netiiu::writeNotifyRequest ( guard, chan, io, type, nElem, pValue );
1373 }
1374 
1375 void udpiiu::readNotifyRequest (
1376  epicsGuard < epicsMutex > & guard, nciu & chan,
1377  netReadNotifyIO & io, unsigned type, arrayElementCount nElem )
1378 {
1379  netiiu::readNotifyRequest ( guard, chan, io, type, nElem );
1380 }
1381 
1382 void udpiiu::clearChannelRequest (
1383  epicsGuard < epicsMutex > & guard,
1384  ca_uint32_t sid, ca_uint32_t cid )
1385 {
1386  netiiu::clearChannelRequest ( guard, sid, cid );
1387 }
1388 
1389 void udpiiu::subscriptionRequest (
1390  epicsGuard < epicsMutex > & guard, nciu & chan,
1391  netSubscription & subscr )
1392 {
1393  netiiu::subscriptionRequest ( guard, chan, subscr );
1394 }
1395 
1396 void udpiiu::subscriptionUpdateRequest (
1397  epicsGuard < epicsMutex > & guard, nciu & chan,
1398  netSubscription & subscr )
1399 {
1401  guard, chan, subscr );
1402 }
1403 
1404 void udpiiu::subscriptionCancelRequest (
1405  epicsGuard < epicsMutex > & guard,
1406  nciu & chan, netSubscription & subscr )
1407 {
1408  netiiu::subscriptionCancelRequest ( guard, chan, subscr );
1409 }
1410 
1411 void udpiiu::flushRequest (
1412  epicsGuard < epicsMutex > & guard )
1413 {
1414  netiiu::flushRequest ( guard );
1415 }
1416 
1417 unsigned udpiiu::requestMessageBytesPending (
1418  epicsGuard < epicsMutex > & guard )
1419 {
1420  return netiiu::requestMessageBytesPending ( guard );
1421 }
1422 
1423 void udpiiu::flush (
1424  epicsGuard < epicsMutex > & guard )
1425 {
1426  netiiu::flush ( guard );
1427 }
1428 
1429 void udpiiu::requestRecvProcessPostponedFlush (
1430  epicsGuard < epicsMutex > & guard )
1431 {
1433 }
1434 
1435 osiSockAddr udpiiu::getNetworkAddress (
1436  epicsGuard < epicsMutex > & guard ) const
1437 {
1438  return netiiu::getNetworkAddress ( guard );
1439 }
1440 
1441 double udpiiu::receiveWatchdogDelay (
1442  epicsGuard < epicsMutex > & guard ) const
1443 {
1444  return netiiu::receiveWatchdogDelay ( guard );
1445 }
1446 
1447 ca_uint32_t udpiiu::datagramSeqNumber (
1448  epicsGuard < epicsMutex > & ) const
1449 {
1450  return this->sequenceNumber;
1451 }
1452 
#define SOCK_ECONNREFUSED
Definition: osdSock.h:58
#define INADDR_LOOPBACK
Definition: osdSock.h:76
#define CA_REPEATER_PORT
Definition: caProto.h:54
LIBCOM_API void epicsStdCall epicsSocketDestroy(SOCKET s)
Definition: osdSock.c:117
unsigned epicsStdCall sockAddrToDottedIP(const struct sockaddr *paddr, char *pBuf, unsigned bufSize)
Definition: osiSock.c:118
virtual bool ca_v42_ok(epicsGuard< epicsMutex > &) const =0
Definition: netiiu.cpp:37
#define REPEATER_REGISTER
Definition: caProto.h:107
void beaconAnomalyNotify(epicsGuard< epicsMutex > &guard)
Definition: udpiiu.cpp:1200
Definition: cac.h:97
#define INVALID_SOCKET
Definition: osdSock.h:32
int(* pProtoStubUDP)(caHdrLargeArray *mp, void *pPayload, struct client *client)
Definition: camessage.c:2355
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
virtual void subscriptionCancelRequest(epicsGuard< epicsMutex > &, nciu &chan, netSubscription &subscr)=0
Definition: netiiu.cpp:81
void add(T &item)
Definition: tsDLList.h:313
#define SOCK_EADDRINUSE
Definition: osdSock.h:56
void setServerAddressUnknown(netiiu &newiiu, epicsGuard< epicsMutex > &guard)
Definition: nciu.cpp:183
pvd::Status status
#define CA_PROTO_VERSION
Definition: caProto.h:83
int osiSocklen_t
Definition: osdSock.h:36
char * name
Name of the parameter.
Definition: envDefs.h:42
int i
Definition: scan.c:967
LIBCOM_API const char *epicsStdCall envGetConfigParamPtr(const ENV_PARAM *pParam)
Get a configuration parameter&#39;s value or default string.
Definition: envSubr.c:81
struct sockaddr sa
Definition: osiSock.h:158
virtual void requestRecvProcessPostponedFlush(epicsGuard< epicsMutex > &)=0
Definition: netiiu.cpp:142
ca_uint32_t m_available
Definition: caProto.h:166
struct sockaddr_in ia
Definition: osiSock.h:157
virtual void subscriptionRequest(epicsGuard< epicsMutex > &, nciu &, netSubscription &)=0
Definition: netiiu.cpp:76
Routines to get and set EPICS environment parameters.
tsDLIterConst< T > firstIter() const
Definition: tsDLList.h:459
#define printf
Definition: epicsStdio.h:41
#define CA_V42(MINOR)
Definition: caProto.h:33
pvd::StructureConstPtr type
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
void shutdown(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
#define CA_UKN_MINOR_VERSION
Definition: caProto.h:29
void assertIdenticalMutex(const T &) const
Definition: epicsGuard.h:80
udpRecvThread(class udpiiu &iiuIn, cacContextNotify &, epicsMutex &, const char *pName, unsigned stackSize, unsigned priority)
Definition: udpiiu.cpp:370
#define NULL
Definition: catime.c:38
epicsThreadPrivateId caClientCallbackThreadId
unsigned count() const
Definition: tsDLList.h:181
virtual osiSockAddr getNetworkAddress(epicsGuard< epicsMutex > &) const =0
Definition: netiiu.cpp:118
virtual void readNotifyRequest(epicsGuard< epicsMutex > &, nciu &, netReadNotifyIO &, unsigned type, arrayElementCount nElem)=0
Definition: netiiu.cpp:64
int osiSockOptMcastLoop_t
Definition: osdSock.h:37
#define CA_V48(MINOR)
Definition: caProto.h:39
unsigned short ca_uint16_t
Definition: caProto.h:75
virtual void flush(epicsGuard< epicsMutex > &mutualExclusionGuard)=0
Definition: netiiu.cpp:137
Miscellaneous macro definitions.
virtual unsigned getHostName(epicsGuard< epicsMutex > &, char *pBuf, unsigned bufLength) const =0
Definition: netiiu.cpp:93
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
virtual ~udpiiu()
Definition: udpiiu.cpp:313
#define SOCK_SHUTDOWN
Definition: osdSock.h:67
virtual bool ca_v41_ok(epicsGuard< epicsMutex > &) const =0
Definition: netiiu.cpp:43
static unsigned getMaxSearchTimerCount()
Definition: nciu.cpp:598
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
#define CA_MINOR_PROTOCOL_REVISION
Definition: nciu.h:35
void installNewChannel(epicsGuard< epicsMutex > &, nciu &, netiiu *&)
Definition: udpiiu.cpp:1255
void installDisconnectedChannel(epicsGuard< epicsMutex > &, nciu &)
Definition: udpiiu.cpp:1262
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
#define SOCK_ECONNRESET
Definition: osdSock.h:53
LIBCOM_API SOCKET epicsStdCall epicsSocketCreate(int domain, int type, int protocol)
Definition: osdSock.c:71
LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr(SOCKET socket)
Definition: osdNetIntf.c:347
osiSpawnDetachedProcessReturn
Definition: osiProcess.h:35
void caRepeaterThread(void *)
Definition: repeater.cpp:631
ca_uint16_t m_cmmd
Definition: caProto.h:161
LIBCOM_API long epicsStdCall envGetDoubleConfigParam(const ENV_PARAM *pParam, double *pDouble)
Get value of a double configuration parameter.
Definition: envSubr.c:191
virtual ~udpRecvThread()
Definition: udpiiu.cpp:376
void show(unsigned level) const
Definition: udpiiu.cpp:1143
#define CA_MESSAGE_ALIGN(A)
Definition: caProto.h:154
void show(unsigned level) const
Definition: udpiiu.cpp:390
void epicsStdCall caStartRepeaterIfNotInstalled(unsigned repeaterPort)
Definition: udpiiu.cpp:581
LIBCOM_API const ENV_PARAM EPICS_CA_REPEATER_PORT
LIBCOM_API void epicsStdCall epicsSocketEnableAddressReuseDuringTimeWaitState(SOCKET s)
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId, void *)
Definition: osdThread.c:961
ca_uint32_t m_cid
Definition: caProto.h:165
udpiiu(epicsGuard< epicsMutex > &cacGuard, class epicsTimerQueueActive &, epicsMutex &callbackControl, epicsMutex &mutualExclusion, cacContextNotify &, class cac &, unsigned port, tsDLList< SearchDest > &)
Definition: udpiiu.cpp:115
#define epicsPrintf
Definition: errlog.h:51
#define ECA_NOSEARCHADDR
Definition: caerr.h:126
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
virtual void subscriptionUpdateRequest(epicsGuard< epicsMutex > &, nciu &, netSubscription &)=0
Definition: netiiu.cpp:86
#define epicsThreadPriorityLow
Definition: epicsThread.h:75
#define sequenceNoIsValid
Definition: caProto.h:124
void shutdown(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: udpiiu.cpp:332
#define CA_PROTO_SEARCH
Definition: caProto.h:89
int SOCKET
Definition: osdSock.h:31
ca_uint16_t m_postsize
Definition: caProto.h:162
virtual void flushRequest(epicsGuard< epicsMutex > &)=0
Definition: netiiu.cpp:126
ca_uint16_t m_dataType
Definition: caProto.h:163
#define NELEMENTS(A)
Definition: aToIPAddr.c:21
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
virtual const char * pHostName(epicsGuard< epicsMutex > &) const =0
Definition: netiiu.cpp:112
struct ca_hdr caHdr
void date(const char *format)
ca_uint16_t m_count
Definition: caProto.h:164
epicsGuard< epicsMutex > cbGuard
Definition: cac.h:94
#define SOCKERRNO
Definition: osdSock.h:33
unsigned long arrayElementCount
Definition: cacIO.h:57
const char *epicsStdCall ca_message(long ca_status)
Definition: access.cpp:561
LIBCA_API void epicsStdCall configureChannelAccessAddressList(struct ELLLIST *pList, SOCKET sock, unsigned short port)
Definition: iocinf.cpp:183
LIBCOM_API const ENV_PARAM EPICS_CA_MAX_SEARCH_PERIOD
#define SOCK_EINTR
Definition: osdSock.h:64
LIBCOM_API long epicsStdCall envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong)
Get value of a long configuration parameter.
Definition: envSubr.c:303
LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess(const char *pProcessName, const char *pBaseExecutableName)
Definition: osdProcess.c:61
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
#define genLocalExcep(CBGUARD, GUARD, CAC, STAT, PCTX)
Definition: iocinf.h:66
#define DONTREPLY
Definition: caProto.h:119
Contains a few templates out of the C++ standard header algorithm.
Definition: udpiiu.h:79
#define CA_V45(MINOR)
Definition: caProto.h:36
virtual void writeRequest(epicsGuard< epicsMutex > &, nciu &, unsigned type, arrayElementCount nElem, const void *pValue)=0
Definition: netiiu.cpp:49
void start()
Definition: udpiiu.cpp:380
LIBCOM_API const ENV_PARAM EPICS_CA_MCAST_TTL
virtual unsigned requestMessageBytesPending(epicsGuard< epicsMutex > &mutualExclusionGuard)=0
Definition: netiiu.cpp:131
#define SOCK_EBADF
Definition: osdSock.h:69
#define stderr
Definition: epicsStdio.h:32
List header type.
Definition: ellLib.h:56
unsigned char ca_uint8_t
Definition: caProto.h:74
void epicsStdCall caRepeaterRegistrationMessage(SOCKET sock, unsigned repeaterPort, unsigned attemptNumber)
Definition: udpiiu.cpp:464
void shutdown(epicsGuard< epicsMutex > &cbGuard, epicsGuard< epicsMutex > &guard)
Definition: netiiu.h:37
virtual void clearChannelRequest(epicsGuard< epicsMutex > &, ca_uint32_t sid, ca_uint32_t cid)=0
Definition: netiiu.cpp:71
#define throwWithLocation(parm)
virtual double receiveWatchdogDelay(epicsGuard< epicsMutex > &) const =0
Definition: netiiu.cpp:153
bool exitWait(double delay)
Definition: udpiiu.cpp:385
int osiSockOptMcastTTL_t
Definition: osdSock.h:38
#define SOCK_ENOTSOCK
Definition: osdSock.h:68
#define false
Definition: flexdef.h:85
Definition: nciu.h:127
virtual void writeNotifyRequest(epicsGuard< epicsMutex > &, nciu &, netWriteNotifyIO &, unsigned type, arrayElementCount nElem, const void *pValue)=0
Definition: netiiu.cpp:56