Merge lp:~anj/epics-base/cas-intf-addr-list into lp:~epics-core/epics-base/3.15

Proposed by Andrew Johnson
Status: Merged
Merged at revision: 12508
Proposed branch: lp:~anj/epics-base/cas-intf-addr-list
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 273 lines (+73/-57)
5 files modified
documentation/RELEASE_NOTES.html (+7/-0)
src/ca/client/CAref.html (+10/-5)
src/ioc/rsrv/caservertask.c (+46/-33)
src/ioc/rsrv/cast_server.c (+9/-19)
src/ioc/rsrv/server.h (+1/-0)
To merge this branch: bzr merge lp:~anj/epics-base/cas-intf-addr-list
Reviewer Review Type Date Requested Status
mdavidsaver Approve
Review via email: mp+209803@code.launchpad.net

Description of the change

Partially support EPICS_CAS_INTF_ADDR_LIST in rsrv.

This branch parses the environment parameter into a new global ELLIST.
If the resulting list is empty it adds a single entry of INADDR_ANY.
A warning message is printed if the list contains multiple entries.
The TCP and UDP servers then bind to the first entry in the list.

This approach can be extended to handle multiple entries in the future.

Did I miss anything?

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

softIoc with default settings except EPICS_CA_ADDR_LIST=localhost

> $ netstat -tulpn|grep soft
> tcp 0 0 0.0.0.0:41667 0.0.0.0:* LISTEN 12724/softIoc
> udp 0 0 0.0.0.0:5064 0.0.0.0:* 12724/softIoc
> udp 0 0 0.0.0.0:56316 0.0.0.0:* 12724/softIoc

softIoc with EPICS_CAS_INTF_ADDR_LIST=localhost

> tcp 0 0 127.0.0.1:36373 0.0.0.0:* LISTEN 12759/softIoc
> udp 0 0 127.0.0.1:5064 0.0.0.0:* 12759/softIoc
> udp 0 0 0.0.0.0:50936 0.0.0.0:* 12759/softIoc

softIoc with EPICS_CAS_INTF_ADDR_LIST=localhost and EPICS_CA_SERVER_PORT=5069

> tcp 0 0 127.0.0.1:5069 0.0.0.0:* LISTEN 12843/softIoc
> udp 0 0 127.0.0.1:5069 0.0.0.0:* 12843/softIoc
> udp 0 0 0.0.0.0:50907 0.0.0.0:* 12843/softIoc

softIoc with EPICS_CAS_INTF_ADDR_LIST=localhost:5555

> tcp 0 0 127.0.0.1:5555 0.0.0.0:* LISTEN 12793/softIoc
> udp 0 0 0.0.0.0:54083 0.0.0.0:* 12793/softIoc
> udp 0 0 127.0.0.1:5555 0.0.0.0:* 12793/softIoc

In the final case the UDP port for name requests is 5555 regardless of EPICS_CA_SERVER_PORT (set or unset makes no differnce).

Is this intended behavior?

review: Needs Information
Revision history for this message
Ralph Lange (ralph-lange) wrote :

I guess so.
Note that the EPICS_CAS_INTF_ADDR_LIST settings are for a generic server
that may bind to a number of interfaces.

So, when the default port is changed with
     EPICS_CA_SERVER_PORT=5678
the address list must be able to handle overrides
     EPICS_CAS_INTF_ADDR_LIST="localhost 192.168.13.7 192.168.14.7:5555"
in which case I would expect the first two addresses being bound to port
5678, while the ...14.7 address should listen on 5555.

I.e., explicit setting in EPICS_CAS_INTF_ADDR_LIST should override
EPICS_CA_SERVER_PORT.

