/* * RSRV_ONLINE_NOTIFY_TASK */ void rsrv_online_notify_task(void *pParm) { unsigned priorityOfSelf = epicsThreadGetPrioritySelf (); osiSockAddrNode *pNode; double delay; double maxdelay; long longStatus; double maxPeriod; caHdr msg; int status; SOCKET sock; int intTrue = TRUE; unsigned short port; ca_uint32_t beaconCounter = 0; char * pStr; int autoBeaconAddr; ELLLIST autoAddrList; char buf[16]; unsigned priorityOfUDP; epicsThreadBooleanStatus tbs; epicsThreadId tid; taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL); if ( envGetConfigParamPtr ( & EPICS_CAS_BEACON_PERIOD ) ) { longStatus = envGetDoubleConfigParam ( & EPICS_CAS_BEACON_PERIOD, & maxPeriod ); } else { longStatus = envGetDoubleConfigParam ( & EPICS_CA_BEACON_PERIOD, & maxPeriod ); } if (longStatus || maxPeriod<=0.0) { maxPeriod = 15.0; epicsPrintf ("EPICS \"%s\" float fetch failed\n", EPICS_CAS_BEACON_PERIOD.name); epicsPrintf ("Setting \"%s\" = %f\n", EPICS_CAS_BEACON_PERIOD.name, maxPeriod); } delay = 0.02; /* initial beacon period in sec */ maxdelay = maxPeriod; /* * Open the socket. * Use ARPA Internet address format and datagram socket. * Format described in <sys/socket.h>. */ if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { errlogPrintf ("CAS: online socket creation error\n"); epicsThreadSuspendSelf (); } status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *)&intTrue, sizeof(intTrue)); if (status<0) { errlogPrintf ("CAS: online socket set up error\n"); epicsThreadSuspendSelf (); } { /* * this connect is to supress a warning message on Linux * when we shutdown the read side of the socket. If it * fails (and it will on old ip kernels) we just ignore * the failure. */ osiSockAddr sockAddr; sockAddr.ia.sin_family = AF_UNSPEC; sockAddr.ia.sin_port = htons ( 0 ); sockAddr.ia.sin_addr.s_addr = htonl (0); connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) ); shutdown ( sock, SHUT_RD ); } memset((char *)&msg, 0, sizeof msg); msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP); msg.m_count = htons (ca_server_port); msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION); ellInit ( & beaconAddrList ); ellInit ( & autoAddrList ); pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf); if ( ! pStr ) { pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf); } if (pStr) { if (strstr(pStr,"no")||strstr(pStr,"NO")) { autoBeaconAddr = FALSE; } else if (strstr(pStr,"yes")||strstr(pStr,"YES")) { autoBeaconAddr = TRUE; } else { fprintf(stderr, "CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr); autoBeaconAddr = TRUE; } } else { autoBeaconAddr = TRUE; } /* * load user and auto configured * broadcast address list */ if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) { port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT, (unsigned short) CA_REPEATER_PORT ); } else { port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, (unsigned short) CA_REPEATER_PORT ); } /* * discover beacon addresses associated with this interface */ if ( autoBeaconAddr ) { osiSockAddr addr; ELLLIST tmpList; ellInit ( &tmpList ); addr.ia.sin_family = AF_UNSPEC; osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr); forcePort ( &tmpList, port ); removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 ); } /* * by default use EPICS_CA_ADDR_LIST for the * beacon address list */ { const ENV_PARAM *pParam; if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) || envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) { pParam = &EPICS_CAS_BEACON_ADDR_LIST; } else { pParam = &EPICS_CA_ADDR_LIST; } /* * add in the configured addresses */ addAddrToChannelAccessAddressList ( &autoAddrList, pParam, port, pParam == &EPICS_CA_ADDR_LIST ); } removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 ); if ( ellCount ( &beaconAddrList ) == 0 ) { errlogPrintf ("The CA server's beacon address list was empty after initialization?\n"); } # ifdef DEBUG printChannelAccessAddressList (&beaconAddrList); # endif tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP ); if ( tbs != epicsThreadBooleanStatusSuccess ) { priorityOfUDP = priorityOfSelf; } casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty); casudp_ctl = ctlPause; tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP, epicsThreadGetStackSize (epicsThreadStackMedium), cast_server, 0 ); if ( tid == 0 ) { epicsPrintf ( "CAS: unable to start UDP daemon thread\n" ); } epicsEventMustWait(casudp_startStopEvent); epicsEventSignal(beacon_startStopEvent); while (TRUE) { pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList); while (pNode) { char buf[64]; status = connect (sock, &pNode->addr.sa, sizeof(pNode->addr.sa)); if (status<0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf)); errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n", __FILE__, buf, sockErrBuf); } else { struct sockaddr_in if_addr; osiSocklen_t size = sizeof (if_addr); status = getsockname (sock, (struct sockaddr *) &if_addr, &size); if (status<0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n", __FILE__, sockErrBuf); } else if (if_addr.sin_family==AF_INET) { msg.m_available = if_addr.sin_addr.s_addr; msg.m_cid = htonl ( beaconCounter ); status = send (sock, (char *)&msg, sizeof(msg), 0); if (status < 0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf)); errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n", __FILE__, buf, sockErrBuf); } else { assert (status == sizeof(msg)); } } } pNode = (osiSockAddrNode *) pNode->node.next; } epicsThreadSleep(delay); if (delay<maxdelay) { delay *= 2.0; if (delay>maxdelay) { delay = maxdelay; } } beaconCounter++; /* expected to overflow */ while (beacon_ctl == ctlPause) { epicsThreadSleep(0.1); delay = 0.02; /* Restart beacon timing if paused */ } } }
/* * configureChannelAccessAddressList () */ extern "C" void epicsShareAPI configureChannelAccessAddressList ( ELLLIST *pList, SOCKET sock, unsigned short port ) { ELLLIST tmpList; char *pstr; char yesno[32u]; int yes; /* * dont load the list twice */ assert ( ellCount (pList) == 0 ); // X aCC 392 ellInit ( &tmpList ); // X aCC 392 /* * Check to see if the user has disabled * initializing the search b-cast list * from the interfaces found. */ yes = true; pstr = envGetConfigParam ( &EPICS_CA_AUTO_ADDR_LIST, sizeof (yesno), yesno ); if ( pstr ) { if ( strstr ( pstr, "no" ) || strstr ( pstr, "NO" ) ) { yes = false; } } /* * LOCK is for piiu->destAddr list * (lock outside because this is used by the server also) */ if (yes) { ELLLIST bcastList; osiSockAddr addr; ellInit ( &bcastList ); // X aCC 392 addr.ia.sin_family = AF_UNSPEC; osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr ); forcePort ( &bcastList, port ); removeDuplicateAddresses ( &tmpList, &bcastList, 1 ); if ( ellCount ( &tmpList ) == 0 ) { // X aCC 392 osiSockAddrNode *pNewNode; pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) ); if ( pNewNode ) { /* * if no interfaces found then look for local channels * with the loop back interface */ pNewNode->addr.ia.sin_family = AF_INET; pNewNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK ); pNewNode->addr.ia.sin_port = htons ( port ); ellAdd ( &tmpList, &pNewNode->node ); } else { errlogPrintf ( "configureChannelAccessAddressList(): no memory available for configuration\n" ); } } } addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_ADDR_LIST, port, false ); removeDuplicateAddresses ( pList, &tmpList, 0 ); }