This is Unofficial EPICS BASE Doxygen Site
udpiiu.h File Reference
#include <memory>
#include "osiSock.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "tsDLList.h"
#include "libCaAPI.h"
#include "netiiu.h"
#include "searchTimer.h"
#include "disconnectGovernorTimer.h"
#include "repeaterSubscribeTimer.h"
#include "SearchDest.h"
+ Include dependency graph for udpiiu.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

class  udpRecvThread
 
class  udpiiu
 
class  udpiiu::noSocket
 

Functions

void cacRecvThreadUDP (void *pParam)
 
LIBCA_API void epicsStdCall caStartRepeaterIfNotInstalled (unsigned repeaterPort)
 
LIBCA_API void epicsStdCall caRepeaterRegistrationMessage (SOCKET sock, unsigned repeaterPort, unsigned attemptNumber)
 
LIBCA_API void caRepeaterThread (void *pDummy)
 
LIBCA_API void ca_repeater (void)
 

Function Documentation

LIBCA_API void ca_repeater ( void  )

Definition at line 482 of file repeater.cpp.

483 {
485  int size;
486  SOCKET sock;
487  osiSockAddr from;
488  unsigned short port;
489  char * pBuf;
490 
491  pBuf = new char [MAX_UDP_RECV];
492 
493  {
494  bool success = osiSockAttach();
495  assert ( success );
496  }
497 
499  static_cast <unsigned short> (CA_REPEATER_PORT) );
500  if ( int sockerrno = makeSocket ( port, true, & sock ) ) {
501  /*
502  * test for server was already started
503  */
504  if ( sockerrno == SOCK_EADDRINUSE ) {
505  osiSockRelease ();
506  debugPrintf ( ( "CA Repeater: exiting because a repeater is already running\n" ) );
507  delete [] pBuf;
508  return;
509  }
510  char sockErrBuf[64];
512  sockErrBuf, sizeof ( sockErrBuf ), sockerrno );
513  fprintf ( stderr, "%s: Unable to create repeater socket because \"%s\" - fatal\n",
514  __FILE__, sockErrBuf );
515  osiSockRelease ();
516  delete [] pBuf;
517  return;
518  }
519 
520 #ifdef IP_ADD_MEMBERSHIP
521  /*
522  * join UDP socket to any multicast groups
523  */
524  {
525  ELLLIST casBeaconAddrList = ELLLIST_INIT;
526  ELLLIST casMergeAddrList = ELLLIST_INIT;
527 
528  /*
529  * collect user specified beacon address list;
530  * check BEACON_ADDR_LIST list first; if no result, take CA_ADDR_LIST
531  */
532  if(!addAddrToChannelAccessAddressList(&casMergeAddrList,&EPICS_CAS_BEACON_ADDR_LIST,port,0)) {
533  addAddrToChannelAccessAddressList(&casMergeAddrList,&EPICS_CA_ADDR_LIST,port,0);
534  }
535 
536  /* First clean up */
537  removeDuplicateAddresses(&casBeaconAddrList, &casMergeAddrList , 0);
538 
539  osiSockAddrNode *pNode;
540  for(pNode = (osiSockAddrNode*)ellFirst(&casBeaconAddrList);
541  pNode;
542  pNode = (osiSockAddrNode*)ellNext(&pNode->node))
543  {
544 
545  if(pNode->addr.ia.sin_family==AF_INET) {
546  epicsUInt32 top = ntohl(pNode->addr.ia.sin_addr.s_addr)>>24;
547  if(top>=224 && top<=239) {
548 
549  /* This is a multi-cast address */
550  struct ip_mreq mreq;
551 
552  memset(&mreq, 0, sizeof(mreq));
553  mreq.imr_multiaddr = pNode->addr.ia.sin_addr;
554  mreq.imr_interface.s_addr = INADDR_ANY;
555 
556  if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
557  (char *) &mreq, sizeof(mreq)) != 0) {
558  char name[40];
559  char sockErrBuf[64];
560  epicsSocketConvertErrnoToString (sockErrBuf, sizeof ( sockErrBuf ) );
561  ipAddrToDottedIP (&pNode->addr.ia, name, sizeof(name));
562  errlogPrintf("caR: Socket mcast join to %s failed: %s\n", name, sockErrBuf );
563  }
564  }
565  }
566  }
567  }
568 #endif
569 
570  debugPrintf ( ( "CA Repeater: Attached and initialized\n" ) );
571 
572  while ( true ) {
573  osiSocklen_t from_size = sizeof ( from );
574  size = recvfrom ( sock, pBuf, MAX_UDP_RECV, 0,
575  &from.sa, &from_size );
576  if ( size < 0 ) {
577  int errnoCpy = SOCKERRNO;
578  // Avoid spurious ECONNREFUSED bug in linux
579  if ( errnoCpy == SOCK_ECONNREFUSED ) {
580  continue;
581  }
582  // Avoid ECONNRESET from connected socket in windows
583  if ( errnoCpy == SOCK_ECONNRESET ) {
584  continue;
585  }
586  char sockErrBuf[64];
588  sockErrBuf, sizeof ( sockErrBuf ) );
589  fprintf ( stderr, "CA Repeater: unexpected UDP recv err: %s\n",
590  sockErrBuf );
591  continue;
592  }
593 
594  caHdr * pMsg = ( caHdr * ) pBuf;
595 
596  /*
597  * both zero length message and a registration message
598  * will register a new client
599  */
600  if ( ( (size_t) size) >= sizeof (*pMsg) ) {
602  register_new_client ( from, freeList );
603 
604  /*
605  * strip register client message
606  */
607  pMsg++;
608  size -= sizeof ( *pMsg );
609  if ( size==0 ) {
610  continue;
611  }
612  }
614  if ( pMsg->m_available == 0u ) {
615  pMsg->m_available = from.ia.sin_addr.s_addr;
616  }
617  }
618  }
619  else if ( size == 0 ) {
620  register_new_client ( from, freeList );
621  continue;
622  }
623 
624  fanOut ( from, pMsg, size, freeList );
625  }
626 }
#define SOCK_ECONNREFUSED
Definition: osdSock.h:58
LIBCA_API void epicsStdCall removeDuplicateAddresses(struct ELLLIST *pDestList, ELLLIST *pSrcList, int silent)
Definition: iocinf.cpp:123
#define CA_REPEATER_PORT
Definition: caProto.h:54
#define REPEATER_REGISTER
Definition: caProto.h:107
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
osiSockAddr addr
Definition: osiSock.h:163
#define SOCK_EADDRINUSE
Definition: osdSock.h:56
int osiSocklen_t
Definition: osdSock.h:36
void osiSockRelease()
Definition: osdSock.c:62
struct sockaddr sa
Definition: osiSock.h:158
LIBCA_API int epicsStdCall addAddrToChannelAccessAddressList(struct ELLLIST *pList, const ENV_PARAM *pEnv, unsigned short port, int ignoreNonDefaultPort)
Definition: iocinf.cpp:74
ca_uint32_t m_available
Definition: caProto.h:166
struct sockaddr_in ia
Definition: osiSock.h:157
unsigned int epicsUInt32
Definition: epicsTypes.h:43
#define ELLLIST_INIT
Value of an empty list.
Definition: ellLib.h:63
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
#define SOCK_ECONNRESET
Definition: osdSock.h:53
ca_uint16_t m_cmmd
Definition: caProto.h:161
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
LIBCOM_API const ENV_PARAM EPICS_CA_REPEATER_PORT
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
int SOCKET
Definition: osdSock.h:31
LIBCOM_API const ENV_PARAM EPICS_CA_ADDR_LIST
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
LIBCOM_API const ENV_PARAM EPICS_CAS_BEACON_ADDR_LIST
#define SOCKERRNO
Definition: osdSock.h:33
#define MAX_UDP_RECV
Definition: caProto.h:61
ELLNODE node
Definition: osiSock.h:162
int osiSockAttach()
Definition: osdSock.c:54
#define debugPrintf(argsInParen)
Definition: iocinf.h:30
#define stderr
Definition: epicsStdio.h:32
List header type.
Definition: ellLib.h:56
#define CA_PROTO_RSRV_IS_UP
Definition: caProto.h:96
void epicsSocketConvertErrorToString(char *pBuf, unsigned bufSize, int theSockError)
unsigned epicsStdCall ipAddrToDottedIP(const struct sockaddr_in *paddr, char *pBuf, unsigned bufSize)
Definition: osiSock.c:144
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
void cacRecvThreadUDP ( void *  pParam)
LIBCA_API void epicsStdCall caRepeaterRegistrationMessage ( SOCKET  sock,
unsigned  repeaterPort,
unsigned  attemptNumber 
)

