diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 96eb0a540..2563546fc 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -15,6 +15,13 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.
Changes between 3.15.0.1 and 3.15.0.2
+Implement EPICS_CAS_INTF_ADDR_LIST in rsrv
+
+The IOC server can now bind to a single IP address (and optional port number)
+read from the standard environment parameter EPICS_CAS_INTF_ADDR_LIST.
+Additional addresses included in that parameter after the first will be ignored
+and a warning message displayed at iocInit time.
+
alarmString.h deprecated again
The string arrays that provide string versions of the alarm status and
diff --git a/src/ca/client/CAref.html b/src/ca/client/CAref.html
index 43a4f43fa..98dbdd5e5 100644
--- a/src/ca/client/CAref.html
+++ b/src/ca/client/CAref.html
@@ -874,8 +874,13 @@ network interfaces. Specifically, UDP search messages addressed to both the IP
addresses in EPICS_CAS_INTF_ADDR_LIST and also to the broadcast addresses of
the corresponding LAN interfaces will be accepted by the server. By default,
the CA server is accessible from all network interfaces configured into its
-host. In R3.14 and previous releases the CA server employed by iocCore does
-not implement this feature.
+host.
+
+In R3.14 and previous releases the CA server employed by iocCore did not
+implement the EPICS_CAS_INTF_ADDR_LIST feature. In this release the iocCore
+server will read the first IP address from the parameter variable and use that
+to select which interface to bind to. Any additional IP addresses will be
+ignored and a warning message displayed during IOC initialization.
Ignoring Process Variable Name Resolution Requests From Certain Hosts
diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c
index e3ab087f1..14c7ce1b0 100644
--- a/src/ioc/rsrv/caservertask.c
+++ b/src/ioc/rsrv/caservertask.c
@@ -63,8 +63,9 @@ static void req_server (void *pParm)
unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
unsigned priorityOfBeacons;
epicsThreadBooleanStatus tbs;
+ osiSockAddrNode *pNode;
struct sockaddr_in serverAddr; /* server's address */
- osiSocklen_t addrSize;
+ osiSocklen_t addrSize = (osiSocklen_t) sizeof(struct sockaddr_in);
int status;
SOCKET clientSock;
epicsThreadId tid;
@@ -85,6 +86,24 @@ static void req_server (void *pParm)
(unsigned short) CA_SERVER_PORT );
}
+ addAddrToChannelAccessAddressList ( &casIntfAddrList,
+ &EPICS_CAS_INTF_ADDR_LIST, ca_server_port, 0 );
+ if (ellCount(&casIntfAddrList) == 0) {
+ pNode = (osiSockAddrNode *) calloc ( 1, sizeof(*pNode) );
+ pNode->addr.ia.sin_family = AF_INET;
+ pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
+ pNode->addr.ia.sin_port = htons ( ca_server_port );
+ ellAdd ( &casIntfAddrList, &pNode->node );
+ }
+ else {
+ if (ellCount ( &casIntfAddrList ) > 1)
+ epicsPrintf ("CAS: Multiple entries in EPICS_CAS_INTF_ADDR_LIST, "
+ "only the first will be used.\n");
+ pNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList );
+ }
+
+ memcpy ( &serverAddr, &pNode->addr.ia, addrSize );
+
if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) {
epicsSocketDestroy ( IOC_sock );
}
@@ -100,50 +119,43 @@ static void req_server (void *pParm)
epicsSocketEnableAddressReuseDuringTimeWaitState ( IOC_sock );
- /* Zero the sock_addr structure */
- memset ( (void *) &serverAddr, 0, sizeof ( serverAddr ) );
- serverAddr.sin_family = AF_INET;
- serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
- serverAddr.sin_port = htons ( ca_server_port );
-
/* get server's Internet address */
- status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
- if ( status < 0 ) {
- if ( SOCKERRNO == SOCK_EADDRINUSE ) {
- /*
- * enable assignment of a default port
- * (so the getsockname() call below will
- * work correctly)
- */
- serverAddr.sin_port = ntohs (0);
- status = bind ( IOC_sock,
- (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
- }
- if ( status < 0 ) {
+
+ status = bind(IOC_sock, (struct sockaddr *) &serverAddr, addrSize);
+ if ( status < 0 ) {
+ if ( SOCKERRNO == SOCK_EADDRINUSE ) {
+ /*
+ * enable assignment of a default port
+ * (so the getsockname() call below will
+ * work correctly)
+ */
+ serverAddr.sin_port = ntohs (0);
+ status = bind(IOC_sock, (struct sockaddr *) &serverAddr, addrSize);
+ }
+ if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: Socket bind error was \"%s\"\n",
sockErrBuf );
epicsThreadSuspendSelf ();
- }
+ }
portChange = 1;
- }
+ }
else {
portChange = 0;
}
- addrSize = ( osiSocklen_t ) sizeof ( serverAddr );
- status = getsockname ( IOC_sock,
- (struct sockaddr *)&serverAddr, &addrSize);
- if ( status ) {
+ status = getsockname ( IOC_sock,
+ (struct sockaddr *)&serverAddr, &addrSize);
+ if ( status ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
- errlogPrintf ( "CAS: getsockname() error %s\n",
- sockErrBuf );
+ errlogPrintf ( "CAS: getsockname() error %s\n",
+ sockErrBuf );
epicsThreadSuspendSelf ();
- }
+ }
ca_server_port = ntohs (serverAddr.sin_port);
@@ -274,6 +286,7 @@ int rsrv_init (void)
}
}
freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 );
+ ellInit ( &casIntfAddrList );
ellInit ( &beaconAddrList );
prsrv_cast_client = NULL;
pCaBucket = NULL;
@@ -948,16 +961,16 @@ struct client *create_tcp_client ( SOCKET sock )
void casStatsFetch ( unsigned *pChanCount, unsigned *pCircuitCount )
{
- LOCK_CLIENTQ;
+ LOCK_CLIENTQ;
{
int circuitCount = ellCount ( &clientQ );
if ( circuitCount < 0 ) {
- *pCircuitCount = 0;
+ *pCircuitCount = 0;
}
else {
- *pCircuitCount = (unsigned) circuitCount;
+ *pCircuitCount = (unsigned) circuitCount;
}
*pChanCount = rsrvChannelCount;
}
- UNLOCK_CLIENTQ;
+ UNLOCK_CLIENTQ;
}
diff --git a/src/ioc/rsrv/cast_server.c b/src/ioc/rsrv/cast_server.c
index 27cbea355..939cc5514 100644
--- a/src/ioc/rsrv/cast_server.c
+++ b/src/ioc/rsrv/cast_server.c
@@ -115,23 +115,14 @@ static void clean_addrq(void)
*/
void cast_server(void *pParm)
{
- struct sockaddr_in sin;
+ osiSockAddrNode *paddrNode;
+ struct sockaddr_in sin;
int status;
int count=0;
struct sockaddr_in new_recv_addr;
osiSocklen_t recv_addr_size;
- unsigned short port;
osiSockIoctl_t nchars;
- if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) {
- port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT,
- (unsigned short) CA_SERVER_PORT );
- }
- else {
- port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
- (unsigned short) CA_SERVER_PORT );
- }
-
recv_addr_size = sizeof(new_recv_addr);
if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) {
@@ -174,13 +165,11 @@ void cast_server(void *pParm)
#endif
epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock );
-
- /* Zero the sock_addr structure */
- memset((char *)&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
- sin.sin_port = htons(port);
-
+
+ paddrNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList );
+
+ memcpy(&sin, &paddrNode->addr.ia, sizeof (sin));
+
/* get server's Internet address */
if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){
char sockErrBuf[64];
@@ -245,7 +234,8 @@ void cast_server(void *pParm)
* see if the next message is for this same client.
*/
if (prsrv_cast_client->send.stk>sizeof(caHdr)) {
- status = memcmp( (void *)&prsrv_cast_client->addr, (void *)&new_recv_addr, recv_addr_size);
+ status = memcmp(&prsrv_cast_client->addr,
+ &new_recv_addr, recv_addr_size);
if(status){
/*
* if the address is different
diff --git a/src/ioc/rsrv/server.h b/src/ioc/rsrv/server.h
index 9651ca601..c45728593 100644
--- a/src/ioc/rsrv/server.h
+++ b/src/ioc/rsrv/server.h
@@ -165,6 +165,7 @@ GLBLTYPE SOCKET IOC_cast_sock;
GLBLTYPE unsigned short ca_server_port;
GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */
GLBLTYPE ELLLIST beaconAddrList;
+GLBLTYPE ELLLIST casIntfAddrList;
GLBLTYPE epicsMutexId clientQlock;
GLBLTYPE struct client *prsrv_cast_client;
GLBLTYPE BUCKET *pCaBucket;