~Ralph

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Ok, that makes sense.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'documentation/RELEASE_NOTES.html'
2--- documentation/RELEASE_NOTES.html 2014-02-21 21:49:15 +0000
3+++ documentation/RELEASE_NOTES.html 2014-03-06 22:28:58 +0000
4@@ -15,6 +15,13 @@
5 <h2 align="center">Changes between 3.15.0.1 and 3.15.0.2</h2>
6 <!-- Insert new items immediately below here ... -->
7
8+<h3>Implement EPICS_CAS_INTF_ADDR_LIST in rsrv</h3>
9+
10+<p>The IOC server can now bind to a single IP address (and optional port number)
11+read from the standard environment parameter EPICS_CAS_INTF_ADDR_LIST.
12+Additional addresses included in that parameter after the first will be ignored
13+and a warning message displayed at iocInit time.</p>
14+
15 <h3>Added echo command to iocsh</h3>
16
17 <p>The single argument string may contain escaped characters, which will be
18
19=== modified file 'src/ca/client/CAref.html'
20--- src/ca/client/CAref.html 2013-11-07 23:57:09 +0000
21+++ src/ca/client/CAref.html 2014-03-06 22:28:58 +0000
22@@ -796,7 +796,7 @@
23 </tr>
24 <tr>
25 <td>EPICS_CAS_BEACON_ADDR_LIST</td>
26- <td>{N.N.N.NN.N.N.N:P...}</td>
27+ <td>{N.N.N.N N.N.N.N:P ...}</td>
28 <td>EPICS_CA_ADDR_LIST<sup>1</sup></td>
29 </tr>
30 <tr>
31@@ -811,12 +811,12 @@
32 </tr>
33 <tr>
34 <td>EPICS_CAS_INTF_ADDR_LIST</td>
35- <td>{N.N.N.NN.N.N.N:P...}</td>
36+ <td>{N.N.N.N N.N.N.N:P ...}</td>
37 <td>&lt;none&gt;</td>
38 </tr>
39 <tr>
40 <td>EPICS_CAS_IGNORE_ADDR_LIST</td>
41- <td>{N.N.N.NN.N.N.N:P...}</td>
42+ <td>{N.N.N.N N.N.N.N:P ...}</td>
43 <td>&lt;none&gt;</td>
44 </tr>
45 </tbody>
46@@ -874,8 +874,13 @@
47 addresses in EPICS_CAS_INTF_ADDR_LIST and also to the broadcast addresses of
48 the corresponding LAN interfaces will be accepted by the server. By default,
49 the CA server is accessible from all network interfaces configured into its
50-host. <em>In R3.14 and previous releases the CA server employed by iocCore does
51-not implement this feature</em>.</p>
52+host.</p>
53+
54+<p>In R3.14 and previous releases the CA server employed by iocCore did not
55+implement the EPICS_CAS_INTF_ADDR_LIST feature. In this release the iocCore
56+server will read the first IP address from the parameter variable and use that
57+to select which interface to bind to. Any additional IP addresses will be
58+ignored and a warning message displayed during IOC initialization.</p>
59
60 <h4>Ignoring Process Variable Name Resolution Requests From Certain Hosts</h4>
61
62
63=== modified file 'src/ioc/rsrv/caservertask.c'
64--- src/ioc/rsrv/caservertask.c 2012-07-17 19:36:34 +0000
65+++ src/ioc/rsrv/caservertask.c 2014-03-06 22:28:58 +0000
66@@ -63,8 +63,9 @@
67 unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
68 unsigned priorityOfBeacons;
69 epicsThreadBooleanStatus tbs;
70+ osiSockAddrNode *pNode;
71 struct sockaddr_in serverAddr; /* server's address */
72- osiSocklen_t addrSize;
73+ osiSocklen_t addrSize = (osiSocklen_t) sizeof(struct sockaddr_in);
74 int status;
75 SOCKET clientSock;
76 epicsThreadId tid;
77@@ -85,6 +86,24 @@
78 (unsigned short) CA_SERVER_PORT );
79 }
80
81+ addAddrToChannelAccessAddressList ( &casIntfAddrList,
82+ &EPICS_CAS_INTF_ADDR_LIST, ca_server_port, 0 );
83+ if (ellCount(&casIntfAddrList) == 0) {
84+ pNode = (osiSockAddrNode *) calloc ( 1, sizeof(*pNode) );
85+ pNode->addr.ia.sin_family = AF_INET;
86+ pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
87+ pNode->addr.ia.sin_port = htons ( ca_server_port );
88+ ellAdd ( &casIntfAddrList, &pNode->node );
89+ }
90+ else {
91+ if (ellCount ( &casIntfAddrList ) > 1)
92+ epicsPrintf ("CAS: Multiple entries in EPICS_CAS_INTF_ADDR_LIST, "
93+ "only the first will be used.\n");
94+ pNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList );
95+ }
96+
97+ memcpy ( &serverAddr, &pNode->addr.ia, addrSize );
98+
99 if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) {
100 epicsSocketDestroy ( IOC_sock );
101 }
102@@ -100,50 +119,43 @@
103
104 epicsSocketEnableAddressReuseDuringTimeWaitState ( IOC_sock );
105
106- /* Zero the sock_addr structure */
107- memset ( (void *) &serverAddr, 0, sizeof ( serverAddr ) );
108- serverAddr.sin_family = AF_INET;
109- serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
110- serverAddr.sin_port = htons ( ca_server_port );
111-
112 /* get server's Internet address */
113- status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
114- if ( status < 0 ) {
115- if ( SOCKERRNO == SOCK_EADDRINUSE ) {
116- /*
117- * enable assignment of a default port
118- * (so the getsockname() call below will
119- * work correctly)
120- */
121- serverAddr.sin_port = ntohs (0);
122- status = bind ( IOC_sock,
123- (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
124- }
125- if ( status < 0 ) {
126+
127+ status = bind(IOC_sock, (struct sockaddr *) &serverAddr, addrSize);
128+ if ( status < 0 ) {
129+ if ( SOCKERRNO == SOCK_EADDRINUSE ) {
130+ /*
131+ * enable assignment of a default port
132+ * (so the getsockname() call below will
133+ * work correctly)
134+ */
135+ serverAddr.sin_port = ntohs (0);
136+ status = bind(IOC_sock, (struct sockaddr *) &serverAddr, addrSize);
137+ }
138+ if ( status < 0 ) {
139 char sockErrBuf[64];
140 epicsSocketConvertErrnoToString (
141 sockErrBuf, sizeof ( sockErrBuf ) );
142 errlogPrintf ( "CAS: Socket bind error was \"%s\"\n",
143 sockErrBuf );
144 epicsThreadSuspendSelf ();
145- }
146+ }
147 portChange = 1;
148- }
149+ }
150 else {
151 portChange = 0;
152 }
153
154- addrSize = ( osiSocklen_t ) sizeof ( serverAddr );
155- status = getsockname ( IOC_sock,
156- (struct sockaddr *)&serverAddr, &addrSize);
157- if ( status ) {
158+ status = getsockname ( IOC_sock,
159+ (struct sockaddr *)&serverAddr, &addrSize);
160+ if ( status ) {
161 char sockErrBuf[64];
162 epicsSocketConvertErrnoToString (
163 sockErrBuf, sizeof ( sockErrBuf ) );
164- errlogPrintf ( "CAS: getsockname() error %s\n",
165- sockErrBuf );
166+ errlogPrintf ( "CAS: getsockname() error %s\n",
167+ sockErrBuf );
168 epicsThreadSuspendSelf ();
169- }
170+ }
171
172 ca_server_port = ntohs (serverAddr.sin_port);
173
174@@ -274,6 +286,7 @@
175 }
176 }
177 freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 );
178+ ellInit ( &casIntfAddrList );
179 ellInit ( &beaconAddrList );
180 prsrv_cast_client = NULL;
181 pCaBucket = NULL;
182@@ -948,16 +961,16 @@
183
184 void casStatsFetch ( unsigned *pChanCount, unsigned *pCircuitCount )
185 {
186- LOCK_CLIENTQ;
187+ LOCK_CLIENTQ;
188 {
189 int circuitCount = ellCount ( &clientQ );
190 if ( circuitCount < 0 ) {
191- *pCircuitCount = 0;
192+ *pCircuitCount = 0;
193 }
194 else {
195- *pCircuitCount = (unsigned) circuitCount;
196+ *pCircuitCount = (unsigned) circuitCount;
197 }
198 *pChanCount = rsrvChannelCount;
199 }
200- UNLOCK_CLIENTQ;
201+ UNLOCK_CLIENTQ;
202 }
203
204=== modified file 'src/ioc/rsrv/cast_server.c'
205--- src/ioc/rsrv/cast_server.c 2009-07-09 16:37:24 +0000
206+++ src/ioc/rsrv/cast_server.c 2014-03-06 22:28:58 +0000
207@@ -115,23 +115,14 @@
208 */
209 void cast_server(void *pParm)
210 {
211- struct sockaddr_in sin;
212+ osiSockAddrNode *paddrNode;
213+ struct sockaddr_in sin;
214 int status;
215 int count=0;
216 struct sockaddr_in new_recv_addr;
217 osiSocklen_t recv_addr_size;
218- unsigned short port;
219 osiSockIoctl_t nchars;
220
221- if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) {
222- port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT,
223- (unsigned short) CA_SERVER_PORT );
224- }
225- else {
226- port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
227- (unsigned short) CA_SERVER_PORT );
228- }
229-
230 recv_addr_size = sizeof(new_recv_addr);
231
232 if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) {
233@@ -174,13 +165,11 @@
234 #endif
235
236 epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock );
237-
238- /* Zero the sock_addr structure */
239- memset((char *)&sin, 0, sizeof(sin));
240- sin.sin_family = AF_INET;
241- sin.sin_addr.s_addr = htonl(INADDR_ANY);
242- sin.sin_port = htons(port);
243-
244+
245+ paddrNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList );
246+
247+ memcpy(&sin, &paddrNode->addr.ia, sizeof (sin));
248+
249 /* get server's Internet address */
250 if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){
251 char sockErrBuf[64];
252@@ -245,7 +234,8 @@
253 * see if the next message is for this same client.
254 */
255 if (prsrv_cast_client->send.stk>sizeof(caHdr)) {
256- status = memcmp( (void *)&prsrv_cast_client->addr, (void *)&new_recv_addr, recv_addr_size);
257+ status = memcmp(&prsrv_cast_client->addr,
258+ &new_recv_addr, recv_addr_size);
259 if(status){
260 /*
261 * if the address is different
262
263=== modified file 'src/ioc/rsrv/server.h'
264--- src/ioc/rsrv/server.h 2012-06-22 23:16:26 +0000
265+++ src/ioc/rsrv/server.h 2014-03-06 22:28:58 +0000
266@@ -165,6 +165,7 @@
267 GLBLTYPE unsigned short ca_server_port;
268 GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */
269 GLBLTYPE ELLLIST beaconAddrList;
270+GLBLTYPE ELLLIST casIntfAddrList;
271 GLBLTYPE epicsMutexId clientQlock;
272 GLBLTYPE struct client *prsrv_cast_client;
273 GLBLTYPE BUCKET *pCaBucket;

Subscribers

People subscribed via source and target branches