Definition at line 464 of file udpiiu.cpp.

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 }
#define SOCK_ECONNREFUSED
Definition: osdSock.h:58
#define INADDR_LOOPBACK
Definition: osdSock.h:76
#define REPEATER_REGISTER
Definition: caProto.h:107
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
pvd::Status status
struct sockaddr sa
Definition: osiSock.h:158
ca_uint32_t m_available
Definition: caProto.h:166
struct sockaddr_in ia
Definition: osiSock.h:157
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
#define SOCK_ECONNRESET
Definition: osdSock.h:53
LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr(SOCKET socket)
Definition: osdNetIntf.c:347
ca_uint16_t m_cmmd
Definition: caProto.h:161
#define SOCKERRNO
Definition: osdSock.h:33
#define SOCK_EINTR
Definition: osdSock.h:64
#define stderr
Definition: epicsStdio.h:32
LIBCA_API void caRepeaterThread ( void *  pDummy)

Definition at line 631 of file repeater.cpp.

632 {
634  ca_repeater ();
635 }
void taskwdInsert(epicsThreadId tid, TASKWDFUNC callback, void *usr)
Definition: taskwd.c:176
void ca_repeater()
Definition: repeater.cpp:482
#define NULL
Definition: catime.c:38
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810
LIBCA_API void epicsStdCall caStartRepeaterIfNotInstalled ( unsigned  repeaterPort)

Definition at line 581 of file udpiiu.cpp.

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 }
LIBCOM_API void epicsStdCall epicsSocketDestroy(SOCKET s)
Definition: osdSock.c:117
#define INVALID_SOCKET
Definition: osdSock.h:32
#define SOCK_EADDRINUSE
Definition: osdSock.h:56
pvd::Status status
unsigned short ca_uint16_t
Definition: caProto.h:75
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
LIBCOM_API SOCKET epicsStdCall epicsSocketCreate(int domain, int type, int protocol)
Definition: osdSock.c:71
osiSpawnDetachedProcessReturn
Definition: osiProcess.h:35
void caRepeaterThread(void *)
Definition: repeater.cpp:631
LIBCOM_API void epicsStdCall epicsSocketEnableAddressReuseDuringTimeWaitState(SOCKET s)
#define epicsThreadPriorityLow
Definition: epicsThread.h:75
int SOCKET
Definition: osdSock.h:31
#define SOCKERRNO
Definition: osdSock.h:33
LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess(const char *pProcessName, const char *pBaseExecutableName)
Definition: osdProcess.c:61
#define stderr
Definition: epicsStdio.h:32