Merge lp:~epics-core/epics-base/rsrvbindiface into lp:~epics-core/epics-base/3.15
- rsrvbindiface
- Merge into 3.15
Status: | Merged |
---|---|
Merged at revision: | 12728 |
Proposed branch: | lp:~epics-core/epics-base/rsrvbindiface |
Merge into: | lp:~epics-core/epics-base/3.15 |
Diff against target: |
2686 lines (+1058/-707) 34 files modified
documentation/RELEASE_NOTES.html (+29/-0) src/ca/client/CAref.html (+13/-20) src/ca/client/addrList.h (+1/-1) src/ca/client/iocinf.cpp (+6/-5) src/ca/client/udpiiu.cpp (+13/-0) src/ca/legacy/pcas/generic/caServerI.cc (+33/-0) src/ca/legacy/pcas/generic/caServerI.h (+2/-0) src/ca/legacy/pcas/io/bsdSocket/caServerIO.cc (+17/-0) src/ca/legacy/pcas/io/bsdSocket/caServerIO.h (+2/-0) src/ca/legacy/pcas/io/bsdSocket/casDGIntfIO.cc (+18/-59) src/ioc/db/dbChannel.c (+21/-15) src/ioc/rsrv/camessage.c (+8/-31) src/ioc/rsrv/caserverio.c (+1/-1) src/ioc/rsrv/caservertask.c (+726/-234) src/ioc/rsrv/cast_server.c (+76/-97) src/ioc/rsrv/online_notify.c (+15/-197) src/ioc/rsrv/server.h (+22/-9) src/libCom/bucketLib/bucketLib.c (+2/-2) src/libCom/env/envDefs.h (+2/-0) src/libCom/env/envSubr.c (+14/-1) src/libCom/osi/os/Darwin/osdSock.h (+1/-0) src/libCom/osi/os/Linux/osdSock.h (+1/-0) src/libCom/osi/os/RTEMS/osdSock.h (+1/-0) src/libCom/osi/os/WIN32/osdSock.h (+2/-1) src/libCom/osi/os/cygwin32/osdSock.h (+1/-0) src/libCom/osi/os/default/osdNetIntf.c (+23/-30) src/libCom/osi/os/freebsd/osdSock.h (+1/-0) src/libCom/osi/os/iOS/osdSock.h (+1/-0) src/libCom/osi/os/solaris/osdSock.h (+1/-0) src/libCom/osi/os/vxWorks/osdSock.h (+1/-0) src/std/filters/arr.c (+1/-1) src/std/filters/dbnd.c (+1/-1) src/std/filters/sync.c (+1/-1) src/std/filters/ts.c (+1/-1) |
To merge this branch: | bzr merge lp:~epics-core/epics-base/rsrvbindiface |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ralph Lange | Needs Fixing | ||
Andrew Johnson | Approve | ||
EPICS Core Developers | Pending | ||
mdavidsaver | Pending | ||
Review via email:
|
This proposal supersedes a proposal from 2015-12-21.
Commit message
Description of the change
Updates to RSRV, mainly to allow binding to a specific network interfaces via. EPICS_CAS_
Along the way support for name lookup via IPv4 multicasting is added, but not enabled by default. Use by adding an mcast address to EPICS_CA_ADDR_LIST.
One potentially troublesome change is to allow osiSockDiscover
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : Posted in a previous version of this proposal | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Rebased against 3.15
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
When building for VxWorks 5.5.2 (which we still support):
../udpiiu.cpp: In method `udpiiu:
../udpiiu.cpp:169: passing `int *' as argument 4 of `setsockopt(int, int, int, char *, int)'
The fix is to cast &flag to (char *) [I tried (void *), but the C++ rules don't allow that].
Later, same target-arch:
../../.
../../.
../../.
../../.
../../.
../../.
../../.
../../.
../../.
On line 135 change bind() arg #2 to be (struct sockaddr *) &addr->sa (cast is needed to drop const).
Line 201 is not standard C code, a declaration appears after other statements in block; swapped with preceding line.
Line 579 needs another cast to (char *).
The result builds on all my standard architectures.
Question: Is 'rsrv_grap_tcp' a typo for 'rsrv_grab_tcp'?
Could your point about there being a broadcast route through lo conceivably apply to other OSs too? If so I would prefer that we use some other conditional in the libCom/
More to come, I'll try to do some testing this afternoon.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
On 01/20/2016 02:10 PM, Andrew Johnson wrote:
> Question: Is 'rsrv_grap_tcp' a typo for 'rsrv_grab_tcp'?
I'm going to go with, yes.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
On 01/20/2016 02:10 PM, Andrew Johnson wrote:
> Could your point about there being a broadcast route through lo conceivably apply to other OSs too?
I suspect so as it seems like a reasonable thing to do. However, I
couldn't find any reference, and am not in a position to test any other
targets except RTEMS (where it isn't useful).
> ... I would define some macro in osi/os/
Seems reasonable.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
I'm not quite sure what this means, but on my Windows & Cygwin box:
ECLIPSE$ route PRINT -4 127*
=======
Interface List
12...ac 16 2d 0d 54 de ......Intel(R) 82579LM Gigabit Network Connection
1....
13...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter
11...00 00 00 00 00 00 00 e0 Microsoft 6to4 Adapter
=======
IPv4 Route Table
=======
Active Routes:
Network Destination Netmask Gateway Interface Metric
127.0.0.0 255.0.0.0 On-link 127.0.0.1 306
127.0.0.1 255.255.255.255 On-link 127.0.0.1 306
127.255.255.255 255.255.255.255 On-link 127.0.0.1 306
=======
Persistent Routes:
None
It's likely that Cygwin would see those same routes, and it uses the osi/os/default implementation (how would I test that?). We might want to add similar code to the osi/WIN32/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Seems to be working for me on VxWorks 6.9, I can connect to PVs, and outgoing CA client connections still work OK too (although I didn't test setting CA_ADDR_LIST).
Also works with a second network interface configured at 10.0.0.2 (but not actually connected to anything):
iocanj> casr 2
Channel Access Server V4.13
No clients connected.
Server interface 0.0.0.0:5064
UDP receiver 1 0.0.0.0:5064
Beacon destination 10.0.0.255:5065
Beacon destination 164.54.11.255:5065
There are currently 1288 bytes on the server's free list
7 client(s), 0 channel(s), 0 event(s) (monitors) 0 putNotify(s)
0 small buffers (16384 bytes ea), and 0 jumbo buffers (16408 bytes ea)
The server's resource id conversion table:
Bucket entries in use = 0 bytes in use = 16404
Bucket entries/hash id - mean = 0.000000 std dev = 0.000000 max = 0
The server's array size limit is 16408 bytes max
Channel Access Address List
10.0.0.255:5065
164.54.11.255:5065
value = 19 = 0x13
The "Server interface 0.0.0.0:5064" and "UDP receiver 1 0.0.0.0:5064" lines are slightly confusing in the above status message, although I guess they do make sense. At least the casr command now shows the dynamically allocated TCP port number (which used to only show up at iocInit, making it hard to look up later on).
when running on an IOC without DNS properly configured the two entries in the CA Address list at the bottom take a minute or two each to print while waiting for the DNS search to time out; in my experience network administrators don't add names for their broadcast IP addresses to DNS, so why are we querying DNS before printing just the numbers in that list? I guess there might be host IPs in there too, but in this case I would be happy with just printing the numbers even for them. You probably haven't touched this part of the code though...
Pointing EPICS_CAS_
When I pointed EPICS_CAS_
Starting iocInit
#######
## EPICS R3.15.3-DEV $$Date: Sun 2015-11-22 18:10:40 +0100 $$
## EPICS Base built Jan 20 2016
#######
Warning: RSRV has empty beacon address list
CAS: Socket bind 164.54.11.255:5064 error was "S_errno_EINVAL"
Thread tShell0 (0x6f6c70) can't proceed, suspending.
Users are going to try putting broadcast addresses in EPICS_CAS_
How might I go about testing the multi-cast support?
This branch at least needs an entry in the Release Notes explaining what's new and how to configure the new features. I'm not sure if there's a suitable place in the AppDevGuide for more detail or not, although I think we...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
So this branch was overtaking my rebase on GitHub... need to rearrange.
I pushed the fix for the issue with compiling on MinGW to the 3.15 branch (http://
Do we need more detailed test instructions?
Remember that we wanted to trigger a serious testing campaign for this, so we should have some kind of rough test plan that we want people to run.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> Do we need more detailed test instructions?
We do, so I'll write something up.
- 12737. By Andrew Johnson
-
Fix build for vxWorks 5.5.2
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Committed fixes for building on VxWorks 5.5.2.
- 12738. By mdavidsaver
-
minor
fix typo
expand error message
skip redundant (and misleading) print of beacon address list - 12739. By mdavidsaver
-
rsrv: fixup beacon address list handling
should be based on client interface list,
not server. - 12740. By mdavidsaver
-
rsrv: loopback mcast beacons
- 12741. By mdavidsaver
-
don't use EPICS_CA_ADDR_LIST for server interface list
keep existing behavior, and server binds wildcard
when only client address list is specified. - 12742. By mdavidsaver
-
update release notes
- 12743. By mdavidsaver
-
pcas: listen for mcast search request
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Fixed incorrect broadcast address list construction. Made the "no addresses" error message longer. Added release notes. Teach PCAS to listen for mcast search requests as well.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> ... the two entries in the CA Address list ...
This isn't actually the CA address list, but rather the beacon address list printed a second time. The first uses ipAddrToDottedIP(), and the second is now removed.
FYI the only place I've found the actual CA address list (for the dbCa context) is buried in "dbcar '' 8".
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> ... How might I go about testing the multi-cast support? ...
Set:
EPICS_CAS_
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Since this branch allows 127.255.255.255 to be discovered and included in the default address list (for Linux), some configurations will result in more spurious duplicate PV warnings when IOC and client are on the same system. I go back and forth about whether this is acceptable or not. Thoughts?
- 12744. By Andrew Johnson
-
Fix build for vxWorks 5.5.2 (again)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
You broke the generation of beacon anomalies at IOC startup somehow.
There is a tool build as part of src/ca called casw which monitors for and displays beacon anomalies, using exactly the same code that the clients use. When I start a regular 3.14 softIoc with casw running I get the expected anomalies displayed, but when starting a softIoc from this branch it shows nothing.
The IOC is sending out beacons at the usual exponentially-
localhost:5064 2016-01-21 12:56:35.851115672
tux.aps.
localhost:5064 2016-01-21 12:56:35.871209057
tux.aps.
localhost:5064 2016-01-21 12:56:35.911352969
tux.aps.
localhost:5064 2016-01-21 12:56:35.991482300
tux.aps.
localhost:5064 2016-01-21 12:56:36.151682412
tux.aps.
localhost:5064 2016-01-21 12:56:36.471809095
tux.aps.
localhost:5064 2016-01-21 12:56:37.111908997
tux.aps.
localhost:5064 2016-01-21 12:56:38.392053916
tux.aps.
localhost:5064 2016-01-21 12:56:40.952238006
tux.aps.
localhost:5064 2016-01-21 12:56:46.072448531
tux.aps.
I tried starting the IOC with EPICS_CAS_
- 12745. By mdavidsaver
-
rsrv: beaconCounter not updated
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> You broke the generation of beacon anomalies at IOC startup somehow.
Good catch, and now fixed. I had checked that beacons were sent, but didn't look at the contents. The counter wasn't being copied into the packet buffer, so it was always sending a count of 0.
Another (intentional) change is that beacons are sent with the "address" field set to zero, so carepeater will fill it in based on the source address. With the switch to an unconnected socket this gives the correct result (verified with casw and wireshark).
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Beacons fixed, thanks.
Trying multicast name resolution:
tux$ EPICS_CAS_
Starting iocInit
#######
## EPICS R3.15.3-DEV $$Date: Sun 2015-11-22 18:10:40 +0100 $$
## EPICS Base built Jan 21 2016
#######
CAS address list can not contain 0.0.0.0 and other addresses, ignoring...
iocRun: All initialization complete
epics>
I get the same output from 'casr 2' without the warning message by omitting the 0.0.0.0 interface address, so I'll assume including it was just a mistake in your instructions above.
Searches from the same subnet succeed with EPICS_CA_
If I configure the IOC to only use the localhost interface, why does it still send beacons through my primary interface?
tux$ EPICS_CAS_
Starting iocInit
#######
## EPICS R3.15.3-DEV $$Date: Sun 2015-11-22 18:10:40 +0100 $$
## EPICS Base built Jan 21 2016
#######
iocRun: All initialization complete
epics> casr 2
Channel Access Server V4.13
No clients connected.
Server interface 127.0.0.1:5064
UDP receiver 1 127.0.0.1:5064
UDP receiver 2 127.255.
Beacon destination 127.255.
Beacon destination 164.54.11.255:5065
...
I had expected that explicitly setting the interface would also configure the beacons to be sent through the same interface(s), although I do realize the original code didn't work like that and it can be done manually. I'd be OK with leaving that change for later if there are objections to fixing it here though.
I also have some minor modifications to casr which I'll finish off next week.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
> Trying multicast name resolution:
>
> tux$ EPICS_CAS_
> EPICS_CA_
> Starting iocInit
> #######
> ## EPICS R3.15.3-DEV $$Date: Sun 2015-11-22 18:10:40 +0100 $$
> ## EPICS Base built Jan 21 2016
> #######
> CAS address list can not contain 0.0.0.0 and other addresses, ignoring...
> iocRun: All initialization complete
> epics>
>
> I get the same output from 'casr 2' without the warning message by omitting
> the 0.0.0.0 interface address, so I'll assume including it was just a mistake
> in your instructions above.
>
> Searches from the same subnet succeed with EPICS_CA_
> EPICS_CA_
Hm.
Shouldn't there be a way to specify: "bind to all available network interfaces, plus the extra multicast address".
It look s like the settings from Michael's instructions were trying to do this, but the "0.0.0.0" was rejected. (Which might be wrong.)
Do searches from the same subnet with broadcasts or directed to the IOCs IP work in this configuration?
- 12746. By mdavidsaver
-
rsrv: fix wildcard check ordering
filter out mcast addresses before wildcard uniqueness check.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Ha, I should be more careful about testing exactly the examples I give.
> EPICS_CAS_
Triggered the error.
> EPICS_CAS_
Didn't.
Now fixed so that ordering shouldn't matter.
Also, EPICS_CAS_
To actually trigger this error (now cantProceed) include the wildcard address and a specific interface address.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> Do I need to have our network admins configure something for searches to work across subnets?
I'm fairly certain that I'm doing the right thing on the socket level. But I just don't know how what additional work is needed at the router/switch level. As I think about it, this is probably a good tech-talk question.
For layer 2 devices (hubs and dumb switches) multicasts and broadcasts are quite similar. In the presence of layer 3 (routers and "smart" switches) things will be different. I'm not sure how to test this situation. Note that how this works, and what configuration is needed, may well depend on which mcast address is used.
- 12747. By mdavidsaver
-
rsrv: oops
improper rebase
- 12748. By mdavidsaver
-
rsrv: more beacon address fixups
should really be based on *server* config
as beacons should be sent to clients attempting
to connect to the server.By default send beacons to bcast addresses
from the interface address list.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
More changes to beacon address list population (I think I've got it this time).
https:/
Details most tested configurations with expected results.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
I have a set of changes which significantly tidy up the output from casr. Should I commit them here, or to 3.16 after this branch has been merged up?
Here's some new output:
epics> casr
Channel Access Server V4.13
2 client(s) connected.
epics> casr 1
Channel Access Server V4.13
2 client(s) connected:
CA-client at 164.54.9.24:57238 'tux.aps.anl.gov':
User 'anj', V4.13, Priority = 0, 2 Channel(s)
CA-client at 164.54.8.21:33434 'venus':
User 'anj', V4.11, Priority = 0, 1 Channel(s)
CAS-TCP server 0.0.0.0:5064
CAS-UDP name server 0.0.0.0:5064
2 CAS-beacon destinations:
127.
164.
epics> casr 2
Channel Access Server V4.13
2 client(s) connected:
CA-client at 164.54.9.24:57238 'tux.aps.anl.gov':
User 'anj', V4.13, Priority = 0, 2 Channel(s)
Channel: 'anj:exit'
Channel: 'anj:exit.
CA-client at 164.54.8.21:33434 'venus':
User 'anj', V4.11, Priority = 0, 1 Channel(s)
Channel: 'anj:exit.A'
CAS-TCP server 0.0.0.0:5064
CAS-UDP name server 0.0.0.0:5064
2 CAS-beacon destinations:
127.
164.
epics> casr 3
Channel Access Server V4.13
2 client(s) connected:
CA-client at 164.54.9.24:57238 'tux.aps.anl.gov':
User 'anj', V4.13, Priority = 0, 2 Channel(s)
Channel: 'anj:exit'
# on eventq=1, access=rw
Channel: 'anj:exit.
2 filters (1 pre eventq, 0 post eventq)
final field_type=
# on eventq=1, access=rw
CA-client at 164.54.8.21:33434 'venus':
User 'anj', V4.11, Priority = 0, 1 Channel(s)
Channel: 'anj:exit.A'
# on eventq=1, access=rw
CAS-TCP server 0.0.0.0:5064
CAS-UDP name server 0.0.0.0:5064
2 CAS-beacon destinations:
127.
164.
epics> casr 4
Channel Access Server V4.13
2 client(s) connected:
CA-client at 164.54.9.24:57238 'tux.aps.anl.gov':
User 'anj', V4.13, Priority = 0, 2 Channel(s)
Task Id = 0x7f1e2c005680, Socket FD = 7
10.30 secs since last send, 10.30 secs since last receive
Unprocessed request bytes = 0, Undelivered response bytes = 0
State = up
Channel: 'anj:exit'
# on eventq=1, access=rw
Channel: 'anj:exit.
2 filters (1 pre eventq, 0 post eventq)
final field_type=
# on eventq=1, access=rw
CA-client at 164.54.8.21:33434 'venus':
User 'anj', V4.11, Priority = 0, 1 Channel(s)
Task Id = 0x7f1e2c005f80, Socket FD = 9
11.35 secs since last send, 11.35 secs since last receive
Unprocessed request bytes = 0, Undelivered response bytes...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
No strong preference.
But since the changes are probably in one source file and thus easy to separate from the functional changes, why not here.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Well I think the answer is simple and none technical. Commit it if you have time to update the wiki ;)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Ok; the changes are mostly in rsrv/caserverta
I did notice that casr() no longer prints a log_one_client() report for the UDP (i.e. name-server) clients. There used to be only one such client thread, but now the number can vary, with one or two threads for each interface. I had removed the UDP reporting code from the log_one_client() routine since it was no longer being used, but I just put it back in case we want to add these threads back into the report. I think I know how to do that if it's wanted.
How are the multicast monitors supposed to work? There isn't a separate thread started for them, the code just joins every primary UDP socket to the multicast group(s) configured. Isn't that going to cause multiple search replies from any IOC that has two interfaces say if both receive a copy of the same multicast search request? We might need a way to configure which multicast addresses get joined to which interfaces if this starts to be used much.
- 12749. By Andrew Johnson
-
Improve casr() output
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
I added 2 comments to the wiki page in bold red, the beacon list for Test #2 seems wrong, and Test #6 gives me different results (the interface on 0.0.0.0 is still open, so clients in the same subnet can still connect without having to use the multicast address).
I think I'm done with this now; apart from multi-cast it builds and works fine.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> How are the multicast monitors supposed to work? ... Isn't that going to cause multiple search replies from any IOC that has two interfaces say if both receive a copy of the same multicast search request?
The best I can say is probably not, at least on Linux. I haven't found any clear description, of all that is involved here, so I could be completely wrong. As I understand it, as with any ip packet, a multicast packet is always received on a specific interface, and won't be forwarded absent some specific routing rule ("ip mroute" is empty by default). So an mcast should only be delivered to sockets bound to the interface it was received on, and joined to the group.
Linux might have some additional hoops to jump. I find some references to needing to disable reverse path filtering (rp_filter), though this isn't enabled by default w/ debian 8.
Once the test-plan wiki page is deemed correct, and the code to match, we had discussed putting out a request for testing on tech-talk. I'd like to have this tested in a more realistic setting.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> the beacon list for Test #2 seems wrong
Not surprising. For some reason I'm getting confused about whether this should match the server or client interface address list. I've "fixed" this at least twice now and two parity flips means I need some outside input. Can you fix the wiki page to what you think it should be?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
A given socket will only send multicast packets out a single interface (as determined by the local routing table or IP_MULTICAST_IF). So no duplication there.
There probably should be some way of configuring IP_MULTICAST_TTL though. Would you care to pick a EPICS_CA_* name for this Andrew?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> Test #6 gives me different results ...
... Due to the way my test system is configured :P You result is the correct one.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> ... We might need a way to configure which multicast addresses get joined to which interfaces if this starts to be used much.
> ... as determined by the local routing table or IP_MULTICAST_IF ...
Yes, to allow full flexibility the both client and server address lists would need to be configured with pairs of multicast+interface address. However, I'm inclined to forgo this unnecessary until someone describes a situation where this is necessary, or even helpful.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Beacons should be related to the server interfaces in use. In the past they weren't, originally because there were no EPICS_CAS_ variables, although later I think Jeff just re-used the contents of EPICS_CA_ADDR_LIST for rsrv's beacon list unless you explicitly set EPICS_CAS_
Starting a softIoc with all defaults, I get this:
tux$ bin/linux-
...
CAS-TCP server on 0.0.0.0:5064 with
CAS-UDP name server on 0.0.0.0:5064
Sending CAS-beacons to 2 addresses:
127.
164.
If I set EPICS_CAS_
tux$ EPICS_CAS_
...
CAS-TCP server on 164.54.9.24:5064 with
CAS-UDP unicast name server on 164.54.9.24:5064
CAS-UDP broadcast name server on 164.54.11.255:5064
Sending CAS-beacons to 1 address:
164.
Setting it to localhost I get this:
tux$ EPICS_CAS_
...
CAS-TCP server on 127.0.0.1:5064 with
CAS-UDP unicast name server on 127.0.0.1:5064
CAS-UDP broadcast name server on 127.255.
Sending CAS-beacons to 1 address:
127.
I can add addresses to the beacon list:
tux$ EPICS_CAS_
...
CAS-TCP server on 127.0.0.1:5064 with
CAS-UDP unicast name server on 127.0.0.1:5064
CAS-UDP broadcast name server on 127.255.
Sending CAS-beacons to 2 addresses:
127.
224.0.2.9:5065
Those all look correct to me so far, beacons are being sent to the broadcast addresses of the interfaces that my servers are listening on, plus any others I explicitly specify. However if I set EPICS_CA_
tux$ EPICS_CAS_
...
Warning: RSRV has empty beacon address list
...
CAS-TCP server on 127.0.0.1:5064 with
CAS-UDP unicast name server on 127.0.0.1:5064
CAS-UDP broadcast name server on 127.255.
Sending CAS-beacons to 0 addresses:
In this case it still seems to be copying the initial beacon list from the EPICS_CA_ADDR_LIST instead of the interface list because I can put addresses in the beacon list by adding them to EPICS_CA_ADDR_LIST, e.g:
tux$ EPICS_CAS_
bin/linux-
...
CAS-TCP server on 127.0.0.1:5064 with
CAS-UDP unicast name server on 127.0.0.1:5064
CAS-UDP broadcast name server on 127.255.
Sending CAS-beacons to 1 address:
224.0.2.9:5065
A different issue: If I put a multicast address in EPICS_CAS_
tux$ EPICS_CAS_
- 12750. By mdavidsaver
-
rsrv: decouple some client/server config
the automatic beacon address list should follow
the server interface address list, and not be
effected by any client config.Also, don't populate the interface address list
from EPICS_CAS_BEACON_ ADDR_LIST as this will
almost never contain local interface addresses.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> Beacons should be related to the server interfaces in use.
Ok, auto beacon list is no longer tied to client auto address list.
Also, the server interface list will no longer use the beacon address list as a fallback.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Thanks, I think this makes much more sense. The behavior change does need documenting though, in the Release Notes entry and probably in CAref.html as well. I can update the Wiki page to match if you like.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> The behavior change does need documenting though, in the Release Notes entry and probably in CAref.html
Which raises the question: what about PCAS?
> I can update the Wiki page to match if you like.
Please do. And you may assume in future that I would always like.
- 12751. By mdavidsaver
-
pcas: no fallbacks for beacon address list
Don't mix client and server configuration
by defaulting the server beacon list to use
the client address list. - 12752. By mdavidsaver
-
ca: update CAref.html with changes to beacon address list
Note that server beacon address list will no longer
consider client address list as a fallback. - 12753. By mdavidsaver
-
update release notes
- 12754. By mdavidsaver
-
rsrv: EPICS_CAS_
IGNORE_ ADDR_LIST - 12755. By mdavidsaver
-
libCom: fix debug print formats in osiSockDiscover
BroadcastAddres ses() - 12756. By mdavidsaver
-
rsrv: "casr 1" shows ignore list
- 12757. By mdavidsaver
-
update release notes
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> Beacons should be related to the server interfaces in use.
I made the corresponding change to PCAS as well.
I also made an attempt to teach RSRV about EPICS_CAS_
Updated CAref.html and release notes.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Unfortunately I think your PCAS changes have broken something. I can run the base-3.15 excas example with no arguments and I get no errors, but if I run it from this branch I get the following errors, printed at the exponentially-
../../.
../../.
../../.
The IP address in that error message is the broadcast address of my local subnet. Connections to the excas PVs from a local client do succeed, so I think it is listening on the primary interface properly. Running casw while starting the server shows beacons coming from localhost but not from the machine's regular IP address (the opposite of running the base-3.15 version of excas).
I updated the Wiki page to remove my last red question and fix the expected casr output there, and fixed the CAS-beacon list in Test #6.
About the wiki page, I don't think we really need to set EPICS_CA_ADDR_LIST or AUTO_ADDR_LIST when starting the IOC in most of these tests, dbCa will always connect to local channels through the internal channel provider anyway, it doesn't use the network at all. Test #5 and maybe #6 could keep those settings though.
- 12758. By Andrew Johnson
-
Show UDP name server status in casr 2+ output
- 12759. By mdavidsaver
-
pcas: don't send beacons w/ connect()d socket
use sendto() and leave the origin field to 0.0.0.0
so it will be filled in by the receiving repeater
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Ok, I think this is fixed as well. PCAS was sending beacons from a connect()d UDP socket as RSRV was. Now changed to use sendto() and leave the origin interface field zero'd, as RSRV now does.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
CAS beacon issue fixed, will merge after Ralph's approval.
- 12760. By Ralph Lange
-
pcas: fix compilation on MSC Windows
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
On Windows, I am not getting any of the thread's messages, type
CAS-TCP server on 10.5.1.1:5064 with
CAS-UDP unicast name server on 10.5.1.1:5064
CAS-UDP broadcast name server on 10.5.1.255:5064
Have these messages been removed again?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
More testing:
cygwin does show the messages.
MSVC 12.0 (both 64 and 32 bit) and MinGW32 do not.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
Rough test for the PCAS changes
On 64bit Linux:
The CA Gateway (trunk) compiles, the (very few) unit tests succeed.
However, beacons and reconnection behavior are not tested by these tests yet.
- 12761. By Andrew Johnson
-
Report UDP client status on Windows
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Ah yes, the code for casr() does use ifdef _WIN32 and doesn't call log_one_client() from that section of code. I just committed a fix.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
Sorry if I wasn't clear enough.
The Windows builds show *no* thread related messages, none at all.
[...]
iocRun: All initialization complete
epics> casr 1
Channel Access Server V4.13
No clients connected.
Sending CAS-beacons to 2 addresses:
172.
192.
epics> casr 2
Channel Access Server V4.13
No clients connected.
Sending CAS-beacons to 2 addresses:
172.
192.
epics> casr 3
Channel Access Server V4.13
No clients connected.
Sending CAS-beacons to 2 addresses:
172.
192.
epics>
- 12762. By Ralph Lange
-
rsrv: populate the server list - also on Windows builds
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
Bummer: the server list was empty (not being populated) on Windows.
I just committed a fix.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
I did a complete test on my windows box, report is as follows.
The cygwin target needs fixing. I'm not sure what's happening there.
Please also add tests on the behavior when another IOC is already running.
It is not covered by the test plan, but I have seen IOCs hanging or exiting.
These tests are pretty tedious. Excellent candidate for automation...
---- snip ----
Test Report rsrvbindiface on Windows 7
Test Plan https:/
Version 2016-02-16T14:44
Tested 2016-02-25T09:00 by Ralph
Version lp:~epics-core/epics-base/rsrvbindiface revision 12762
Targets MSVC 12.0 (amd64), MSVC (x86), Cygwin (x86_64), MinGW32 (x86)
Machine Latitude E7240 (intel i3) running Windows 7
Test #1 Defaults
client get pass pass pass pass
epicsParamShow pass pass pass pass
casr 1 pass pass pass pass
dbcar "" 8 pass pass pass pass
Note on Cygwin:
- warning at boot time
Warning: Duplicate EPICS CA Address list entry "169.254.
- casr and dbcar (UDP search destination) show this interface address (link-local)
in addition to the two regular interfaces
Test #2 Client address list only
client get pass pass pass pass
epicsParamShow pass pass pass pass
casr 1 pass pass pass pass
dbcar "" 8 pass pass pass pass
Note on Cygwin:
- warning at boot time
Warning: Duplicate EPICS CA Address list entry "169.254.
- casr shows this interface address in addition to the two regular interfaces
Test #3 Client and Server on a single interface
client get pass pass FAIL pass
epicsParamShow pass pass FAIL pass
casr 1 pass pass FAIL pass
dbcar "" 8 pass pass FAIL pass
Failure on Cygwin:
- error at boot time
CAS: UDP Socket bcast bind error: "Cannot assign requested address"
IOC hangs after that message
Test #4 Client and Server on multiple interfaces
client get pass pass FAIL pass
epicsParamShow pass pass FAIL pass
casr 1 pass pass FAIL pass
dbcar "" 8 pass pass FAIL pass
Failure on Cygwin:
- error at boot time
CAS: UDP Socket bcast bind error: "Cannot assign requested address"
IOC hangs ...
- 12763. By mdavidsaver
-
win32: include ws2tcpip.h from osdSock.h
Needed to get some additional definitions
including IP_ADD_MEMBERSHIP - 12764. By mdavidsaver
-
cygwin inherits winsock broadcast behavior
- 12765. By mdavidsaver
-
rsrv: use SOCKERRNO
Must use OSI SOCKERRNO for correct handling
of errors w/ winsock
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> Please also add tests on the behavior when another IOC is already running.
Good point. Provisionally I think the instruction would be to repeat all tests with a second IOC running w/ default config. Just fixed an mistake here were I used 'errno' instead of 'SOCKERRNO'.
> CAS: UDP Socket bcast bind error: "Cannot assign requested address"
This is a failure to bind a UDP socket to an interface broadcast address. So it seems likely that cygwin is (unavoidably) letting the winsock behavior show through. In caservertask.c, I'vee replaced the three '!defined(_WIN32)' with '!(defined(_WIN32) || defined(
> IPv4 Multicast name lookup not supported by this target
The direct cause is that the macro IP_ADD_MEMBERSHIP is not defined in caservertask.c, which is the test I picked for OS support of multicast. I've added an include of "ws2tcpip.h" to WIN32/osdSock.h, which I think is reasonable.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> These tests are pretty tedious. Excellent candidate for automation...
Agreed, just not sure how given the requirement for superuser, and the OS differences in network configuration. How can the effect of linux tap interfaces be achieved on windows/macos? What sort of virtual NIC should be used?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Norum (wenorum) wrote : | # |
Tuntap is available as an add-on for OS X — I use it with a Verilog simulator to test the ethernet-
> On Feb 25, 2016, at 8:42 AM, mdavidsaver <email address hidden> wrote:
>
> How can the effect of linux tap interfaces be achieved on windows/macos?
--
Eric Norum
<email address hidden>
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
I was doing manual testing here using a combination of localhost and my workstation's primary IP address (i.e. `hostname`); would using just those two be sufficient for automated testing? That would avoid the need for running as root, and I suspect might work on all OSs.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
Testing using a VM is fine, and interfaces are a dime a dozen on those.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Ok, but requiring that does preclude automated testing on Jenkins (the APS one at least).
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> would using just those two be sufficient for automated testing?
The test process as currently written wants two interfaces which would be found with EPICS_CA_
> at would avoid the need for running as root
On reflection I was making an implicit assumption that the test code would have to change the network configuration, which isn't strictly required. Rather it could inspect, and SKIP if the host doesn't meet some requirements.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Are you working on some automated tests for this branch, or should I merge it?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
I have some ideas, but haven't started writing. Go ahead and merge.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
I did a partial test.
- The multicast issue seems to be fixed.
- Cygwin still fails miserably
Test results as follows
---- snip ----
Test Report rsrvbindiface on Windows 7 - ONLY PARTIAL TEST
Test Plan https:/
Version 2016-02-16T14:44
Tested 2016-02-26T20:00 by Ralph
Version lp:~epics-core/epics-base/rsrvbindiface revision 12765
Targets MSVC 12.0 (amd64), MSVC (x86), Cygwin (x86_64), MinGW32 (x86)
Machine Latitude E7240 (intel i3) running Windows 7
Test #1 Defaults
starting second IOC pass pass pass pass
client get pass pass pass pass
epicsParamShow pass pass pass pass
casr 1 pass pass pass pass
dbcar "" 8 pass pass pass pass
Note on Cygwin:
- warning at boot time
Warning: Duplicate EPICS CA Address list entry "169.254.
- casr and dbcar (UDP search destination) show this interface address (link-local)
in addition to the two regular interfaces
Test #2 Client address list only
starting second IOC pass pass pass pass
client get pass pass pass pass
epicsParamShow pass pass pass pass
casr 1 pass pass pass pass
dbcar "" 8 pass pass pass pass
Note on Cygwin:
- warning at boot time
Warning: Duplicate EPICS CA Address list entry "169.254.
- casr shows this interface address in addition to the two regular interfaces
Test #3 Client and Server on a single interface
starting second IOC pass pass FAIL pass
client get pass pass FAIL pass
epicsParamShow pass pass FAIL pass
casr 1 pass pass FAIL pass
dbcar "" 8 pass pass FAIL pass
Failure on Cygwin:
- error at boot time
[cas warnings in case of second IOC]
CAS: UDP Socket bcast bind error: "Cannot assign requested address"
IOC hangs after that message
Test #4 Client and Server on multiple interfaces
starting second IOC skip skip FAIL skip
client get skip skip FAIL skip
epicsParamShow skip skip FAIL skip
casr 1 skip skip FAIL skip
dbcar "" 8 skip skip FAIL skip
Failure on Cygwin:
-...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ralph Lange (ralph-lange) wrote : | # |
Re: Automation
I would not test this as part of a unit test, but move it into a separate job.
In that case it can be executed on a selected (group of) builder(s), which can easily be configured to be the VM kind with two interfaces.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
> #if !(defined(_WIN32) || defined(
So clearly __CYGWIN32__ is not the right macro to test. Can you try some others (maybe __CYGWIN__) and/or send me the output of:
> touch empty.c
> cpp -dM empty.c
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
> So clearly __CYGWIN32__ is not the right macro to test.
We define our own flags for most architectures, please look for and use those instead of trying to guess what the compiler might define:
tux% cd configure/os
tux% grep OP_SYS_CPPFLAGS *
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
CONFIG.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
I'm not guessing Andrew, I copied shareLib.h. Should I change this to 'CYGWIN32' as well?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
There is also https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
This might explain some strange Cygwin DLL build issues in the past.
I am changing all the Cygwin macro tests to use __CYGWIN__, and will add a comment deprecating our CYGWIN32 macro.
Ah, if I run "cpp -dM -m32 empty.c" it defines __CYGWIN32__ as well as __CYGWIN__ so they evidently removed that when they added 64-bit support. There is no __CYGWIN64__ macro.
Preview Diff
1 | === modified file 'documentation/RELEASE_NOTES.html' |
2 | --- documentation/RELEASE_NOTES.html 2016-02-23 21:43:26 +0000 |
3 | +++ documentation/RELEASE_NOTES.html 2016-02-25 16:34:00 +0000 |
4 | @@ -43,6 +43,35 @@ |
5 | |
6 | <h2 align="center">Changes between 3.15.2 and 3.15.3</h2> |
7 | |
8 | +<h3>CA server configuration changes</h3> |
9 | + |
10 | +<p>RSRV now honors EPICS_CAS_INTF_ADDR_LIST and binds to only |
11 | +the provided list of network interfaces. |
12 | +Name searches (UDP and TCP) on other network interfaces are ignored. |
13 | +For example on a computer with interfaces 10.5.1.1/24, 10.5.2.1/24, and 10.5.3.1/24, |
14 | +setting "EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'" will accept traffic |
15 | +on the .1.1 and .2.1, but ignore from .3.1</p> |
16 | + |
17 | +<p>RSRV now honors EPICS_CAS_IGNORE_ADDR_LIST and ignores |
18 | +UDP messages received from addresses in this list.</p> |
19 | + |
20 | +<p>Previously, CA servers (RSRV and PCAS) would build the beacon address list |
21 | +using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set. |
22 | +This is no longer done. |
23 | +Sites depending on this should set both envronment variables to the same value.</p> |
24 | + |
25 | +<h3>IPv4 multicast for name search and beacons</h3> |
26 | + |
27 | +<p>libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name search and beacons). |
28 | +This is disabled by default. |
29 | +To enable multicast address(s) must be listed in EPICS_CA_ADDR_LIST for clients |
30 | +and EPICS_CAS_INTF_ADDR_LIST for servers (IOCs should set both). |
31 | +For example: "EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9". |
32 | +</p> |
33 | + |
34 | +<p>Please note that no IPv4 multicast address is officially assigned for Channel Access by IANA. |
35 | +The example 224.0.2.9 is taken from the AD-HOC Block I range.<p> |
36 | + |
37 | <h3>Make the NTP Time provider optional on VxWorks</h3> |
38 | |
39 | <p>Recent versions of VxWorks (sometime after VxWorks 6) provide facilities for |
40 | |
41 | === modified file 'src/ca/client/CAref.html' |
42 | --- src/ca/client/CAref.html 2015-07-13 18:05:33 +0000 |
43 | +++ src/ca/client/CAref.html 2016-02-25 16:34:00 +0000 |
44 | @@ -841,23 +841,18 @@ |
45 | Interval</a>.</p> |
46 | |
47 | <p>CA servers build a list of addresses to send beacons to during |
48 | -initialization. If EPICS_CAS_AUTO_BEACON_ADDR_LIST has the value "YES" then the |
49 | -beacon address list will be automatically configured to contain the broadcast |
50 | -addresses of all LAN interfaces found in the host and the destination address |
51 | -of all point-to-point interfaces found in the host. However, if the user also |
52 | +initialization. If EPICS_CAS_AUTO_BEACON_ADDR_LIST has the value "YES" |
53 | +(the default) this list will be automatically populated with the broadcast |
54 | +addresses of all network interfaces. However, if the user also |
55 | defines EPICS_CAS_INTF_ADDR_LIST then beacon address list automatic |
56 | configuration is constrained to the network interfaces specified therein, and |
57 | -therefore only the broadcast addresses of the specified LAN interfaces, and the |
58 | -destination addresses of all specified point-to-point links, will be |
59 | +therefore only the broadcast addresses of the specified LAN interfaces, will be |
60 | automatically configured.</p> |
61 | |
62 | <p>If EPICS_CAS_BEACON_ADDR_LIST is defined then its contents will be used to |
63 | augment any automatic configuration of the beacon address list. Individual |
64 | entries in EPICS_CAS_BEACON_ADDR_LIST may override the destination port number |
65 | -if ":nnn" follows the host name or IP address there. Alternatively, when both |
66 | -EPICS_CAS_BEACON_ADDR_LIST and EPICS_CAS_INTF_ADDR_LIST are not defined then |
67 | -the contents of EPICS_CA_ADDR_LIST is used to augment the list. Otherwise, the |
68 | -list is not augmented.</p> |
69 | +if ":nnn" follows the host name or IP address there.</p> |
70 | |
71 | <p>The EPICS_CAS_BEACON_PORT parameter specifies the destination port for |
72 | server beacons. The only exception to this occurs when ports are specified in |
73 | @@ -868,20 +863,18 @@ |
74 | <h4>Binding a Server to a Limited Set of Network Interfaces</h4> |
75 | |
76 | <p>The parameter EPICS_CAS_INTF_ADDR_LIST allows a ca server to bind itself to, |
77 | -and therefore accept messages only over, a limited set of the local host's |
78 | +and therefore accept messages received by, a limited set of the local host's |
79 | network interfaces (each specified by its IP address). On UNIX systems type |
80 | -"netstat -i" (type "ipconfig" on windows) to see a list of the local host's |
81 | -network interfaces. Specifically, UDP search messages addressed to both the IP |
82 | -addresses in EPICS_CAS_INTF_ADDR_LIST and also to the broadcast addresses of |
83 | -the corresponding LAN interfaces will be accepted by the server. By default, |
84 | +"netstat -ie" (type "ipconfig" on windows) to see a list of the local host's |
85 | +network interfaces. By default, |
86 | the CA server is accessible from all network interfaces configured into its |
87 | host.</p> |
88 | |
89 | -<p>In R3.14 and previous releases the CA server employed by iocCore did not |
90 | -implement the EPICS_CAS_INTF_ADDR_LIST feature. In this release the iocCore |
91 | -server will read the first IP address from the parameter variable and use that |
92 | -to select which interface to bind to. Any additional IP addresses will be |
93 | -ignored and a warning message displayed during IOC initialization.</p> |
94 | +<p>Until R3.15.4 the CA server employed by iocCore did not |
95 | +implement the EPICS_CAS_INTF_ADDR_LIST feature.</p> |
96 | + |
97 | +<p>Prior to R3.15.4 CA servers would build the beacon address list |
98 | +using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set.</p> |
99 | |
100 | <h4>Ignoring Process Variable Name Resolution Requests From Certain Hosts</h4> |
101 | |
102 | |
103 | === modified file 'src/ca/client/addrList.h' |
104 | --- src/ca/client/addrList.h 2008-09-19 23:27:52 +0000 |
105 | +++ src/ca/client/addrList.h 2016-02-25 16:34:00 +0000 |
106 | @@ -22,7 +22,7 @@ |
107 | epicsShareFunc void epicsShareAPI configureChannelAccessAddressList |
108 | ( struct ELLLIST *pList, SOCKET sock, unsigned short port ); |
109 | |
110 | -epicsShareFunc void epicsShareAPI addAddrToChannelAccessAddressList |
111 | +epicsShareFunc int epicsShareAPI addAddrToChannelAccessAddressList |
112 | ( struct ELLLIST *pList, const ENV_PARAM *pEnv, |
113 | unsigned short port, int ignoreNonDefaultPort ); |
114 | |
115 | |
116 | === modified file 'src/ca/client/iocinf.cpp' |
117 | --- src/ca/client/iocinf.cpp 2013-12-17 18:54:04 +0000 |
118 | +++ src/ca/client/iocinf.cpp 2016-02-25 16:34:00 +0000 |
119 | @@ -73,7 +73,7 @@ |
120 | /* |
121 | * addAddrToChannelAccessAddressList () |
122 | */ |
123 | -extern "C" void epicsShareAPI addAddrToChannelAccessAddressList |
124 | +extern "C" int epicsShareAPI addAddrToChannelAccessAddressList |
125 | ( ELLLIST *pList, const ENV_PARAM *pEnv, |
126 | unsigned short port, int ignoreNonDefaultPort ) |
127 | { |
128 | @@ -82,11 +82,11 @@ |
129 | const char *pToken; |
130 | struct sockaddr_in addr; |
131 | char buf[32u]; /* large enough to hold an IP address */ |
132 | - int status; |
133 | + int status, ret = -1; |
134 | |
135 | pStr = envGetConfigParamPtr (pEnv); |
136 | if (!pStr) { |
137 | - return; |
138 | + return ret; |
139 | } |
140 | |
141 | while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) { |
142 | @@ -104,7 +104,7 @@ |
143 | pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode)); |
144 | if (pNewNode==NULL) { |
145 | fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n"); |
146 | - return; |
147 | + break; |
148 | } |
149 | |
150 | pNewNode->addr.ia = addr; |
151 | @@ -113,9 +113,10 @@ |
152 | * LOCK applied externally |
153 | */ |
154 | ellAdd (pList, &pNewNode->node); |
155 | + ret = 0; /* success if anything is added to the list */ |
156 | } |
157 | |
158 | - return; |
159 | + return ret; |
160 | } |
161 | |
162 | /* |
163 | |
164 | === modified file 'src/ca/client/udpiiu.cpp' |
165 | --- src/ca/client/udpiiu.cpp 2013-06-07 23:08:38 +0000 |
166 | +++ src/ca/client/udpiiu.cpp 2016-02-25 16:34:00 +0000 |
167 | @@ -163,6 +163,19 @@ |
168 | throwWithLocation ( noSocket () ); |
169 | } |
170 | |
171 | +#ifdef IP_ADD_MEMBERSHIP |
172 | + { |
173 | + int flag = 1; |
174 | + if ( setsockopt ( this->sock, IPPROTO_IP, IP_MULTICAST_LOOP, |
175 | + (char *) &flag, sizeof ( flag ) ) == -1 ) { |
176 | + char sockErrBuf[64]; |
177 | + epicsSocketConvertErrnoToString ( |
178 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
179 | + errlogPrintf("CAC: failed to set mcast loopback\n"); |
180 | + } |
181 | + } |
182 | +#endif |
183 | + |
184 | int boolValue = true; |
185 | int status = setsockopt ( this->sock, SOL_SOCKET, SO_BROADCAST, |
186 | (char *) &boolValue, sizeof ( boolValue ) ); |
187 | |
188 | === modified file 'src/ca/legacy/pcas/generic/caServerI.cc' |
189 | --- src/ca/legacy/pcas/generic/caServerI.cc 2012-11-30 23:42:47 +0000 |
190 | +++ src/ca/legacy/pcas/generic/caServerI.cc 2016-02-25 16:34:00 +0000 |
191 | @@ -141,6 +141,39 @@ |
192 | return S_cas_success; |
193 | } |
194 | |
195 | +void caServerI::addMCast(const osiSockAddr& addr) |
196 | +{ |
197 | +#ifdef IP_ADD_MEMBERSHIP |
198 | + epicsGuard < epicsMutex > locker ( this->mutex ); |
199 | + tsDLIter < casIntfOS > iter = this->intfList.firstIter (); |
200 | + while ( iter.valid () ) { |
201 | + struct ip_mreq mreq; |
202 | + |
203 | + memset(&mreq, 0, sizeof(mreq)); |
204 | + mreq.imr_interface = iter->serverAddress().getSockIP().sin_addr; |
205 | + mreq.imr_multiaddr = addr.ia.sin_addr; |
206 | + |
207 | + if ( setsockopt ( iter->casDGIntfIO::getFD (), IPPROTO_IP, |
208 | + IP_ADD_MEMBERSHIP, (char *) &mreq, |
209 | + sizeof ( mreq ) ) < 0) { |
210 | + struct sockaddr_in temp; |
211 | + char name[40]; |
212 | + char sockErrBuf[64]; |
213 | + temp.sin_family = AF_INET; |
214 | + temp.sin_addr = mreq.imr_multiaddr; |
215 | + temp.sin_port = addr.ia.sin_port; |
216 | + epicsSocketConvertErrnoToString ( |
217 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
218 | + ipAddrToDottedIP (&temp, name, sizeof(name)); |
219 | + fprintf(stderr, "CAS: Socket mcast join %s failed with \"%s\"\n", |
220 | + name, sockErrBuf ); |
221 | + } |
222 | + |
223 | + iter++; |
224 | + } |
225 | +#endif |
226 | +} |
227 | + |
228 | void caServerI::sendBeacon ( ca_uint32_t beaconNo ) |
229 | { |
230 | epicsGuard < epicsMutex > locker ( this->mutex ); |
231 | |
232 | === modified file 'src/ca/legacy/pcas/generic/caServerI.h' |
233 | --- src/ca/legacy/pcas/generic/caServerI.h 2012-11-30 23:42:47 +0000 |
234 | +++ src/ca/legacy/pcas/generic/caServerI.h 2016-02-25 16:34:00 +0000 |
235 | @@ -103,6 +103,8 @@ |
236 | caStatus attachInterface ( const caNetAddr & addr, bool autoBeaconAddr, |
237 | bool addConfigAddr ); |
238 | |
239 | + virtual void addMCast(const osiSockAddr&); |
240 | + |
241 | void sendBeacon ( ca_uint32_t beaconNo ); |
242 | |
243 | caServerI ( const caServerI & ); |
244 | |
245 | === modified file 'src/ca/legacy/pcas/io/bsdSocket/caServerIO.cc' |
246 | --- src/ca/legacy/pcas/io/bsdSocket/caServerIO.cc 2012-04-12 16:13:50 +0000 |
247 | +++ src/ca/legacy/pcas/io/bsdSocket/caServerIO.cc 2016-02-25 16:34:00 +0000 |
248 | @@ -14,6 +14,7 @@ |
249 | // |
250 | |
251 | #include <ctype.h> |
252 | +#include <list> |
253 | |
254 | #include "epicsSignal.h" |
255 | #include "envDefs.h" |
256 | @@ -92,6 +93,9 @@ |
257 | autoBeaconAddr = true; |
258 | } |
259 | |
260 | + typedef std::list<osiSockAddr> mcastAddrs_t; |
261 | + mcastAddrs_t mcastAddrs; |
262 | + |
263 | // |
264 | // bind to the the interfaces specified - otherwise wildcard |
265 | // with INADDR_ANY and allow clients to attach from any interface |
266 | @@ -114,6 +118,15 @@ |
267 | pToken); |
268 | continue; |
269 | } |
270 | + |
271 | + epicsUInt32 top = ntohl(saddr.sin_addr.s_addr)>>24; |
272 | + if (saddr.sin_family==AF_INET && top>=224 && top<=239) { |
273 | + osiSockAddr oaddr; |
274 | + oaddr.ia = saddr; |
275 | + mcastAddrs.push_back(oaddr); |
276 | + continue; |
277 | + } |
278 | + |
279 | stat = this->attachInterface (caNetAddr(saddr), autoBeaconAddr, configAddrOnceFlag); |
280 | if (stat) { |
281 | errMessage(stat, "unable to attach explicit interface"); |
282 | @@ -131,6 +144,10 @@ |
283 | errMessage(stat, "unable to attach any interface"); |
284 | } |
285 | } |
286 | + |
287 | + for (mcastAddrs_t::const_iterator it = mcastAddrs.begin(); it!=mcastAddrs.end(); ++it) { |
288 | + this->addMCast(*it); |
289 | + } |
290 | } |
291 | |
292 | // |
293 | |
294 | === modified file 'src/ca/legacy/pcas/io/bsdSocket/caServerIO.h' |
295 | --- src/ca/legacy/pcas/io/bsdSocket/caServerIO.h 2010-10-05 19:27:37 +0000 |
296 | +++ src/ca/legacy/pcas/io/bsdSocket/caServerIO.h 2016-02-25 16:34:00 +0000 |
297 | @@ -47,6 +47,8 @@ |
298 | virtual caStatus attachInterface ( |
299 | const caNetAddr & addr, bool autoBeaconAddr, |
300 | bool addConfigAddr ) = 0; |
301 | + |
302 | + virtual void addMCast(const osiSockAddr&) = 0; |
303 | }; |
304 | |
305 | #endif // caServerIOh |
306 | |
307 | === modified file 'src/ca/legacy/pcas/io/bsdSocket/casDGIntfIO.cc' |
308 | --- src/ca/legacy/pcas/io/bsdSocket/casDGIntfIO.cc 2014-02-16 18:29:58 +0000 |
309 | +++ src/ca/legacy/pcas/io/bsdSocket/casDGIntfIO.cc 2016-02-25 16:34:00 +0000 |
310 | @@ -19,6 +19,11 @@ |
311 | #include "addrList.h" |
312 | #include "errlog.h" |
313 | |
314 | +#if defined(_MSC_VER) |
315 | +# include <BaseTsd.h> |
316 | + typedef SSIZE_T ssize_t; |
317 | +#endif |
318 | + |
319 | #define epicsExportSharedSymbols |
320 | #include "casDGIntfIO.h" |
321 | #include "ipIgnoreEntry.h" |
322 | @@ -148,26 +153,8 @@ |
323 | } |
324 | |
325 | if ( addConfigBeaconAddr ) { |
326 | - |
327 | - // |
328 | - // by default use EPICS_CA_ADDR_LIST for the |
329 | - // beacon address list |
330 | - // |
331 | - const ENV_PARAM *pParam; |
332 | - |
333 | - if ( envGetConfigParamPtr ( & EPICS_CAS_INTF_ADDR_LIST ) || |
334 | - envGetConfigParamPtr ( & EPICS_CAS_BEACON_ADDR_LIST ) ) { |
335 | - pParam = & EPICS_CAS_BEACON_ADDR_LIST; |
336 | - } |
337 | - else { |
338 | - pParam = & EPICS_CA_ADDR_LIST; |
339 | - } |
340 | - |
341 | - // |
342 | - // add in the configured addresses |
343 | - // |
344 | addAddrToChannelAccessAddressList ( |
345 | - & BCastAddrList, pParam, beaconPort, pParam == & EPICS_CA_ADDR_LIST ); |
346 | + & BCastAddrList, &EPICS_CAS_BEACON_ADDR_LIST, beaconPort, 0 ); |
347 | } |
348 | |
349 | removeDuplicateAddresses ( & this->beaconAddrList, & BCastAddrList, 0 ); |
350 | @@ -267,7 +254,7 @@ |
351 | |
352 | // avoid use of ellFree because problems on windows occur if the |
353 | // free is in a different DLL than the malloc |
354 | - ELLNODE * nnode = this->beaconAddrList.node.next; |
355 | + ELLNODE * nnode = ellFirst(&this->beaconAddrList); |
356 | while ( nnode ) |
357 | { |
358 | ELLNODE * pnode = nnode; |
359 | @@ -418,52 +405,24 @@ |
360 | } |
361 | |
362 | void casDGIntfIO::sendBeaconIO ( char & msg, unsigned length, |
363 | - aitUint16 & portField, aitUint32 & addrField ) |
364 | + aitUint16 & portField, aitUint32 & ) |
365 | { |
366 | caNetAddr addr = this->serverAddress (); |
367 | struct sockaddr_in inetAddr = addr.getSockIP(); |
368 | - osiSockAddrNode *pAddr; |
369 | - int status; |
370 | - char buf[64]; |
371 | |
372 | portField = inetAddr.sin_port; // the TCP port |
373 | |
374 | - for (pAddr = reinterpret_cast <osiSockAddrNode *> ( ellFirst ( & this->beaconAddrList ) ); |
375 | - pAddr; pAddr = reinterpret_cast <osiSockAddrNode *> ( ellNext ( & pAddr->node ) ) ) { |
376 | - status = connect ( this->beaconSock, &pAddr->addr.sa, sizeof ( pAddr->addr.sa ) ); |
377 | - if (status<0) { |
378 | - char sockErrBuf[64]; |
379 | + for (ELLNODE *pNode = ellFirst(&this->beaconAddrList); pNode; pNode = ellNext(pNode)) |
380 | + { |
381 | + osiSockAddrNode *pAddr = reinterpret_cast<osiSockAddrNode *>(pNode); |
382 | + |
383 | + ssize_t status = sendto(this->beaconSock, &msg, length, 0, &pAddr->addr.sa, sizeof(pAddr->addr.ia)); |
384 | + if ( status != length ) { |
385 | + char sockErrBuf[64], buf[64]; |
386 | epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); |
387 | - ipAddrToDottedIP ( & pAddr->addr.ia, buf, sizeof ( buf ) ); |
388 | - errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n", |
389 | - __FILE__, buf, sockErrBuf ); |
390 | - } |
391 | - else { |
392 | - osiSockAddr sockAddr; |
393 | - osiSocklen_t size = ( osiSocklen_t ) sizeof ( sockAddr.sa ); |
394 | - status = getsockname ( this->beaconSock, &sockAddr.sa, &size ); |
395 | - if ( status < 0 ) { |
396 | - char sockErrBuf[64]; |
397 | - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); |
398 | - errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n", |
399 | - __FILE__, sockErrBuf ); |
400 | - } |
401 | - else if ( sockAddr.sa.sa_family == AF_INET ) { |
402 | - addrField = sockAddr.ia.sin_addr.s_addr; |
403 | - |
404 | - status = send ( this->beaconSock, &msg, length, 0 ); |
405 | - if ( status < 0 ) { |
406 | - char sockErrBuf[64]; |
407 | - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); |
408 | - ipAddrToA ( &pAddr->addr.ia, buf, sizeof(buf) ); |
409 | - errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n", |
410 | - __FILE__, buf, sockErrBuf ); |
411 | - } |
412 | - else { |
413 | - unsigned statusAsLength = static_cast < unsigned > ( status ); |
414 | - assert ( statusAsLength == length ); |
415 | - } |
416 | - } |
417 | + ipAddrToA ( &pAddr->addr.ia, buf, sizeof(buf) ); |
418 | + errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\" (%u)\n", |
419 | + __FILE__, buf, sockErrBuf, (unsigned)status ); |
420 | } |
421 | } |
422 | } |
423 | |
424 | === modified file 'src/ioc/db/dbChannel.c' |
425 | --- src/ioc/db/dbChannel.c 2015-03-18 21:48:07 +0000 |
426 | +++ src/ioc/db/dbChannel.c 2016-02-25 16:34:00 +0000 |
427 | @@ -704,21 +704,27 @@ |
428 | int pre = ellCount(&chan->pre_chain); |
429 | int post = ellCount(&chan->post_chain); |
430 | |
431 | - printf("%*schannel name: %s\n", indent, "", chan->name); |
432 | - printf("%*s field_type=%s (%d bytes), dbr_type=%s, %ld element%s, %d filter%s", indent, "", |
433 | - dbGetFieldTypeString(chan->addr.field_type), chan->addr.field_size, |
434 | - dbGetFieldTypeString(chan->addr.dbr_field_type), elems, elems == 1 ? "" : "s", |
435 | - count, count == 1 ? "" : "s"); |
436 | - if (count) |
437 | - printf(" (%d pre eventq, %d post eventq)\n", pre, post); |
438 | - else |
439 | - printf("\n"); |
440 | - if (level > 0) |
441 | - dbChannelFilterShow(chan, level - 1, indent + 2); |
442 | - if (count) { |
443 | - printf("%*s final field_type=%s (%dB), %ld element%s\n", indent, "", |
444 | - dbGetFieldTypeString(chan->final_type), chan->final_field_size, |
445 | - felems, felems == 1 ? "" : "s"); |
446 | + printf("%*sChannel: '%s'\n", indent, "", chan->name); |
447 | + if (level > 0) { |
448 | + printf("%*sfield_type=%s (%d bytes), dbr_type=%s, %ld element%s", |
449 | + indent + 4, "", |
450 | + dbGetFieldTypeString(chan->addr.field_type), |
451 | + chan->addr.field_size, |
452 | + dbGetFieldTypeString(chan->addr.dbr_field_type), |
453 | + elems, elems == 1 ? "" : "s"); |
454 | + if (count) |
455 | + printf("\n%*s%d filter%s (%d pre eventq, %d post eventq)\n", |
456 | + indent + 4, "", count, count == 1 ? "" : "s", pre, post); |
457 | + else |
458 | + printf(", no filters\n"); |
459 | + if (level > 1) |
460 | + dbChannelFilterShow(chan, level - 2, indent + 8); |
461 | + if (count) { |
462 | + printf("%*sfinal field_type=%s (%dB), %ld element%s\n", indent + 4, "", |
463 | + dbGetFieldTypeString(chan->final_type), |
464 | + chan->final_field_size, |
465 | + felems, felems == 1 ? "" : "s"); |
466 | + } |
467 | } |
468 | } |
469 | |
470 | |
471 | === modified file 'src/ioc/rsrv/camessage.c' |
472 | --- src/ioc/rsrv/camessage.c 2015-04-22 21:51:31 +0000 |
473 | +++ src/ioc/rsrv/camessage.c 2016-02-25 16:34:00 +0000 |
474 | @@ -1126,7 +1126,7 @@ |
475 | pclient = pciu->client; |
476 | assert(pclient); |
477 | |
478 | - if(pclient == prsrv_cast_client){ |
479 | + if(pclient->proto==IPPROTO_UDP){ |
480 | return; |
481 | } |
482 | |
483 | @@ -1193,7 +1193,7 @@ |
484 | int v41; |
485 | int status; |
486 | |
487 | - assert ( pciu->client != prsrv_cast_client ); |
488 | + assert ( pciu->client->proto!=IPPROTO_UDP ); |
489 | |
490 | /* |
491 | * noop if this is an old client |
492 | @@ -1321,7 +1321,7 @@ |
493 | } |
494 | } |
495 | else { |
496 | - epicsMutexMustLock(prsrv_cast_client->chanListLock); |
497 | + epicsMutexMustLock(client->chanListLock); |
498 | /* |
499 | * clients which dont claim their |
500 | * channel in use block prior to |
501 | @@ -1331,7 +1331,7 @@ |
502 | if(!pciu){ |
503 | errlogPrintf("CAS: client timeout disconnect id=%d\n", |
504 | mp->m_cid); |
505 | - epicsMutexUnlock(prsrv_cast_client->chanListLock); |
506 | + epicsMutexUnlock(client->chanListLock); |
507 | SEND_LOCK(client); |
508 | send_err( |
509 | mp, |
510 | @@ -1343,33 +1343,15 @@ |
511 | } |
512 | |
513 | /* |
514 | - * duplicate claim message are unacceptable |
515 | - * (so we disconnect the client) |
516 | - */ |
517 | - if (pciu->client!=prsrv_cast_client) { |
518 | - errlogPrintf("CAS: duplicate claim disconnect id=%d\n", |
519 | - mp->m_cid); |
520 | - epicsMutexUnlock(prsrv_cast_client->chanListLock); |
521 | - SEND_LOCK(client); |
522 | - send_err( |
523 | - mp, |
524 | - ECA_INTERNAL, |
525 | - client, |
526 | - "duplicate claim in old connect protocol"); |
527 | - SEND_UNLOCK(client); |
528 | - return RSRV_ERROR; |
529 | - } |
530 | - |
531 | - /* |
532 | * remove channel in use block from |
533 | * the UDP client where it could time |
534 | * out and place it on the client |
535 | * who is claiming it |
536 | */ |
537 | ellDelete( |
538 | - &prsrv_cast_client->chanList, |
539 | + &client->chanList, |
540 | &pciu->node); |
541 | - epicsMutexUnlock(prsrv_cast_client->chanListLock); |
542 | + epicsMutexUnlock(client->chanListLock); |
543 | |
544 | epicsMutexMustLock(client->chanListLock); |
545 | pciu->state = rsrvCS_pendConnectResp; |
546 | @@ -2515,12 +2497,7 @@ |
547 | unsigned bytes_left; |
548 | int status = RSRV_ERROR; |
549 | |
550 | - if ( ! pCaBucket ) { |
551 | - pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE); |
552 | - if(!pCaBucket){ |
553 | - return RSRV_ERROR; |
554 | - } |
555 | - } |
556 | + assert(pCaBucket); |
557 | |
558 | /* drain remnents of large messages that will not fit */ |
559 | if ( client->recvBytesToDrain ) { |
560 | @@ -2623,7 +2600,7 @@ |
561 | if ( CASDEBUG > 2 ) |
562 | log_header (NULL, client, &msg, pBody, nmsg); |
563 | |
564 | - if ( client == prsrv_cast_client ) { |
565 | + if ( client->proto==IPPROTO_UDP ) { |
566 | if ( msg.m_cmmd < NELEMENTS ( udpJumpTable ) ) { |
567 | status = ( *udpJumpTable[msg.m_cmmd] )( &msg, pBody, client ); |
568 | if (status!=RSRV_OK) { |
569 | |
570 | === modified file 'src/ioc/rsrv/caserverio.c' |
571 | --- src/ioc/rsrv/caserverio.c 2015-02-28 00:11:37 +0000 |
572 | +++ src/ioc/rsrv/caserverio.c 2016-02-25 16:34:00 +0000 |
573 | @@ -222,7 +222,7 @@ |
574 | /* |
575 | * add placeholder for the first version message should it be needed |
576 | */ |
577 | - rsrv_version_reply ( prsrv_cast_client ); |
578 | + rsrv_version_reply ( pclient ); |
579 | |
580 | SEND_UNLOCK(pclient); |
581 | |
582 | |
583 | === modified file 'src/ioc/rsrv/caservertask.c' |
584 | --- src/ioc/rsrv/caservertask.c 2015-02-28 00:11:37 +0000 |
585 | +++ src/ioc/rsrv/caservertask.c 2016-02-25 16:34:00 +0000 |
586 | @@ -1,4 +1,7 @@ |
587 | /*************************************************************************\ |
588 | +* Copyright (c) 2016 Michael Davidsaver |
589 | +* Copyright (c) 2015 Brookhaven Science Assoc. as operator of Brookhaven |
590 | +* National Laboratory. |
591 | * Copyright (c) 2002 The University of Chicago, as Operator of Argonne |
592 | * National Laboratory. |
593 | * Copyright (c) 2002 The Regents of the University of California, as |
594 | @@ -32,6 +35,7 @@ |
595 | #include "osiPoolStatus.h" |
596 | #include "osiSock.h" |
597 | #include "taskwd.h" |
598 | +#include "cantProceed.h" |
599 | |
600 | #define epicsExportSharedSymbols |
601 | #include "dbChannel.h" |
602 | @@ -58,113 +62,12 @@ |
603 | */ |
604 | static void req_server (void *pParm) |
605 | { |
606 | - unsigned priorityOfSelf = epicsThreadGetPrioritySelf (); |
607 | - unsigned priorityOfBeacons; |
608 | - epicsThreadBooleanStatus tbs; |
609 | - osiSockAddrNode *pNode; |
610 | - struct sockaddr_in serverAddr; /* server's address */ |
611 | - osiSocklen_t addrSize = (osiSocklen_t) sizeof(struct sockaddr_in); |
612 | - int status; |
613 | - SOCKET clientSock; |
614 | - epicsThreadId tid; |
615 | - int portChange; |
616 | - |
617 | - epicsSignalInstallSigPipeIgnore (); |
618 | + rsrv_iface_config *conf = pParm; |
619 | + SOCKET IOC_sock; |
620 | |
621 | taskwdInsert ( epicsThreadGetIdSelf (), NULL, NULL ); |
622 | |
623 | - rsrvCurrentClient = epicsThreadPrivateCreate (); |
624 | - |
625 | - if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) { |
626 | - ca_server_port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT, |
627 | - (unsigned short) CA_SERVER_PORT ); |
628 | - } |
629 | - else { |
630 | - ca_server_port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, |
631 | - (unsigned short) CA_SERVER_PORT ); |
632 | - } |
633 | - |
634 | - addAddrToChannelAccessAddressList ( &casIntfAddrList, |
635 | - &EPICS_CAS_INTF_ADDR_LIST, ca_server_port, 0 ); |
636 | - if (ellCount(&casIntfAddrList) == 0) { |
637 | - pNode = (osiSockAddrNode *) calloc ( 1, sizeof(*pNode) ); |
638 | - pNode->addr.ia.sin_family = AF_INET; |
639 | - pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); |
640 | - pNode->addr.ia.sin_port = htons ( ca_server_port ); |
641 | - ellAdd ( &casIntfAddrList, &pNode->node ); |
642 | - } |
643 | - else { |
644 | - if (ellCount ( &casIntfAddrList ) > 1) |
645 | - epicsPrintf ("CAS: Multiple entries in EPICS_CAS_INTF_ADDR_LIST, " |
646 | - "only the first will be used.\n"); |
647 | - pNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList ); |
648 | - } |
649 | - |
650 | - memcpy ( &serverAddr, &pNode->addr.ia, addrSize ); |
651 | - |
652 | - if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) { |
653 | - epicsSocketDestroy ( IOC_sock ); |
654 | - } |
655 | - |
656 | - /* |
657 | - * Open the socket. Use ARPA Internet address format and stream |
658 | - * sockets. Format described in <sys/socket.h>. |
659 | - */ |
660 | - if ( ( IOC_sock = epicsSocketCreate (AF_INET, SOCK_STREAM, 0) ) == INVALID_SOCKET ) { |
661 | - errlogPrintf ("CAS: Socket creation error\n"); |
662 | - epicsThreadSuspendSelf (); |
663 | - } |
664 | - |
665 | - epicsSocketEnableAddressReuseDuringTimeWaitState ( IOC_sock ); |
666 | - |
667 | - /* get server's Internet address */ |
668 | - |
669 | - status = bind(IOC_sock, (struct sockaddr *) &serverAddr, addrSize); |
670 | - if ( status < 0 ) { |
671 | - if ( SOCKERRNO == SOCK_EADDRINUSE ) { |
672 | - /* |
673 | - * enable assignment of a default port |
674 | - * (so the getsockname() call below will |
675 | - * work correctly) |
676 | - */ |
677 | - serverAddr.sin_port = ntohs (0); |
678 | - status = bind(IOC_sock, (struct sockaddr *) &serverAddr, addrSize); |
679 | - } |
680 | - if ( status < 0 ) { |
681 | - char sockErrBuf[64]; |
682 | - epicsSocketConvertErrnoToString ( |
683 | - sockErrBuf, sizeof ( sockErrBuf ) ); |
684 | - errlogPrintf ( "CAS: Socket bind error was \"%s\"\n", |
685 | - sockErrBuf ); |
686 | - epicsThreadSuspendSelf (); |
687 | - } |
688 | - portChange = 1; |
689 | - } |
690 | - else { |
691 | - portChange = 0; |
692 | - } |
693 | - |
694 | - status = getsockname ( IOC_sock, |
695 | - (struct sockaddr *)&serverAddr, &addrSize); |
696 | - if ( status ) { |
697 | - char sockErrBuf[64]; |
698 | - epicsSocketConvertErrnoToString ( |
699 | - sockErrBuf, sizeof ( sockErrBuf ) ); |
700 | - errlogPrintf ( "CAS: getsockname() error %s\n", |
701 | - sockErrBuf ); |
702 | - epicsThreadSuspendSelf (); |
703 | - } |
704 | - |
705 | - ca_server_port = ntohs (serverAddr.sin_port); |
706 | - |
707 | - if ( portChange ) { |
708 | - errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n"); |
709 | - errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n", |
710 | - ca_server_port ); |
711 | - errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n"); |
712 | - errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" ); |
713 | - errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" ); |
714 | - } |
715 | + IOC_sock = conf->tcp; |
716 | |
717 | /* listen and accept new connections */ |
718 | if ( listen ( IOC_sock, 20 ) < 0 ) { |
719 | @@ -177,25 +80,10 @@ |
720 | epicsThreadSuspendSelf (); |
721 | } |
722 | |
723 | - tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfBeacons ); |
724 | - if ( tbs != epicsThreadBooleanStatusSuccess ) { |
725 | - priorityOfBeacons = priorityOfSelf; |
726 | - } |
727 | - |
728 | - beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty); |
729 | - beacon_ctl = ctlPause; |
730 | - |
731 | - tid = epicsThreadCreate ( "CAS-beacon", priorityOfBeacons, |
732 | - epicsThreadGetStackSize (epicsThreadStackSmall), |
733 | - rsrv_online_notify_task, 0 ); |
734 | - if ( tid == 0 ) { |
735 | - epicsPrintf ( "CAS: unable to start beacon thread\n" ); |
736 | - } |
737 | - |
738 | - epicsEventMustWait(beacon_startStopEvent); |
739 | epicsEventSignal(castcp_startStopEvent); |
740 | |
741 | while (TRUE) { |
742 | + SOCKET clientSock; |
743 | struct sockaddr sockAddr; |
744 | osiSocklen_t addLen = sizeof(sockAddr); |
745 | |
746 | @@ -244,6 +132,327 @@ |
747 | } |
748 | } |
749 | |
750 | +static |
751 | +int tryBind(SOCKET sock, const osiSockAddr* addr, const char *name) |
752 | +{ |
753 | + if(bind(sock, (struct sockaddr *) &addr->sa, sizeof(*addr))<0) { |
754 | + char sockErrBuf[64]; |
755 | + if(SOCKERRNO!=SOCK_EADDRINUSE) |
756 | + { |
757 | + epicsSocketConvertErrnoToString ( |
758 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
759 | + errlogPrintf ( "CAS: %s bind error: \"%s\"\n", |
760 | + name, sockErrBuf ); |
761 | + epicsThreadSuspendSelf (); |
762 | + } |
763 | + return -1; |
764 | + } else |
765 | + return 0; |
766 | +} |
767 | + |
768 | +/* need to collect a set of TCP sockets, one for each interface, |
769 | + * which are bound to the same TCP port number. |
770 | + * Needed to avoid the complications and confusion of different TCP |
771 | + * ports for each interface (name server and beacon sender would need |
772 | + * to know this). |
773 | + */ |
774 | +static |
775 | +SOCKET* rsrv_grab_tcp(unsigned short *port) |
776 | +{ |
777 | + SOCKET *socks; |
778 | + osiSockAddr scratch; |
779 | + unsigned i; |
780 | + |
781 | + socks = mallocMustSucceed(ellCount(&casIntfAddrList)*sizeof(*socks), "rsrv_grab_tcp"); |
782 | + for(i=0; i<ellCount(&casIntfAddrList); i++) |
783 | + socks[i] = INVALID_SOCKET; |
784 | + |
785 | + /* start with preferred port */ |
786 | + memset(&scratch, 0, sizeof(scratch)); |
787 | + scratch.ia.sin_family = AF_INET; |
788 | + scratch.ia.sin_port = htons(*port); |
789 | + |
790 | + while(ellCount(&casIntfAddrList)>0) { |
791 | + ELLNODE *cur, *next; |
792 | + unsigned ok = 1; |
793 | + |
794 | + for(i=0; i<ellCount(&casIntfAddrList); i++) { |
795 | + if(socks[i] != INVALID_SOCKET) |
796 | + epicsSocketDestroy(socks[i]); |
797 | + socks[i] = INVALID_SOCKET; |
798 | + } |
799 | + |
800 | + for (i=0, cur=ellFirst(&casIntfAddrList), next = cur ? ellNext(cur) : NULL; |
801 | + cur; |
802 | + i++, cur=next, next=next ? ellNext(next) : NULL) |
803 | + { |
804 | + SOCKET tcpsock; |
805 | + osiSockAddr ifaceAddr = ((osiSockAddrNode *)cur)->addr; |
806 | + |
807 | + scratch.ia.sin_addr = ifaceAddr.ia.sin_addr; |
808 | + |
809 | + tcpsock = socks[i] = epicsSocketCreate (AF_INET, SOCK_STREAM, 0); |
810 | + if(tcpsock==INVALID_SOCKET) |
811 | + cantProceed("rsrv ran out of sockets during initialization"); |
812 | + |
813 | + epicsSocketEnableAddressReuseDuringTimeWaitState ( tcpsock ); |
814 | + |
815 | + if(bind(tcpsock, &scratch.sa, sizeof(scratch))==0) { |
816 | + if(scratch.ia.sin_port==0) { |
817 | + /* use first socket to pick a random port */ |
818 | + osiSocklen_t alen = sizeof(ifaceAddr); |
819 | + assert(i==0); |
820 | + if(getsockname(tcpsock, &ifaceAddr.sa, &alen)) { |
821 | + char sockErrBuf[64]; |
822 | + epicsSocketConvertErrnoToString ( |
823 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
824 | + errlogPrintf ( "CAS: getsockname error was \"%s\"\n", |
825 | + sockErrBuf ); |
826 | + epicsThreadSuspendSelf (); |
827 | + ok = 0; |
828 | + break; |
829 | + } |
830 | + scratch.ia.sin_port = ifaceAddr.ia.sin_port; |
831 | + assert(scratch.ia.sin_port!=0); |
832 | + } |
833 | + } else { |
834 | + int errcode = SOCKERRNO; |
835 | + /* bind fails. React harshly to unexpected errors to avoid an infinite loop */ |
836 | + if(errcode==SOCK_EADDRNOTAVAIL) { |
837 | + /* this is not a bind()able address. */ |
838 | + int j; |
839 | + char name[40]; |
840 | + ipAddrToDottedIP(&scratch.ia, name, sizeof(name)); |
841 | + printf("Skipping %s which is not an interface address\n", name); |
842 | + |
843 | + for(j=0; j<=i; j++) { |
844 | + epicsSocketDestroy(socks[j]); |
845 | + socks[j] = INVALID_SOCKET; |
846 | + } |
847 | + |
848 | + ellDelete(&casIntfAddrList, cur); |
849 | + free(cur); |
850 | + ok = 0; |
851 | + break; |
852 | + } |
853 | + /* if SOCK_EADDRINUSE then try again with a different port number. |
854 | + * otherwise, fail hard |
855 | + */ |
856 | + if(errcode!=SOCK_EADDRINUSE) { |
857 | + char name[40]; |
858 | + char sockErrBuf[64]; |
859 | + epicsSocketConvertErrnoToString ( |
860 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
861 | + ipAddrToDottedIP(&scratch.ia, name, sizeof(name)); |
862 | + cantProceed( "CAS: Socket bind %s error was \"%s\"\n", |
863 | + name, sockErrBuf ); |
864 | + } |
865 | + ok = 0; |
866 | + break; |
867 | + } |
868 | + } |
869 | + |
870 | + if (ok) { |
871 | + assert(scratch.ia.sin_port!=0); |
872 | + *port = ntohs(scratch.ia.sin_port); |
873 | + |
874 | + break; |
875 | + } else { |
876 | + |
877 | + for(i=0; i<ellCount(&casIntfAddrList); i++) { |
878 | + /* cleanup any ports actually bound */ |
879 | + if(socks[i]!=INVALID_SOCKET) { |
880 | + epicsSocketDestroy(socks[i]); |
881 | + socks[i] = INVALID_SOCKET; |
882 | + } |
883 | + } |
884 | + |
885 | + scratch.ia.sin_port=0; /* next iteration starts with a random port */ |
886 | + } |
887 | + } |
888 | + |
889 | + if(ellCount(&casIntfAddrList)==0) |
890 | + cantProceed("Error: RSRV has empty interface list\n" |
891 | + "The CA server can't function without binding to" |
892 | + " at least one network interface.\n"); |
893 | + |
894 | + return socks; |
895 | +} |
896 | + |
897 | +static |
898 | +void rsrv_build_addr_lists(void) |
899 | +{ |
900 | + int autobeaconlist = 1; |
901 | + |
902 | + /* the UDP ports are known at this point, but the TCP port is not */ |
903 | + assert(ca_beacon_port!=0); |
904 | + assert(ca_udp_port!=0); |
905 | + |
906 | + envGetBoolConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, &autobeaconlist); |
907 | + |
908 | + ellInit ( &casIntfAddrList ); |
909 | + ellInit ( &beaconAddrList ); |
910 | + ellInit ( &casMCastAddrList ); |
911 | + |
912 | + /* Setup socket for sending server beacons. |
913 | + * Also used for NIC introspection |
914 | + */ |
915 | + |
916 | + beaconSocket = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); |
917 | + if (beaconSocket==INVALID_SOCKET) |
918 | + cantProceed("socket allocation failed during address list expansion"); |
919 | + |
920 | + { |
921 | + int intTrue = 1; |
922 | + if (setsockopt (beaconSocket, SOL_SOCKET, SO_BROADCAST, |
923 | + (char *)&intTrue, sizeof(intTrue))<0) { |
924 | + cantProceed("CAS: online socket set up error\n"); |
925 | + } |
926 | +#ifdef IP_ADD_MEMBERSHIP |
927 | + { |
928 | + int flag = 1; |
929 | + if (setsockopt(beaconSocket, IPPROTO_IP, IP_MULTICAST_LOOP, |
930 | + (char *)&flag, sizeof(flag))<0) { |
931 | + char sockErrBuf[64]; |
932 | + epicsSocketConvertErrnoToString ( |
933 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
934 | + errlogPrintf("rsrv: failed to set mcast loopback\n"); |
935 | + } |
936 | + } |
937 | +#endif |
938 | + } |
939 | + |
940 | + /* populate the interface address list (default is empty) */ |
941 | + { |
942 | + ELLLIST temp = ELLLIST_INIT; |
943 | + /* use the first parameter which is set. */ |
944 | + addAddrToChannelAccessAddressList ( &temp, &EPICS_CAS_INTF_ADDR_LIST, ca_udp_port, 0 ); |
945 | + |
946 | + removeDuplicateAddresses(&casIntfAddrList, &temp, 0); |
947 | + } |
948 | + |
949 | + /* Process the interface address list |
950 | + * Move multicast addresses to casMCastAddrList |
951 | + * Populate beacon address list (if autobeaconlist and iface list not-empty). |
952 | + */ |
953 | + { |
954 | + int foundWildcard = 0, doautobeacon = autobeaconlist; |
955 | + |
956 | + osiSockAddrNode *pNode, *pNext; |
957 | + for(pNode = (osiSockAddrNode*)ellFirst(&casIntfAddrList), |
958 | + pNext = pNode ? (osiSockAddrNode*)ellNext(&pNode->node) : NULL; |
959 | + pNode; |
960 | + pNode = pNext, |
961 | + pNext = pNext ? (osiSockAddrNode*)ellNext(&pNext->node) : NULL) |
962 | + { |
963 | + osiSockAddr match; |
964 | + epicsUInt32 top = ntohl(pNode->addr.ia.sin_addr.s_addr)>>24; |
965 | + |
966 | + if(pNode->addr.ia.sin_family==AF_INET && pNode->addr.ia.sin_addr.s_addr==htonl(INADDR_ANY)) |
967 | + { |
968 | + foundWildcard = 1; |
969 | + |
970 | + } else if(pNode->addr.ia.sin_family==AF_INET && top>=224 && top<=239) { |
971 | + /* This is a multi-cast address */ |
972 | + ellDelete(&casIntfAddrList, &pNode->node); |
973 | + ellAdd(&casMCastAddrList, &pNode->node); |
974 | + continue; |
975 | + } |
976 | + |
977 | + if(!doautobeacon) |
978 | + continue; |
979 | + /* when given a specific interface address, auto populate with the |
980 | + * corresponding broadcast address. |
981 | + */ |
982 | + |
983 | + autobeaconlist = 0; /* prevent later population from wildcard */ |
984 | + |
985 | + memset(&match, 0, sizeof(match)); |
986 | + match.ia.sin_family = AF_INET; |
987 | + match.ia.sin_addr.s_addr = pNode->addr.ia.sin_addr.s_addr; |
988 | + match.ia.sin_port = htons(ca_beacon_port); |
989 | + |
990 | + osiSockDiscoverBroadcastAddresses(&beaconAddrList, beaconSocket, &match); |
991 | + } |
992 | + |
993 | + if (foundWildcard && ellCount(&casIntfAddrList) != 1) { |
994 | + cantProceed("CAS interface address list can not contain 0.0.0.0 and other interface addresses.\n"); |
995 | + } |
996 | + } |
997 | + |
998 | + if (ellCount(&casIntfAddrList) == 0) { |
999 | + /* default to wildcard 0.0.0.0 when interface address list is empty */ |
1000 | + osiSockAddrNode *pNode = (osiSockAddrNode *) callocMustSucceed( 1, sizeof(*pNode), "rsrv_init" ); |
1001 | + pNode->addr.ia.sin_family = AF_INET; |
1002 | + pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); |
1003 | + pNode->addr.ia.sin_port = 0; |
1004 | + ellAdd ( &casIntfAddrList, &pNode->node ); |
1005 | + } |
1006 | + |
1007 | + { |
1008 | + ELLLIST temp = ELLLIST_INIT; |
1009 | + osiSockAddrNode *pNode; |
1010 | + |
1011 | + ellConcat(&temp, &beaconAddrList); |
1012 | + |
1013 | + /* collect user specified beacon address list |
1014 | + * prefer EPICS_CAS_BEACON_ADDR_LIST, fallback to EPICS_CA_ADDR_LIST |
1015 | + */ |
1016 | + addAddrToChannelAccessAddressList ( &temp, &EPICS_CAS_BEACON_ADDR_LIST, ca_beacon_port, 0 ); |
1017 | + |
1018 | + if (autobeaconlist) { |
1019 | + /* auto populate with all broadcast addresses. |
1020 | + * Note that autobeaconlist is zeroed above if an interface |
1021 | + * address list is provided. |
1022 | + */ |
1023 | + osiSockAddr match; |
1024 | + memset(&match, 0, sizeof(match)); |
1025 | + match.ia.sin_family = AF_INET; |
1026 | + match.ia.sin_addr.s_addr = htonl(INADDR_ANY); |
1027 | + match.ia.sin_port = htons(ca_beacon_port); |
1028 | + |
1029 | + osiSockDiscoverBroadcastAddresses(&temp, beaconSocket, &match); |
1030 | + } |
1031 | + |
1032 | + /* set the port for any automatically discovered destinations. */ |
1033 | + for(pNode = (osiSockAddrNode*)ellFirst(&temp); |
1034 | + pNode; |
1035 | + pNode = (osiSockAddrNode*)ellNext(&pNode->node)) |
1036 | + { |
1037 | + if(pNode->addr.ia.sin_port==0) |
1038 | + pNode->addr.ia.sin_port = htons(ca_beacon_port); |
1039 | + } |
1040 | + |
1041 | + removeDuplicateAddresses(&beaconAddrList, &temp, 0); |
1042 | + } |
1043 | + |
1044 | + if (ellCount(&beaconAddrList)==0) |
1045 | + fprintf(stderr, "Warning: RSRV has empty beacon address list\n"); |
1046 | + |
1047 | + { |
1048 | + osiSockAddrNode *node; |
1049 | + ELLLIST temp = ELLLIST_INIT, |
1050 | + temp2= ELLLIST_INIT; |
1051 | + size_t idx = 0; |
1052 | + |
1053 | + addAddrToChannelAccessAddressList ( &temp, &EPICS_CAS_IGNORE_ADDR_LIST, 0, 0 ); |
1054 | + removeDuplicateAddresses(&temp2, &temp, 0); |
1055 | + |
1056 | + /* Keep the list of addresses to ignore in an array on the assumption that |
1057 | + * it is short enough that using a hash table would be slower. |
1058 | + * 0.0.0.0 indicates end of list |
1059 | + */ |
1060 | + casIgnoreAddrs = callocMustSucceed(1+ellCount(&temp2), sizeof(casIgnoreAddrs[0]), "casIgnoreAddrs"); |
1061 | + |
1062 | + while((node=(osiSockAddrNode*)ellGet(&temp2))!=NULL) |
1063 | + { |
1064 | + casIgnoreAddrs[idx++] = node->addr.ia.sin_addr.s_addr; |
1065 | + free(node); |
1066 | + } |
1067 | + casIgnoreAddrs[idx] = 0; |
1068 | + } |
1069 | +} |
1070 | + |
1071 | static dbServer rsrv_server = { |
1072 | ELLNODE_INIT, |
1073 | "rsrv", |
1074 | @@ -257,11 +466,9 @@ |
1075 | */ |
1076 | int rsrv_init (void) |
1077 | { |
1078 | - epicsThreadBooleanStatus tbs; |
1079 | - unsigned priorityOfConnectDaemon; |
1080 | - epicsThreadId tid; |
1081 | long maxBytesAsALong; |
1082 | long status; |
1083 | + SOCKET *socks; |
1084 | |
1085 | clientQlock = epicsMutexMustCreate(); |
1086 | |
1087 | @@ -272,8 +479,31 @@ |
1088 | freeListInitPvt ( &rsrvSmallBufFreeListTCP, MAX_TCP, 16 ); |
1089 | initializePutNotifyFreeList (); |
1090 | |
1091 | + epicsSignalInstallSigPipeIgnore (); |
1092 | + |
1093 | + rsrvCurrentClient = epicsThreadPrivateCreate (); |
1094 | + |
1095 | dbRegisterServer(&rsrv_server); |
1096 | |
1097 | + if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) { |
1098 | + ca_server_port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT, |
1099 | + (unsigned short) CA_SERVER_PORT ); |
1100 | + } |
1101 | + else { |
1102 | + ca_server_port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, |
1103 | + (unsigned short) CA_SERVER_PORT ); |
1104 | + } |
1105 | + ca_udp_port = ca_server_port; |
1106 | + |
1107 | + if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) { |
1108 | + ca_beacon_port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT, |
1109 | + (unsigned short) CA_REPEATER_PORT ); |
1110 | + } |
1111 | + else { |
1112 | + ca_beacon_port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, |
1113 | + (unsigned short) CA_REPEATER_PORT ); |
1114 | + } |
1115 | + |
1116 | status = envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong ); |
1117 | if ( status || maxBytesAsALong < 0 ) { |
1118 | errlogPrintf ( "CAS: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" ); |
1119 | @@ -298,41 +528,223 @@ |
1120 | } |
1121 | } |
1122 | freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 ); |
1123 | - ellInit ( &casIntfAddrList ); |
1124 | - ellInit ( &beaconAddrList ); |
1125 | - prsrv_cast_client = NULL; |
1126 | - pCaBucket = NULL; |
1127 | + pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE); |
1128 | + if (!pCaBucket) |
1129 | + cantProceed("RSRV failed to allocate ID lookup table\n"); |
1130 | + |
1131 | + rsrv_build_addr_lists(); |
1132 | |
1133 | castcp_startStopEvent = epicsEventMustCreate(epicsEventEmpty); |
1134 | + casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty); |
1135 | + beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty); |
1136 | castcp_ctl = ctlPause; |
1137 | |
1138 | - /* |
1139 | - * go down two levels so that we are below |
1140 | - * the TCP and event threads started on behalf |
1141 | - * of individual clients |
1142 | - */ |
1143 | - tbs = epicsThreadHighestPriorityLevelBelow ( |
1144 | - epicsThreadPriorityCAServerLow, &priorityOfConnectDaemon ); |
1145 | - if ( tbs == epicsThreadBooleanStatusSuccess ) { |
1146 | - tbs = epicsThreadHighestPriorityLevelBelow ( |
1147 | - priorityOfConnectDaemon, &priorityOfConnectDaemon ); |
1148 | - if ( tbs != epicsThreadBooleanStatusSuccess ) { |
1149 | - priorityOfConnectDaemon = epicsThreadPriorityCAServerLow; |
1150 | - } |
1151 | - } |
1152 | - else { |
1153 | - priorityOfConnectDaemon = epicsThreadPriorityCAServerLow; |
1154 | - } |
1155 | - |
1156 | - tid = epicsThreadCreate ( "CAS-TCP", |
1157 | - priorityOfConnectDaemon, |
1158 | - epicsThreadGetStackSize(epicsThreadStackMedium), |
1159 | - req_server, 0); |
1160 | - if ( tid == 0 ) { |
1161 | - epicsPrintf ( "CAS: unable to start connection request thread\n" ); |
1162 | - } |
1163 | - |
1164 | - epicsEventMustWait(castcp_startStopEvent); |
1165 | + /* Thread priorites |
1166 | + * Now starting per interface |
1167 | + * TCP Listener: epicsThreadPriorityCAServerLow-2 |
1168 | + * Name receiver: epicsThreadPriorityCAServerLow-4 |
1169 | + * Now starting global |
1170 | + * Beacon sender: epicsThreadPriorityCAServerLow-3 |
1171 | + * Started later per TCP client |
1172 | + * TCP receiver: epicsThreadPriorityCAServerLow |
1173 | + * TCP sender : epicsThreadPriorityCAServerLow-1 |
1174 | + */ |
1175 | + { |
1176 | + unsigned i; |
1177 | + threadPrios[0] = epicsThreadPriorityCAServerLow; |
1178 | + |
1179 | + for(i=1; i<NELEMENTS(threadPrios); i++) |
1180 | + { |
1181 | + if(epicsThreadBooleanStatusSuccess!=epicsThreadHighestPriorityLevelBelow( |
1182 | + threadPrios[i-1], &threadPrios[i])) |
1183 | + { |
1184 | + /* on failure use the lowest known */ |
1185 | + threadPrios[i] = threadPrios[i-1]; |
1186 | + } |
1187 | + } |
1188 | + } |
1189 | + |
1190 | + { |
1191 | + unsigned short sport = ca_server_port; |
1192 | + socks = rsrv_grab_tcp(&sport); |
1193 | + |
1194 | + if ( sport != ca_server_port ) { |
1195 | + ca_server_port = sport; |
1196 | + errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n"); |
1197 | + errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n", |
1198 | + ca_server_port ); |
1199 | + errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n"); |
1200 | + errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" ); |
1201 | + errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" ); |
1202 | + } |
1203 | + } |
1204 | + |
1205 | + /* start servers (TCP and UDP(s) for each interface. |
1206 | + */ |
1207 | + { |
1208 | + int havesometcp = 0; |
1209 | + ELLNODE *cur; |
1210 | + int i; |
1211 | + |
1212 | + for (i=0, cur=ellFirst(&casIntfAddrList); cur; i++, cur=ellNext(cur)) |
1213 | + { |
1214 | + char ifaceName[40]; |
1215 | + rsrv_iface_config *conf; |
1216 | + |
1217 | + conf = callocMustSucceed(1, sizeof(*conf), "rsrv_init"); |
1218 | + |
1219 | + conf->tcpAddr = ((osiSockAddrNode *)cur)->addr; |
1220 | + conf->tcpAddr.ia.sin_port = htons(ca_server_port); |
1221 | + conf->tcp = socks[i]; |
1222 | + socks[i] = INVALID_SOCKET; |
1223 | + |
1224 | + ipAddrToDottedIP (&conf->tcpAddr.ia, ifaceName, sizeof(ifaceName)); |
1225 | + |
1226 | + conf->udp = conf->udpbcast = INVALID_SOCKET; |
1227 | + |
1228 | + /* create and bind UDP name receiver socket(s) */ |
1229 | + |
1230 | + conf->udp = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); |
1231 | + if(conf->udp==INVALID_SOCKET) |
1232 | + cantProceed("rsrv_init ran out of udp sockets"); |
1233 | + |
1234 | + conf->udpAddr = conf->tcpAddr; |
1235 | + conf->udpAddr.ia.sin_port = htons(ca_udp_port); |
1236 | + |
1237 | + epicsSocketEnableAddressUseForDatagramFanout ( conf->udp ); |
1238 | + |
1239 | + if(tryBind(conf->udp, &conf->udpAddr, "UDP unicast socket")) |
1240 | + goto cleanup; |
1241 | + |
1242 | +#ifdef IP_ADD_MEMBERSHIP |
1243 | + /* join UDP socket to any multicast groups */ |
1244 | + { |
1245 | + osiSockAddrNode *pNode; |
1246 | + |
1247 | + for(pNode = (osiSockAddrNode*)ellFirst(&casMCastAddrList); |
1248 | + pNode; |
1249 | + pNode = (osiSockAddrNode*)ellNext(&pNode->node)) |
1250 | + { |
1251 | + struct ip_mreq mreq; |
1252 | + |
1253 | + memset(&mreq, 0, sizeof(mreq)); |
1254 | + mreq.imr_multiaddr = pNode->addr.ia.sin_addr; |
1255 | + mreq.imr_interface.s_addr = conf->udpAddr.ia.sin_addr.s_addr; |
1256 | + |
1257 | + if (setsockopt(conf->udp, IPPROTO_IP, IP_ADD_MEMBERSHIP, |
1258 | + (char *) &mreq, sizeof(mreq))!=0) { |
1259 | + struct sockaddr_in temp; |
1260 | + char name[40]; |
1261 | + char sockErrBuf[64]; |
1262 | + temp.sin_family = AF_INET; |
1263 | + temp.sin_addr = mreq.imr_multiaddr; |
1264 | + temp.sin_port = conf->udpAddr.ia.sin_port; |
1265 | + epicsSocketConvertErrnoToString ( |
1266 | + sockErrBuf, sizeof ( sockErrBuf ) ); |
1267 | + ipAddrToDottedIP (&temp, name, sizeof(name)); |
1268 | + fprintf(stderr, "CAS: Socket mcast join %s to %s failed with \"%s\"\n", |
1269 | + ifaceName, name, sockErrBuf ); |
1270 | + } |
1271 | + } |
1272 | + } |
1273 | +#else |
1274 | + if(ellCount(&casMCastAddrList)){ |
1275 | + fprintf(stderr, "IPv4 Multicast name lookup not supported by this target\n"); |
1276 | + } |
1277 | +#endif |
1278 | + |
1279 | +#if !(defined(_WIN32) || defined(__CYGWIN32__)) |
1280 | + /* An oddness of BSD sockets (not winsock) is that binding to |
1281 | + * INADDR_ANY will receive unicast and broadcast, but binding to |
1282 | + * a specific interface address receives only unicast. The trick |
1283 | + * is to bind a second socket to the interface broadcast address, |
1284 | + * which will then receive only broadcasts. |
1285 | + */ |
1286 | + if(conf->udpAddr.ia.sin_addr.s_addr!=htonl(INADDR_ANY)) { |
1287 | + /* find interface broadcast address */ |
1288 | + ELLLIST bcastList = ELLLIST_INIT; |
1289 | + osiSockAddrNode *pNode; |
1290 | + |
1291 | + osiSockDiscoverBroadcastAddresses (&bcastList, |
1292 | + conf->udp, &conf->udpAddr); // match addr |
1293 | + |
1294 | + if(ellCount(&bcastList)==0) { |
1295 | + fprintf(stderr, "Warning: Can't find broadcast address of interface %s\n" |
1296 | + " Name lookup may not work on this interface\n", ifaceName); |
1297 | + } else { |
1298 | + if(ellCount(&bcastList)>1 && conf->udpAddr.ia.sin_addr.s_addr!=htonl(INADDR_ANY)) |
1299 | + printf("Interface %s has more than one broadcast address?\n", ifaceName); |
1300 | + |
1301 | + pNode = (osiSockAddrNode*)ellFirst(&bcastList); |
1302 | + |
1303 | + conf->udpbcast = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); |
1304 | + if(conf->udpbcast==INVALID_SOCKET) |
1305 | + cantProceed("rsrv_init ran out of udp sockets for bcast"); |
1306 | + |
1307 | + epicsSocketEnableAddressUseForDatagramFanout ( conf->udpbcast ); |
1308 | + |
1309 | + conf->udpbcastAddr = conf->udpAddr; |
1310 | + conf->udpbcastAddr.ia.sin_addr.s_addr = pNode->addr.ia.sin_addr.s_addr; |
1311 | + |
1312 | + if(tryBind(conf->udpbcast, &conf->udpbcastAddr, "UDP Socket bcast")) |
1313 | + goto cleanup; |
1314 | + } |
1315 | + |
1316 | + ellFree(&bcastList); |
1317 | + } |
1318 | + |
1319 | +#endif /* !(defined(_WIN32) || defined(__CYGWIN32__)) */ |
1320 | + |
1321 | + ellAdd(&servers, &conf->node); |
1322 | + |
1323 | + /* have all sockets, time to start some threads */ |
1324 | + |
1325 | + epicsThreadMustCreate("CAS-TCP", threadPrios[2], |
1326 | + epicsThreadGetStackSize(epicsThreadStackMedium), |
1327 | + &req_server, conf); |
1328 | + |
1329 | + epicsEventMustWait(castcp_startStopEvent); |
1330 | + |
1331 | + epicsThreadMustCreate("CAS-UDP", threadPrios[4], |
1332 | + epicsThreadGetStackSize(epicsThreadStackMedium), |
1333 | + &cast_server, conf); |
1334 | + |
1335 | + epicsEventMustWait(casudp_startStopEvent); |
1336 | + |
1337 | +#if !(defined(_WIN32) || defined(__CYGWIN32__)) |
1338 | + if(conf->udpbcast != INVALID_SOCKET) { |
1339 | + conf->startbcast = 1; |
1340 | + |
1341 | + epicsThreadMustCreate("CAS-UDP2", threadPrios[4], |
1342 | + epicsThreadGetStackSize(epicsThreadStackMedium), |
1343 | + &cast_server, conf); |
1344 | + |
1345 | + epicsEventMustWait(casudp_startStopEvent); |
1346 | + |
1347 | + conf->startbcast = 0; |
1348 | + } |
1349 | +#endif /* !(defined(_WIN32) || defined(__CYGWIN32__)) */ |
1350 | + |
1351 | + havesometcp = 1; |
1352 | + continue; |
1353 | + cleanup: |
1354 | + epicsSocketDestroy(conf->tcp); |
1355 | + if(conf->udp!=INVALID_SOCKET) epicsSocketDestroy(conf->udp); |
1356 | + if(conf->udpbcast!=INVALID_SOCKET) epicsSocketDestroy(conf->udpbcast); |
1357 | + free(conf); |
1358 | + } |
1359 | + |
1360 | + if(!havesometcp) |
1361 | + cantProceed("CAS: No TCP server started\n"); |
1362 | + } |
1363 | + |
1364 | + /* servers list is considered read-only from this point */ |
1365 | + |
1366 | + epicsThreadMustCreate("CAS-beacon", threadPrios[3], |
1367 | + epicsThreadGetStackSize(epicsThreadStackSmall), |
1368 | + &rsrv_online_notify_task, NULL); |
1369 | + |
1370 | + epicsEventMustWait(beacon_startStopEvent); |
1371 | |
1372 | return RSRV_OK; |
1373 | } |
1374 | @@ -382,10 +794,11 @@ |
1375 | pciu = (struct channel_in_use *) pList->node.next; |
1376 | while ( pciu ){ |
1377 | dbChannelShow ( pciu->dbch, level, 8 ); |
1378 | - printf( " # on eventq=%d, access=%c%c\n", |
1379 | - ellCount ( &pciu->eventq ), |
1380 | - asCheckGet ( pciu->asClientPVT ) ? 'r': '-', |
1381 | - rsrvCheckPut ( pciu ) ? 'w': '-' ); |
1382 | + if ( level >= 1u ) |
1383 | + printf( "%12s# on eventq=%d, access=%c%c\n", "", |
1384 | + ellCount ( &pciu->eventq ), |
1385 | + asCheckGet ( pciu->asClientPVT ) ? 'r': '-', |
1386 | + rsrvCheckPut ( pciu ) ? 'w': '-' ); |
1387 | pciu = ( struct channel_in_use * ) ellNext ( &pciu->node ); |
1388 | } |
1389 | epicsMutexUnlock ( client->chanListLock ); |
1390 | @@ -396,78 +809,82 @@ |
1391 | */ |
1392 | static void log_one_client (struct client *client, unsigned level) |
1393 | { |
1394 | - char *pproto; |
1395 | - double send_delay; |
1396 | - double recv_delay; |
1397 | - char *state[] = {"up", "down"}; |
1398 | - epicsTimeStamp current; |
1399 | - char clientHostName[256]; |
1400 | - |
1401 | - ipAddrToDottedIP (&client->addr, clientHostName, sizeof(clientHostName)); |
1402 | - |
1403 | - if(client->proto == IPPROTO_UDP){ |
1404 | - pproto = "UDP"; |
1405 | - } |
1406 | - else if(client->proto == IPPROTO_TCP){ |
1407 | - pproto = "TCP"; |
1408 | - } |
1409 | - else{ |
1410 | - pproto = "UKN"; |
1411 | - } |
1412 | - |
1413 | - epicsTimeGetCurrent(¤t); |
1414 | - send_delay = epicsTimeDiffInSeconds(¤t,&client->time_at_last_send); |
1415 | - recv_delay = epicsTimeDiffInSeconds(¤t,&client->time_at_last_recv); |
1416 | - |
1417 | - printf ( "%s %s(%s): User=\"%s\", V%u.%u, %d Channels, Priority=%u\n", |
1418 | - pproto, |
1419 | - clientHostName, |
1420 | - client->pHostName ? client->pHostName : "", |
1421 | + char clientIP[40]; |
1422 | + int n; |
1423 | + |
1424 | + ipAddrToDottedIP (&client->addr, clientIP, sizeof(clientIP)); |
1425 | + |
1426 | + if ( client->proto == IPPROTO_UDP ) { |
1427 | + printf ( "\tLast name requested by %s:\n", |
1428 | + clientIP ); |
1429 | + } |
1430 | + else if ( client->proto == IPPROTO_TCP ) { |
1431 | + printf ( " TCP client at %s '%s':\n", |
1432 | + clientIP, |
1433 | + client->pHostName ? client->pHostName : "" ); |
1434 | + } |
1435 | + else { |
1436 | + printf ( " Unknown client at %s '%s':\n", |
1437 | + clientIP, |
1438 | + client->pHostName ? client->pHostName : "" ); |
1439 | + } |
1440 | + |
1441 | + n = ellCount(&client->chanList) + ellCount(&client->chanPendingUpdateARList); |
1442 | + printf ( "\tUser '%s', V%u.%u, Priority = %u, %d Channel%s\n", |
1443 | client->pUserName ? client->pUserName : "", |
1444 | CA_MAJOR_PROTOCOL_REVISION, |
1445 | client->minor_version_number, |
1446 | - ellCount(&client->chanList) + |
1447 | - ellCount(&client->chanPendingUpdateARList), |
1448 | - client->priority ); |
1449 | - if ( level >= 1 ) { |
1450 | - printf ("\tTask Id=%p, Socket FD=%d\n", |
1451 | + client->priority, |
1452 | + n, n == 1 ? "" : "s" ); |
1453 | + |
1454 | + if ( level >= 3u ) { |
1455 | + double send_delay; |
1456 | + double recv_delay; |
1457 | + char *state[] = {"up", "down"}; |
1458 | + epicsTimeStamp current; |
1459 | + |
1460 | + epicsTimeGetCurrent(¤t); |
1461 | + send_delay = epicsTimeDiffInSeconds(¤t,&client->time_at_last_send); |
1462 | + recv_delay = epicsTimeDiffInSeconds(¤t,&client->time_at_last_recv); |
1463 | + |
1464 | + printf ("\tTask Id = %p, Socket FD = %d\n", |
1465 | (void *) client->tid, client->sock); |
1466 | printf( |
1467 | - "\tSecs since last send %6.2f, Secs since last receive %6.2f\n", |
1468 | + "\t%.2f secs since last send, %.2f secs since last receive\n", |
1469 | send_delay, recv_delay); |
1470 | printf( |
1471 | - "\tUnprocessed request bytes=%u, Undelivered response bytes=%u\n", |
1472 | + "\tUnprocessed request bytes = %u, Undelivered response bytes = %u\n", |
1473 | client->recv.cnt - client->recv.stk, |
1474 | client->send.stk ); |
1475 | printf( |
1476 | - "\tState=%s%s%s\n", |
1477 | + "\tState = %s%s%s\n", |
1478 | state[client->disconnect?1:0], |
1479 | client->send.type == mbtLargeTCP ? " jumbo-send-buf" : "", |
1480 | client->recv.type == mbtLargeTCP ? " jumbo-recv-buf" : ""); |
1481 | } |
1482 | |
1483 | - if ( level >= 2u ) { |
1484 | - unsigned bytes_reserved = 0; |
1485 | - bytes_reserved += sizeof(struct client); |
1486 | + if ( level >= 1u ) { |
1487 | + showChanList ( client, level - 1u, & client->chanList ); |
1488 | + showChanList ( client, level - 1u, & client->chanPendingUpdateARList ); |
1489 | + } |
1490 | + |
1491 | + if ( level >= 4u ) { |
1492 | + unsigned bytes_reserved = sizeof(struct client); |
1493 | + |
1494 | bytes_reserved += countChanListBytes ( |
1495 | client, & client->chanList ); |
1496 | bytes_reserved += countChanListBytes ( |
1497 | client, & client->chanPendingUpdateARList ); |
1498 | printf( "\t%d bytes allocated\n", bytes_reserved); |
1499 | - showChanList ( client, level - 2u, & client->chanList ); |
1500 | - showChanList ( client, level - 2u, & client->chanPendingUpdateARList ); |
1501 | - } |
1502 | - |
1503 | - if ( level >= 3u ) { |
1504 | - printf( "\tSend Lock\n"); |
1505 | + printf( "\tSend Lock:\n\t "); |
1506 | epicsMutexShow(client->lock,1); |
1507 | - printf( "\tPut Notify Lock\n"); |
1508 | + printf( "\tPut Notify Lock:\n\t "); |
1509 | epicsMutexShow (client->putNotifyLock,1); |
1510 | - printf( "\tAddress Queue Lock\n"); |
1511 | + printf( "\tAddress Queue Lock:\n\t "); |
1512 | epicsMutexShow (client->chanListLock,1); |
1513 | - printf( "\tEvent Queue Lock\n"); |
1514 | + printf( "\tEvent Queue Lock:\n\t "); |
1515 | epicsMutexShow (client->eventqLock,1); |
1516 | - printf( "\tBlock Semaphore\n"); |
1517 | + printf( "\tBlock Semaphore:\n\t "); |
1518 | epicsEventShow (client->blockSem,1); |
1519 | } |
1520 | } |
1521 | @@ -478,7 +895,7 @@ |
1522 | void casr (unsigned level) |
1523 | { |
1524 | size_t bytes_reserved; |
1525 | - struct client *client; |
1526 | + int n; |
1527 | |
1528 | if ( ! clientQlock ) { |
1529 | return; |
1530 | @@ -488,25 +905,106 @@ |
1531 | CA_VERSION_STRING ( CA_MINOR_PROTOCOL_REVISION ) ); |
1532 | |
1533 | LOCK_CLIENTQ |
1534 | - client = (struct client *) ellNext ( &clientQ.node ); |
1535 | - if (client) { |
1536 | - printf("Connected circuits:\n"); |
1537 | - } |
1538 | - else { |
1539 | + n = ellCount ( &clientQ ); |
1540 | + if (n == 0) { |
1541 | printf("No clients connected.\n"); |
1542 | } |
1543 | - while (client) { |
1544 | - log_one_client(client, level); |
1545 | - client = (struct client *) ellNext(&client->node); |
1546 | + else if (level == 0) { |
1547 | + printf("%d client%s connected.\n", |
1548 | + n, n == 1 ? "" : "s" ); |
1549 | + } |
1550 | + else { |
1551 | + struct client *client = (struct client *) ellFirst ( &clientQ ); |
1552 | + |
1553 | + printf("%d client%s connected:\n", |
1554 | + n, n == 1 ? "" : "s" ); |
1555 | + while (client) { |
1556 | + log_one_client(client, level - 1); |
1557 | + client = (struct client *) ellNext(&client->node); |
1558 | + } |
1559 | } |
1560 | UNLOCK_CLIENTQ |
1561 | |
1562 | - if (level>=2 && prsrv_cast_client) { |
1563 | - printf( "UDP Server:\n" ); |
1564 | - log_one_client(prsrv_cast_client, level); |
1565 | - } |
1566 | - |
1567 | - if (level>=2u) { |
1568 | + if (level>=1) { |
1569 | + rsrv_iface_config *iface = (rsrv_iface_config *) ellFirst ( &servers ); |
1570 | + while (iface) { |
1571 | + char buf[40]; |
1572 | + |
1573 | + ipAddrToDottedIP (&iface->tcpAddr.ia, buf, sizeof(buf)); |
1574 | + printf("CAS-TCP server on %s with\n", buf); |
1575 | + |
1576 | + ipAddrToDottedIP (&iface->udpAddr.ia, buf, sizeof(buf)); |
1577 | +#if defined(_WIN32) |
1578 | + printf(" CAS-UDP name server on %s\n", buf); |
1579 | + if (level >= 2) |
1580 | + log_one_client(iface->client, level - 2); |
1581 | +#else |
1582 | + if (iface->udpbcast==INVALID_SOCKET) { |
1583 | + printf(" CAS-UDP name server on %s\n", buf); |
1584 | + if (level >= 2) |
1585 | + log_one_client(iface->client, level - 2); |
1586 | + } |
1587 | + else { |
1588 | + printf(" CAS-UDP unicast name server on %s\n", buf); |
1589 | + if (level >= 2) |
1590 | + log_one_client(iface->client, level - 2); |
1591 | + ipAddrToDottedIP (&iface->udpbcastAddr.ia, buf, sizeof(buf)); |
1592 | + printf(" CAS-UDP broadcast name server on %s\n", buf); |
1593 | + if (level >= 2) |
1594 | + log_one_client(iface->bclient, level - 2); |
1595 | + } |
1596 | +#endif |
1597 | + |
1598 | + iface = (rsrv_iface_config *) ellNext(&iface->node); |
1599 | + } |
1600 | + } |
1601 | + |
1602 | + if (level>=1) { |
1603 | + osiSockAddrNode * pAddr; |
1604 | + char buf[40]; |
1605 | + int n = ellCount(&casMCastAddrList); |
1606 | + |
1607 | + if (n) { |
1608 | + printf("Monitoring %d multicast address%s:\n", |
1609 | + n, n == 1 ? "" : "es"); |
1610 | + for(pAddr = (osiSockAddrNode*)ellFirst(&casMCastAddrList); |
1611 | + pAddr; |
1612 | + pAddr = (osiSockAddrNode*)ellNext(&pAddr->node)) |
1613 | + { |
1614 | + ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf)); |
1615 | + printf(" %s\n", buf); |
1616 | + } |
1617 | + } |
1618 | + |
1619 | + n = ellCount(&beaconAddrList); |
1620 | + printf("Sending CAS-beacons to %d address%s:\n", |
1621 | + n, n == 1 ? "" : "es"); |
1622 | + for(pAddr = (osiSockAddrNode*)ellFirst(&beaconAddrList); |
1623 | + pAddr; |
1624 | + pAddr = (osiSockAddrNode*)ellNext(&pAddr->node)) |
1625 | + { |
1626 | + ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf)); |
1627 | + printf(" %s\n", buf); |
1628 | + } |
1629 | + |
1630 | + if (casIgnoreAddrs[0]) { /* 0 indicates end of array */ |
1631 | + size_t i; |
1632 | + printf("Ignoring UDP messages from address%s\n", |
1633 | + n == 1 ? "" : "es"); |
1634 | + for(i=0; casIgnoreAddrs[i]; i++) |
1635 | + { |
1636 | + struct sockaddr_in addr; |
1637 | + memset(&addr, 0, sizeof(addr)); |
1638 | + addr.sin_family = AF_INET; |
1639 | + addr.sin_addr.s_addr = casIgnoreAddrs[i]; |
1640 | + addr.sin_port = 0; |
1641 | + ipAddrToDottedIP(&addr, buf, sizeof(buf)); |
1642 | + printf(" %s\n", buf); |
1643 | + } |
1644 | + } |
1645 | + } |
1646 | + |
1647 | + if (level>=4u) { |
1648 | bytes_reserved = 0u; |
1649 | bytes_reserved += sizeof (struct client) * |
1650 | freeListItemsAvail (rsrvClientFreeList); |
1651 | @@ -520,28 +1018,22 @@ |
1652 | freeListItemsAvail ( rsrvLargeBufFreeListTCP ); |
1653 | bytes_reserved += rsrvSizeOfPutNotify ( 0 ) * |
1654 | freeListItemsAvail ( rsrvPutNotifyFreeList ); |
1655 | - printf( "There are currently %u bytes on the server's free list\n", |
1656 | + printf( "Free-lists total %u bytes, comprising\n", |
1657 | (unsigned int) bytes_reserved); |
1658 | - printf( "%u client(s), %u channel(s), %u event(s) (monitors) %u putNotify(s)\n", |
1659 | + printf( " %u client(s), %u channel(s), %u monitor event(s), %u putNotify(s)\n", |
1660 | (unsigned int) freeListItemsAvail ( rsrvClientFreeList ), |
1661 | (unsigned int) freeListItemsAvail ( rsrvChanFreeList ), |
1662 | (unsigned int) freeListItemsAvail ( rsrvEventFreeList ), |
1663 | (unsigned int) freeListItemsAvail ( rsrvPutNotifyFreeList )); |
1664 | - printf( "%u small buffers (%u bytes ea), and %u jumbo buffers (%u bytes ea)\n", |
1665 | + printf( " %u small (%u byte) buffers, %u jumbo (%u byte) buffers\n", |
1666 | (unsigned int) freeListItemsAvail ( rsrvSmallBufFreeListTCP ), |
1667 | MAX_TCP, |
1668 | (unsigned int) freeListItemsAvail ( rsrvLargeBufFreeListTCP ), |
1669 | rsrvSizeofLargeBufTCP ); |
1670 | - if(pCaBucket){ |
1671 | - printf( "The server's resource id conversion table:\n"); |
1672 | - LOCK_CLIENTQ; |
1673 | - bucketShow (pCaBucket); |
1674 | - UNLOCK_CLIENTQ; |
1675 | - } |
1676 | - printf ( "The server's array size limit is %u bytes max\n", |
1677 | - rsrvSizeofLargeBufTCP ); |
1678 | - |
1679 | - printChannelAccessAddressList (&beaconAddrList); |
1680 | + printf( "Server resource id table:\n"); |
1681 | + LOCK_CLIENTQ; |
1682 | + bucketShow (pCaBucket); |
1683 | + UNLOCK_CLIENTQ; |
1684 | } |
1685 | } |
1686 | |
1687 | |
1688 | === modified file 'src/ioc/rsrv/cast_server.c' |
1689 | --- src/ioc/rsrv/cast_server.c 2014-10-06 05:57:02 +0000 |
1690 | +++ src/ioc/rsrv/cast_server.c 2016-02-25 16:34:00 +0000 |
1691 | @@ -54,7 +54,7 @@ |
1692 | /* |
1693 | * clean_addrq |
1694 | */ |
1695 | -static void clean_addrq(void) |
1696 | +static void clean_addrq(struct client *client) |
1697 | { |
1698 | struct channel_in_use * pciu; |
1699 | struct channel_in_use * pnextciu; |
1700 | @@ -67,9 +67,9 @@ |
1701 | |
1702 | epicsTimeGetCurrent ( ¤t ); |
1703 | |
1704 | - epicsMutexMustLock ( prsrv_cast_client->chanListLock ); |
1705 | + epicsMutexMustLock ( client->chanListLock ); |
1706 | pnextciu = (struct channel_in_use *) |
1707 | - prsrv_cast_client->chanList.node.next; |
1708 | + client->chanList.node.next; |
1709 | |
1710 | while( (pciu = pnextciu) ) { |
1711 | pnextciu = (struct channel_in_use *)pciu->node.next; |
1712 | @@ -77,7 +77,7 @@ |
1713 | delay = epicsTimeDiffInSeconds(¤t,&pciu->time_at_creation); |
1714 | if (delay > timeout) { |
1715 | |
1716 | - ellDelete(&prsrv_cast_client->chanList, &pciu->node); |
1717 | + ellDelete(&client->chanList, &pciu->node); |
1718 | LOCK_CLIENTQ; |
1719 | s = bucketRemoveItemUnsignedId ( |
1720 | pCaBucket, |
1721 | @@ -96,7 +96,7 @@ |
1722 | if(delay>maxdelay) maxdelay = delay; |
1723 | } |
1724 | } |
1725 | - epicsMutexUnlock ( prsrv_cast_client->chanListLock ); |
1726 | + epicsMutexUnlock ( client->chanListLock ); |
1727 | |
1728 | # ifdef DEBUG |
1729 | if(ndelete){ |
1730 | @@ -115,70 +115,19 @@ |
1731 | */ |
1732 | void cast_server(void *pParm) |
1733 | { |
1734 | - osiSockAddrNode *paddrNode; |
1735 | - struct sockaddr_in sin; |
1736 | + rsrv_iface_config *conf = pParm; |
1737 | int status; |
1738 | int count=0; |
1739 | + int mysocket=0; |
1740 | struct sockaddr_in new_recv_addr; |
1741 | osiSocklen_t recv_addr_size; |
1742 | osiSockIoctl_t nchars; |
1743 | + SOCKET recv_sock, reply_sock; |
1744 | + struct client *client; |
1745 | |
1746 | recv_addr_size = sizeof(new_recv_addr); |
1747 | |
1748 | - if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) { |
1749 | - epicsSocketDestroy ( IOC_cast_sock ); |
1750 | - } |
1751 | - |
1752 | - /* |
1753 | - * Open the socket. |
1754 | - * Use ARPA Internet address format and datagram socket. |
1755 | - */ |
1756 | - |
1757 | - if ( ( IOC_cast_sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0) ) == INVALID_SOCKET ) { |
1758 | - epicsPrintf ("CAS: cast socket creation error\n"); |
1759 | - epicsThreadSuspendSelf (); |
1760 | - } |
1761 | - |
1762 | - /* |
1763 | - * some concern that vxWorks will run out of mBuf's |
1764 | - * if this change is made |
1765 | - * |
1766 | - * joh 11-10-98 |
1767 | - */ |
1768 | -#if 0 |
1769 | - { |
1770 | - /* |
1771 | - * |
1772 | - * this allows for faster connects by queuing |
1773 | - * additional incomming UDP search frames |
1774 | - * |
1775 | - * this allocates a 32k buffer |
1776 | - * (uses a power of two) |
1777 | - */ |
1778 | - int size = 1u<<15u; |
1779 | - status = setsockopt (IOC_cast_sock, SOL_SOCKET, |
1780 | - SO_RCVBUF, (char *)&size, sizeof(size)); |
1781 | - if (status<0) { |
1782 | - epicsPrintf ("CAS: unable to set cast socket size\n"); |
1783 | - } |
1784 | - } |
1785 | -#endif |
1786 | - |
1787 | - epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock ); |
1788 | - |
1789 | - paddrNode = (osiSockAddrNode *) ellFirst ( &casIntfAddrList ); |
1790 | - |
1791 | - memcpy(&sin, &paddrNode->addr.ia, sizeof (sin)); |
1792 | - |
1793 | - /* get server's Internet address */ |
1794 | - if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){ |
1795 | - char sockErrBuf[64]; |
1796 | - epicsSocketConvertErrnoToString ( |
1797 | - sockErrBuf, sizeof ( sockErrBuf ) ); |
1798 | - epicsPrintf ("CAS: UDP server port bind error was \"%s\"\n", sockErrBuf ); |
1799 | - epicsSocketDestroy ( IOC_cast_sock ); |
1800 | - epicsThreadSuspendSelf (); |
1801 | - } |
1802 | + reply_sock = conf->udp; |
1803 | |
1804 | /* |
1805 | * setup new client structure but reuse old structure if |
1806 | @@ -186,27 +135,39 @@ |
1807 | * |
1808 | */ |
1809 | while ( TRUE ) { |
1810 | - prsrv_cast_client = create_client ( IOC_cast_sock, IPPROTO_UDP ); |
1811 | - if ( prsrv_cast_client ) { |
1812 | + client = create_client ( reply_sock, IPPROTO_UDP ); |
1813 | + if ( client ) { |
1814 | break; |
1815 | } |
1816 | epicsThreadSleep(300.0); |
1817 | } |
1818 | + if (conf->startbcast) { |
1819 | + recv_sock = conf->udpbcast; |
1820 | + conf->bclient = client; |
1821 | + } |
1822 | + else { |
1823 | + recv_sock = conf->udp; |
1824 | + conf->client = client; |
1825 | + } |
1826 | + client->udpRecv = recv_sock; |
1827 | |
1828 | - casAttachThreadToClient ( prsrv_cast_client ); |
1829 | + casAttachThreadToClient ( client ); |
1830 | |
1831 | /* |
1832 | * add placeholder for the first version message should it be needed |
1833 | */ |
1834 | - rsrv_version_reply ( prsrv_cast_client ); |
1835 | + rsrv_version_reply ( client ); |
1836 | + |
1837 | + /* these pointers become invalid after signaling casudp_startStopEvent */ |
1838 | + conf = NULL; |
1839 | |
1840 | epicsEventSignal(casudp_startStopEvent); |
1841 | |
1842 | while (TRUE) { |
1843 | status = recvfrom ( |
1844 | - IOC_cast_sock, |
1845 | - prsrv_cast_client->recv.buf, |
1846 | - prsrv_cast_client->recv.maxstk, |
1847 | + recv_sock, |
1848 | + client->recv.buf, |
1849 | + client->recv.maxstk, |
1850 | 0, |
1851 | (struct sockaddr *)&new_recv_addr, |
1852 | &recv_addr_size); |
1853 | @@ -219,71 +180,82 @@ |
1854 | sockErrBuf); |
1855 | epicsThreadSleep(1.0); |
1856 | } |
1857 | + |
1858 | + } else { |
1859 | + size_t idx; |
1860 | + for(idx=0; casIgnoreAddrs[idx]; idx++) |
1861 | + { |
1862 | + if(new_recv_addr.sin_addr.s_addr==casIgnoreAddrs[idx]) { |
1863 | + status = -1; /* ignore */ |
1864 | + break; |
1865 | + } |
1866 | + } |
1867 | } |
1868 | - else if (casudp_ctl == ctlRun) { |
1869 | - prsrv_cast_client->recv.cnt = (unsigned) status; |
1870 | - prsrv_cast_client->recv.stk = 0ul; |
1871 | - epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv); |
1872 | - |
1873 | - prsrv_cast_client->minor_version_number = 0; |
1874 | - prsrv_cast_client->seqNoOfReq = 0; |
1875 | + |
1876 | + if (status >= 0 && casudp_ctl == ctlRun) { |
1877 | + client->recv.cnt = (unsigned) status; |
1878 | + client->recv.stk = 0ul; |
1879 | + epicsTimeGetCurrent(&client->time_at_last_recv); |
1880 | + |
1881 | + client->minor_version_number = 0; |
1882 | + client->seqNoOfReq = 0; |
1883 | |
1884 | /* |
1885 | * If we are talking to a new client flush to the old one |
1886 | * in case we are holding UDP messages waiting to |
1887 | * see if the next message is for this same client. |
1888 | */ |
1889 | - if (prsrv_cast_client->send.stk>sizeof(caHdr)) { |
1890 | - status = memcmp(&prsrv_cast_client->addr, |
1891 | + if (client->send.stk>sizeof(caHdr)) { |
1892 | + status = memcmp(&client->addr, |
1893 | &new_recv_addr, recv_addr_size); |
1894 | if(status){ |
1895 | /* |
1896 | * if the address is different |
1897 | */ |
1898 | - cas_send_dg_msg(prsrv_cast_client); |
1899 | - prsrv_cast_client->addr = new_recv_addr; |
1900 | + cas_send_dg_msg(client); |
1901 | + client->addr = new_recv_addr; |
1902 | } |
1903 | } |
1904 | else { |
1905 | - prsrv_cast_client->addr = new_recv_addr; |
1906 | + client->addr = new_recv_addr; |
1907 | } |
1908 | |
1909 | if (CASDEBUG>1) { |
1910 | char buf[40]; |
1911 | |
1912 | - ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); |
1913 | + ipAddrToDottedIP (&client->addr, buf, sizeof(buf)); |
1914 | errlogPrintf ("CAS: cast server msg of %d bytes from addr %s\n", |
1915 | - prsrv_cast_client->recv.cnt, buf); |
1916 | + client->recv.cnt, buf); |
1917 | } |
1918 | |
1919 | if (CASDEBUG>2) |
1920 | - count = ellCount (&prsrv_cast_client->chanList); |
1921 | + count = ellCount (&client->chanList); |
1922 | |
1923 | - status = camessage ( prsrv_cast_client ); |
1924 | + status = camessage ( client ); |
1925 | if(status == RSRV_OK){ |
1926 | - if(prsrv_cast_client->recv.cnt != |
1927 | - prsrv_cast_client->recv.stk){ |
1928 | + if(client->recv.cnt != |
1929 | + client->recv.stk){ |
1930 | char buf[40]; |
1931 | |
1932 | - ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); |
1933 | + ipAddrToDottedIP (&client->addr, buf, sizeof(buf)); |
1934 | |
1935 | epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n", |
1936 | - prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf); |
1937 | + client->recv.cnt-client->recv.stk, buf); |
1938 | } |
1939 | } |
1940 | else { |
1941 | char buf[40]; |
1942 | |
1943 | - ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); |
1944 | + ipAddrToDottedIP (&client->addr, buf, sizeof(buf)); |
1945 | |
1946 | epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf); |
1947 | } |
1948 | |
1949 | if (CASDEBUG>2) { |
1950 | - if ( ellCount (&prsrv_cast_client->chanList) ) { |
1951 | + if ( ellCount (&client->chanList) ) { |
1952 | errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n", |
1953 | - ellCount(&prsrv_cast_client->chanList)-count, |
1954 | - ellCount(&prsrv_cast_client->chanList)); |
1955 | + ellCount(&client->chanList)-count, |
1956 | + ellCount(&client->chanList)); |
1957 | } |
1958 | } |
1959 | } |
1960 | @@ -292,15 +264,22 @@ |
1961 | * allow messages to batch up if more are comming |
1962 | */ |
1963 | nchars = 0; /* supress purify warning */ |
1964 | - status = socket_ioctl(IOC_cast_sock, FIONREAD, &nchars); |
1965 | + status = socket_ioctl(recv_sock, FIONREAD, &nchars); |
1966 | if (status<0) { |
1967 | errlogPrintf ("CA cast server: Unable to fetch N characters pending\n"); |
1968 | - cas_send_dg_msg (prsrv_cast_client); |
1969 | - clean_addrq (); |
1970 | + cas_send_dg_msg (client); |
1971 | + clean_addrq (client); |
1972 | } |
1973 | else if (nchars == 0) { |
1974 | - cas_send_dg_msg (prsrv_cast_client); |
1975 | - clean_addrq (); |
1976 | + cas_send_dg_msg (client); |
1977 | + clean_addrq (client); |
1978 | } |
1979 | } |
1980 | + |
1981 | + /* ATM never reached, just a placeholder */ |
1982 | + |
1983 | + if(!mysocket) |
1984 | + client->sock = INVALID_SOCKET; /* only one cast_server should destroy the reply socket */ |
1985 | + destroy_client(client); |
1986 | + epicsSocketDestroy(recv_sock); |
1987 | } |
1988 | |
1989 | === modified file 'src/ioc/rsrv/online_notify.c' |
1990 | --- src/ioc/rsrv/online_notify.c 2014-10-06 05:57:02 +0000 |
1991 | +++ src/ioc/rsrv/online_notify.c 2016-02-25 16:34:00 +0000 |
1992 | @@ -36,45 +36,18 @@ |
1993 | #include "server.h" |
1994 | |
1995 | /* |
1996 | - * forcePort () |
1997 | - */ |
1998 | -static void forcePort (ELLLIST *pList, unsigned short port) |
1999 | -{ |
2000 | - osiSockAddrNode *pNode; |
2001 | - |
2002 | - pNode = (osiSockAddrNode *) ellFirst ( pList ); |
2003 | - while ( pNode ) { |
2004 | - if ( pNode->addr.sa.sa_family == AF_INET ) { |
2005 | - pNode->addr.ia.sin_port = htons ( port ); |
2006 | - } |
2007 | - pNode = (osiSockAddrNode *) ellNext ( &pNode->node ); |
2008 | - } |
2009 | -} |
2010 | - |
2011 | -/* |
2012 | * RSRV_ONLINE_NOTIFY_TASK |
2013 | */ |
2014 | void rsrv_online_notify_task(void *pParm) |
2015 | { |
2016 | - unsigned priorityOfSelf = epicsThreadGetPrioritySelf (); |
2017 | - osiSockAddrNode *pNode; |
2018 | double delay; |
2019 | double maxdelay; |
2020 | long longStatus; |
2021 | double maxPeriod; |
2022 | caHdr msg; |
2023 | int status; |
2024 | - SOCKET sock; |
2025 | - int intTrue = TRUE; |
2026 | - unsigned short port; |
2027 | ca_uint32_t beaconCounter = 0; |
2028 | - char * pStr; |
2029 | - int autoBeaconAddr; |
2030 | - ELLLIST autoAddrList; |
2031 | char buf[16]; |
2032 | - unsigned priorityOfUDP; |
2033 | - epicsThreadBooleanStatus tbs; |
2034 | - epicsThreadId tid; |
2035 | |
2036 | taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL); |
2037 | |
2038 | @@ -94,189 +67,34 @@ |
2039 | |
2040 | delay = 0.02; /* initial beacon period in sec */ |
2041 | maxdelay = maxPeriod; |
2042 | - |
2043 | - /* |
2044 | - * Open the socket. |
2045 | - * Use ARPA Internet address format and datagram socket. |
2046 | - * Format described in <sys/socket.h>. |
2047 | - */ |
2048 | - if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { |
2049 | - errlogPrintf ("CAS: online socket creation error\n"); |
2050 | - epicsThreadSuspendSelf (); |
2051 | - } |
2052 | - |
2053 | - status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, |
2054 | - (char *)&intTrue, sizeof(intTrue)); |
2055 | - if (status<0) { |
2056 | - errlogPrintf ("CAS: online socket set up error\n"); |
2057 | - epicsThreadSuspendSelf (); |
2058 | - } |
2059 | |
2060 | - { |
2061 | - /* |
2062 | - * this connect is to supress a warning message on Linux |
2063 | - * when we shutdown the read side of the socket. If it |
2064 | - * fails (and it will on old ip kernels) we just ignore |
2065 | - * the failure. |
2066 | - */ |
2067 | - osiSockAddr sockAddr; |
2068 | - sockAddr.ia.sin_family = AF_UNSPEC; |
2069 | - sockAddr.ia.sin_port = htons ( 0 ); |
2070 | - sockAddr.ia.sin_addr.s_addr = htonl (0); |
2071 | - connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) ); |
2072 | - shutdown ( sock, SHUT_RD ); |
2073 | - } |
2074 | - |
2075 | memset((char *)&msg, 0, sizeof msg); |
2076 | msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP); |
2077 | msg.m_count = htons (ca_server_port); |
2078 | msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION); |
2079 | - |
2080 | - ellInit ( & beaconAddrList ); |
2081 | - ellInit ( & autoAddrList ); |
2082 | - |
2083 | - pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf); |
2084 | - if ( ! pStr ) { |
2085 | - pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf); |
2086 | - } |
2087 | - if (pStr) { |
2088 | - if (strstr(pStr,"no")||strstr(pStr,"NO")) { |
2089 | - autoBeaconAddr = FALSE; |
2090 | - } |
2091 | - else if (strstr(pStr,"yes")||strstr(pStr,"YES")) { |
2092 | - autoBeaconAddr = TRUE; |
2093 | - } |
2094 | - else { |
2095 | - fprintf(stderr, |
2096 | - "CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr); |
2097 | - autoBeaconAddr = TRUE; |
2098 | - } |
2099 | - } |
2100 | - else { |
2101 | - autoBeaconAddr = TRUE; |
2102 | - } |
2103 | - |
2104 | - /* |
2105 | - * load user and auto configured |
2106 | - * broadcast address list |
2107 | - */ |
2108 | - if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) { |
2109 | - port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT, |
2110 | - (unsigned short) CA_REPEATER_PORT ); |
2111 | - } |
2112 | - else { |
2113 | - port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, |
2114 | - (unsigned short) CA_REPEATER_PORT ); |
2115 | - } |
2116 | - |
2117 | - /* |
2118 | - * discover beacon addresses associated with this interface |
2119 | - */ |
2120 | - if ( autoBeaconAddr ) { |
2121 | - osiSockAddr addr; |
2122 | - ELLLIST tmpList; |
2123 | - |
2124 | - ellInit ( &tmpList ); |
2125 | - addr.ia.sin_family = AF_UNSPEC; |
2126 | - osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr); |
2127 | - forcePort ( &tmpList, port ); |
2128 | - removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 ); |
2129 | - } |
2130 | - |
2131 | - /* |
2132 | - * by default use EPICS_CA_ADDR_LIST for the |
2133 | - * beacon address list |
2134 | - */ |
2135 | - { |
2136 | - const ENV_PARAM *pParam; |
2137 | - |
2138 | - if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) || |
2139 | - envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) { |
2140 | - pParam = &EPICS_CAS_BEACON_ADDR_LIST; |
2141 | - } |
2142 | - else { |
2143 | - pParam = &EPICS_CA_ADDR_LIST; |
2144 | - } |
2145 | - |
2146 | - /* |
2147 | - * add in the configured addresses |
2148 | - */ |
2149 | - addAddrToChannelAccessAddressList ( |
2150 | - &autoAddrList, pParam, port, pParam == &EPICS_CA_ADDR_LIST ); |
2151 | - } |
2152 | - |
2153 | - removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 ); |
2154 | - |
2155 | - if ( ellCount ( &beaconAddrList ) == 0 ) { |
2156 | - errlogPrintf ("The CA server's beacon address list was empty after initialization?\n"); |
2157 | - } |
2158 | - |
2159 | -# ifdef DEBUG |
2160 | - printChannelAccessAddressList (&beaconAddrList); |
2161 | -# endif |
2162 | - |
2163 | - tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP ); |
2164 | - if ( tbs != epicsThreadBooleanStatusSuccess ) { |
2165 | - priorityOfUDP = priorityOfSelf; |
2166 | - } |
2167 | - |
2168 | - casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty); |
2169 | - casudp_ctl = ctlPause; |
2170 | - |
2171 | - tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP, |
2172 | - epicsThreadGetStackSize (epicsThreadStackMedium), |
2173 | - cast_server, 0 ); |
2174 | - if ( tid == 0 ) { |
2175 | - epicsPrintf ( "CAS: unable to start UDP daemon thread\n" ); |
2176 | - } |
2177 | - |
2178 | - epicsEventMustWait(casudp_startStopEvent); |
2179 | + |
2180 | + |
2181 | epicsEventSignal(beacon_startStopEvent); |
2182 | |
2183 | while (TRUE) { |
2184 | - pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList); |
2185 | - while (pNode) { |
2186 | - char buf[64]; |
2187 | + ELLNODE *cur; |
2188 | |
2189 | - status = connect (sock, &pNode->addr.sa, |
2190 | - sizeof(pNode->addr.sa)); |
2191 | - if (status<0) { |
2192 | + /* send beacon to each interface */ |
2193 | + for(cur=ellFirst(&beaconAddrList); cur; cur=ellNext(cur)) |
2194 | + { |
2195 | + osiSockAddrNode *pAddr = CONTAINER(cur, osiSockAddrNode, node); |
2196 | + status = sendto (beaconSocket, (char *)&msg, sizeof(msg), 0, |
2197 | + &pAddr->addr.sa, sizeof(pAddr->addr)); |
2198 | + if (status < 0) { |
2199 | char sockErrBuf[64]; |
2200 | - epicsSocketConvertErrnoToString ( |
2201 | - sockErrBuf, sizeof ( sockErrBuf ) ); |
2202 | - ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf)); |
2203 | - errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n", |
2204 | + epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); |
2205 | + ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf)); |
2206 | + errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n", |
2207 | __FILE__, buf, sockErrBuf); |
2208 | } |
2209 | else { |
2210 | - struct sockaddr_in if_addr; |
2211 | - |
2212 | - osiSocklen_t size = sizeof (if_addr); |
2213 | - status = getsockname (sock, (struct sockaddr *) &if_addr, &size); |
2214 | - if (status<0) { |
2215 | - char sockErrBuf[64]; |
2216 | - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); |
2217 | - errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n", |
2218 | - __FILE__, sockErrBuf); |
2219 | - } |
2220 | - else if (if_addr.sin_family==AF_INET) { |
2221 | - msg.m_available = if_addr.sin_addr.s_addr; |
2222 | - msg.m_cid = htonl ( beaconCounter ); |
2223 | - |
2224 | - status = send (sock, (char *)&msg, sizeof(msg), 0); |
2225 | - if (status < 0) { |
2226 | - char sockErrBuf[64]; |
2227 | - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); |
2228 | - ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf)); |
2229 | - errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n", |
2230 | - __FILE__, buf, sockErrBuf); |
2231 | - } |
2232 | - else { |
2233 | - assert (status == sizeof(msg)); |
2234 | - } |
2235 | - } |
2236 | + assert (status == sizeof(msg)); |
2237 | } |
2238 | - pNode = (osiSockAddrNode *) pNode->node.next; |
2239 | } |
2240 | |
2241 | epicsThreadSleep(delay); |
2242 | @@ -287,7 +105,7 @@ |
2243 | } |
2244 | } |
2245 | |
2246 | - beaconCounter++; /* expected to overflow */ |
2247 | + msg.m_cid = htonl ( beaconCounter++ ); /* expected to overflow */ |
2248 | |
2249 | while (beacon_ctl == ctlPause) { |
2250 | epicsThreadSleep(0.1); |
2251 | |
2252 | === modified file 'src/ioc/rsrv/server.h' |
2253 | --- src/ioc/rsrv/server.h 2014-03-06 21:55:13 +0000 |
2254 | +++ src/ioc/rsrv/server.h 2016-02-25 16:34:00 +0000 |
2255 | @@ -32,6 +32,7 @@ |
2256 | #include "ellLib.h" |
2257 | #include "epicsTime.h" |
2258 | #include "epicsAssert.h" |
2259 | +#include "osiSock.h" |
2260 | |
2261 | #ifdef rsrvRestore_epicsExportSharedSymbols |
2262 | #define epicsExportSharedSymbols |
2263 | @@ -88,7 +89,7 @@ |
2264 | char *pUserName; |
2265 | char *pHostName; |
2266 | epicsEventId blockSem; /* used whenever the client blocks */ |
2267 | - SOCKET sock; |
2268 | + SOCKET sock, udpRecv; |
2269 | int proto; |
2270 | epicsThreadId tid; |
2271 | unsigned minor_version_number; |
2272 | @@ -137,6 +138,16 @@ |
2273 | char modified; /* mod & ev flw ctrl enbl */ |
2274 | }; |
2275 | |
2276 | +typedef struct { |
2277 | + ELLNODE node; |
2278 | + osiSockAddr tcpAddr, /* TCP listener endpoint */ |
2279 | + udpAddr, /* UDP name unicast receiver endpoint */ |
2280 | + udpbcastAddr; /* UDP name broadcast receiver endpoint */ |
2281 | + SOCKET tcp, udp, udpbcast; |
2282 | + struct client *client, *bclient; |
2283 | + |
2284 | + unsigned int startbcast:1; |
2285 | +} rsrv_iface_config; |
2286 | |
2287 | enum ctl {ctlInit, ctlRun, ctlPause, ctlExit}; |
2288 | |
2289 | @@ -160,15 +171,16 @@ |
2290 | #endif |
2291 | |
2292 | GLBLTYPE int CASDEBUG; |
2293 | -GLBLTYPE SOCKET IOC_sock; |
2294 | -GLBLTYPE SOCKET IOC_cast_sock; |
2295 | -GLBLTYPE unsigned short ca_server_port; |
2296 | -GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */ |
2297 | +GLBLTYPE unsigned short ca_server_port, ca_udp_port, ca_beacon_port; |
2298 | +GLBLTYPE ELLLIST clientQ; /* (TCP clients) locked by clientQlock */ |
2299 | +GLBLTYPE ELLLIST clientQudp; /* locked by clientQlock */ |
2300 | +GLBLTYPE ELLLIST servers; /* rsrv_iface_config::node, read-only after rsrv_init() */ |
2301 | GLBLTYPE ELLLIST beaconAddrList; |
2302 | -GLBLTYPE ELLLIST casIntfAddrList; |
2303 | +GLBLTYPE SOCKET beaconSocket; |
2304 | +GLBLTYPE ELLLIST casIntfAddrList, casMCastAddrList; |
2305 | +GLBLTYPE epicsUInt32 *casIgnoreAddrs; |
2306 | GLBLTYPE epicsMutexId clientQlock; |
2307 | -GLBLTYPE struct client *prsrv_cast_client; |
2308 | -GLBLTYPE BUCKET *pCaBucket; |
2309 | +GLBLTYPE BUCKET *pCaBucket; /* locked by clientQlock */ |
2310 | GLBLTYPE void *rsrvClientFreeList; |
2311 | GLBLTYPE void *rsrvChanFreeList; |
2312 | GLBLTYPE void *rsrvEventFreeList; |
2313 | @@ -176,7 +188,7 @@ |
2314 | GLBLTYPE void *rsrvLargeBufFreeListTCP; |
2315 | GLBLTYPE unsigned rsrvSizeofLargeBufTCP; |
2316 | GLBLTYPE void *rsrvPutNotifyFreeList; |
2317 | -GLBLTYPE unsigned rsrvChannelCount; |
2318 | +GLBLTYPE unsigned rsrvChannelCount; /* locked by clientQlock */ |
2319 | |
2320 | GLBLTYPE epicsEventId casudp_startStopEvent; |
2321 | GLBLTYPE epicsEventId beacon_startStopEvent; |
2322 | @@ -185,6 +197,7 @@ |
2323 | GLBLTYPE volatile enum ctl beacon_ctl; |
2324 | GLBLTYPE volatile enum ctl castcp_ctl; |
2325 | |
2326 | +GLBLTYPE unsigned int threadPrios[5]; |
2327 | |
2328 | #define CAS_HASH_TABLE_SIZE 4096 |
2329 | |
2330 | |
2331 | === modified file 'src/libCom/bucketLib/bucketLib.c' |
2332 | --- src/libCom/bucketLib/bucketLib.c 2014-08-25 21:27:18 +0000 |
2333 | +++ src/libCom/bucketLib/bucketLib.c 2016-02-25 16:34:00 +0000 |
2334 | @@ -486,7 +486,7 @@ |
2335 | unsigned count; |
2336 | unsigned maxEntries; |
2337 | |
2338 | - printf( "Bucket entries in use = %d bytes in use = %ld\n", |
2339 | + printf( " Bucket entries in use = %d bytes in use = %ld\n", |
2340 | pb->nInUse, |
2341 | (long) (sizeof(*pb)+(pb->hashIdMask+1)* |
2342 | sizeof(ITEM *)+pb->nInUse*sizeof(ITEM))); |
2343 | @@ -511,7 +511,7 @@ |
2344 | |
2345 | mean = X/nElem; |
2346 | stdDev = sqrt(XX/nElem - mean*mean); |
2347 | - printf( "Bucket entries/hash id - mean = %f std dev = %f max = %d\n", |
2348 | + printf( " Bucket entries/hash id - mean = %f std dev = %f max = %d\n", |
2349 | mean, |
2350 | stdDev, |
2351 | maxEntries); |
2352 | |
2353 | === modified file 'src/libCom/env/envDefs.h' |
2354 | --- src/libCom/env/envDefs.h 2010-10-05 19:27:37 +0000 |
2355 | +++ src/libCom/env/envDefs.h 2016-02-25 16:34:00 +0000 |
2356 | @@ -88,6 +88,8 @@ |
2357 | envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong); |
2358 | epicsShareFunc unsigned short epicsShareAPI envGetInetPortConfigParam |
2359 | (const ENV_PARAM *pEnv, unsigned short defaultPort); |
2360 | +epicsShareFunc long epicsShareAPI |
2361 | + envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool); |
2362 | epicsShareFunc long epicsShareAPI epicsPrtEnvParams(void); |
2363 | epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value); |
2364 | epicsShareFunc void epicsShareAPI epicsEnvShow (const char *name); |
2365 | |
2366 | === modified file 'src/libCom/env/envSubr.c' |
2367 | --- src/libCom/env/envSubr.c 2012-05-03 17:19:34 +0000 |
2368 | +++ src/libCom/env/envSubr.c 2016-02-25 16:34:00 +0000 |
2369 | @@ -43,6 +43,7 @@ |
2370 | #define epicsExportSharedSymbols |
2371 | #include "epicsStdlib.h" |
2372 | #include "epicsStdio.h" |
2373 | +#include "epicsString.h" |
2374 | #include "errMdef.h" |
2375 | #include "errlog.h" |
2376 | #include "envDefs.h" |
2377 | @@ -319,7 +320,19 @@ |
2378 | } |
2379 | return -1; |
2380 | } |
2381 | - |
2382 | |
2383 | + |
2384 | + |
2385 | +long epicsShareAPI |
2386 | +envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool) |
2387 | +{ |
2388 | + char text[20]; |
2389 | + |
2390 | + if(!envGetConfigParam(pParam, sizeof(text), text)) |
2391 | + return -1; |
2392 | + *pBool = epicsStrCaseCmp(text, "yes")==0; |
2393 | + return 0; |
2394 | +} |
2395 | + |
2396 | /*+/subr********************************************************************** |
2397 | * NAME envPrtConfigParam - print value of a configuration parameter |
2398 | * |
2399 | |
2400 | === modified file 'src/libCom/osi/os/Darwin/osdSock.h' |
2401 | --- src/libCom/osi/os/Darwin/osdSock.h 2011-09-09 22:14:35 +0000 |
2402 | +++ src/libCom/osi/os/Darwin/osdSock.h 2016-02-25 16:34:00 +0000 |
2403 | @@ -41,6 +41,7 @@ |
2404 | #define SOCK_ECONNRESET ECONNRESET |
2405 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2406 | #define SOCK_EADDRINUSE EADDRINUSE |
2407 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2408 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2409 | #define SOCK_ECONNABORTED ECONNABORTED |
2410 | #define SOCK_EINPROGRESS EINPROGRESS |
2411 | |
2412 | === modified file 'src/libCom/osi/os/Linux/osdSock.h' |
2413 | --- src/libCom/osi/os/Linux/osdSock.h 2014-09-08 22:57:18 +0000 |
2414 | +++ src/libCom/osi/os/Linux/osdSock.h 2016-02-25 16:34:00 +0000 |
2415 | @@ -43,6 +43,7 @@ |
2416 | #define SOCK_ECONNRESET ECONNRESET |
2417 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2418 | #define SOCK_EADDRINUSE EADDRINUSE |
2419 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2420 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2421 | #define SOCK_ECONNABORTED ECONNABORTED |
2422 | #define SOCK_EINPROGRESS EINPROGRESS |
2423 | |
2424 | === modified file 'src/libCom/osi/os/RTEMS/osdSock.h' |
2425 | --- src/libCom/osi/os/RTEMS/osdSock.h 2011-09-09 22:14:35 +0000 |
2426 | +++ src/libCom/osi/os/RTEMS/osdSock.h 2016-02-25 16:34:00 +0000 |
2427 | @@ -51,6 +51,7 @@ |
2428 | #define SOCK_ECONNRESET ECONNRESET |
2429 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2430 | #define SOCK_EADDRINUSE EADDRINUSE |
2431 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2432 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2433 | #define SOCK_ECONNABORTED ECONNABORTED |
2434 | #define SOCK_EINPROGRESS EINPROGRESS |
2435 | |
2436 | === modified file 'src/libCom/osi/os/WIN32/osdSock.h' |
2437 | --- src/libCom/osi/os/WIN32/osdSock.h 2011-09-09 22:14:35 +0000 |
2438 | +++ src/libCom/osi/os/WIN32/osdSock.h 2016-02-25 16:34:00 +0000 |
2439 | @@ -21,7 +21,7 @@ |
2440 | # define WIN32 |
2441 | #endif |
2442 | #include <winsock2.h> |
2443 | - |
2444 | +#include <ws2tcpip.h> |
2445 | |
2446 | #define SOCKERRNO WSAGetLastError() |
2447 | |
2448 | @@ -49,6 +49,7 @@ |
2449 | #define SOCK_ECONNRESET WSAECONNRESET |
2450 | #define SOCK_ETIMEDOUT WSAETIMEDOUT |
2451 | #define SOCK_EADDRINUSE WSAEADDRINUSE |
2452 | +#define SOCK_EADDRNOTAVAIL WSAEADDRNOTAVAIL |
2453 | #define SOCK_ECONNREFUSED WSAECONNREFUSED |
2454 | #define SOCK_ECONNABORTED WSAECONNABORTED |
2455 | #define SOCK_EINPROGRESS WSAEINPROGRESS |
2456 | |
2457 | === modified file 'src/libCom/osi/os/cygwin32/osdSock.h' |
2458 | --- src/libCom/osi/os/cygwin32/osdSock.h 2015-04-29 19:01:07 +0000 |
2459 | +++ src/libCom/osi/os/cygwin32/osdSock.h 2016-02-25 16:34:00 +0000 |
2460 | @@ -50,6 +50,7 @@ |
2461 | #define SOCK_ECONNRESET ECONNRESET |
2462 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2463 | #define SOCK_EADDRINUSE EADDRINUSE |
2464 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2465 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2466 | #define SOCK_ECONNABORTED ECONNABORTED |
2467 | #define SOCK_EINPROGRESS EINPROGRESS |
2468 | |
2469 | === modified file 'src/libCom/osi/os/default/osdNetIntf.c' |
2470 | --- src/libCom/osi/os/default/osdNetIntf.c 2014-06-11 04:37:21 +0000 |
2471 | +++ src/libCom/osi/os/default/osdNetIntf.c 2016-02-25 16:34:00 +0000 |
2472 | @@ -54,7 +54,7 @@ |
2473 | struct ifreq *ifr; |
2474 | |
2475 | ifr = ( struct ifreq * )( ifreqSize (pifreq) + ( char * ) pifreq ); |
2476 | - ifDepenDebugPrintf( ("ifreqNext() pifreq 0x%08x, size 0x%08x, ifr 0x%08x\n", pifreq, ifreqSize (pifreq), ifr) ); |
2477 | + ifDepenDebugPrintf( ("ifreqNext() pifreq %p, size 0x%x, ifr 0x%p\n", pifreq, (unsigned)ifreqSize (pifreq), ifr) ); |
2478 | return ifr; |
2479 | } |
2480 | |
2481 | @@ -73,21 +73,6 @@ |
2482 | struct ifreq *pifreq; |
2483 | struct ifreq *pnextifreq; |
2484 | osiSockAddrNode *pNewNode; |
2485 | - |
2486 | - if ( pMatchAddr->sa.sa_family == AF_INET ) { |
2487 | - if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) { |
2488 | - pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); |
2489 | - if ( pNewNode == NULL ) { |
2490 | - errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); |
2491 | - return; |
2492 | - } |
2493 | - pNewNode->addr.ia.sin_family = AF_INET; |
2494 | - pNewNode->addr.ia.sin_port = htons ( 0 ); |
2495 | - pNewNode->addr.ia.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
2496 | - ellAdd ( pList, &pNewNode->node ); |
2497 | - return; |
2498 | - } |
2499 | - } |
2500 | |
2501 | /* |
2502 | * use pool so that we avoid using too much stack space |
2503 | @@ -105,8 +90,7 @@ |
2504 | ifconf.ifc_req = pIfreqList; |
2505 | status = socket_ioctl (socket, SIOCGIFCONF, &ifconf); |
2506 | if (status < 0 || ifconf.ifc_len == 0) { |
2507 | - ifDepenDebugPrintf(("osiSockDiscoverBroadcastAddresses(): status: 0x08x, ifconf.ifc_len: %d\n", status, ifconf.ifc_len)); |
2508 | - errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration\n"); |
2509 | + errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration (%d)\n", status); |
2510 | free (pIfreqList); |
2511 | return; |
2512 | } |
2513 | @@ -116,6 +100,7 @@ |
2514 | |
2515 | for ( pifreq = pIfreqList; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) { |
2516 | uint32_t current_ifreqsize; |
2517 | + struct sockaddr_in if_addr; |
2518 | |
2519 | /* |
2520 | * find the next ifreq |
2521 | @@ -129,8 +114,8 @@ |
2522 | |
2523 | ifDepenDebugPrintf (("osiSockDiscoverBroadcastAddresses(): found IFACE: %s len: 0x%x current_ifreqsize: 0x%x \n", |
2524 | pIfreqList->ifr_name, |
2525 | - ifreq_size(pifreq), |
2526 | - current_ifreqsize)); |
2527 | + (unsigned)ifreq_size(pifreq), |
2528 | + (unsigned)current_ifreqsize)); |
2529 | |
2530 | /* |
2531 | * If its not an internet interface then dont use it |
2532 | @@ -139,6 +124,7 @@ |
2533 | ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): interface \"%s\" was not AF_INET\n", pIfreqList->ifr_name) ); |
2534 | continue; |
2535 | } |
2536 | + if_addr = *(struct sockaddr_in *)&pIfreqList->ifr_addr; |
2537 | |
2538 | /* |
2539 | * if it isnt a wildcarded interface then look for |
2540 | @@ -149,8 +135,7 @@ |
2541 | continue; |
2542 | } |
2543 | if ( pMatchAddr->ia.sin_addr.s_addr != htonl (INADDR_ANY) ) { |
2544 | - struct sockaddr_in *pInetAddr = (struct sockaddr_in *) &pIfreqList->ifr_addr; |
2545 | - if ( pInetAddr->sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) { |
2546 | + if ( if_addr.sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) { |
2547 | ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" didnt match\n", pIfreqList->ifr_name) ); |
2548 | continue; |
2549 | } |
2550 | @@ -171,14 +156,6 @@ |
2551 | continue; |
2552 | } |
2553 | |
2554 | - /* |
2555 | - * dont use the loop back interface |
2556 | - */ |
2557 | - if ( pIfreqList->ifr_flags & IFF_LOOPBACK ) { |
2558 | - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): ignoring loopback interface: \"%s\"\n", pIfreqList->ifr_name) ); |
2559 | - continue; |
2560 | - } |
2561 | - |
2562 | pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); |
2563 | if ( pNewNode == NULL ) { |
2564 | errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); |
2565 | @@ -217,6 +194,22 @@ |
2566 | pNewNode->addr.sa = pIfreqList->ifr_dstaddr; |
2567 | } |
2568 | #endif |
2569 | +#if defined(__linux__) |
2570 | + /* On Linux, even though the 'lo' interface doesn't set IFF_BROADCAST |
2571 | + * a broadcast route often exists. Assume that sending to 127.255.255.255 |
2572 | + * reaches all local listeners. |
2573 | + * |
2574 | + * $ ip route show table local scope link dev lo |
2575 | + * broadcast 127.0.0.0 proto kernel src 127.0.0.1 |
2576 | + * broadcast 127.255.255.255 proto kernel src 127.0.0.1 |
2577 | + */ |
2578 | + else if ( pIfreqList->ifr_flags & IFF_LOOPBACK && if_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK) ) { |
2579 | + memset(&pNewNode->addr.ia, 0, sizeof(pNewNode->addr.ia)); |
2580 | + pNewNode->addr.ia.sin_family = AF_INET; |
2581 | + pNewNode->addr.ia.sin_addr.s_addr = htonl(0x7fffffff); |
2582 | + ifDepenDebugPrintf ( ( "assume loopback broadcast addr = %x\n", ntohl ( pNewNode->addr.ia.sin_addr.s_addr ) ) ); |
2583 | + } |
2584 | +#endif |
2585 | else { |
2586 | ifDepenDebugPrintf ( ( "osiSockDiscoverBroadcastAddresses(): net intf \"%s\": not point to point or bcast?\n", pIfreqList->ifr_name ) ); |
2587 | free ( pNewNode ); |
2588 | |
2589 | === modified file 'src/libCom/osi/os/freebsd/osdSock.h' |
2590 | --- src/libCom/osi/os/freebsd/osdSock.h 2011-09-09 22:14:35 +0000 |
2591 | +++ src/libCom/osi/os/freebsd/osdSock.h 2016-02-25 16:34:00 +0000 |
2592 | @@ -44,6 +44,7 @@ |
2593 | #define SOCK_ECONNRESET ECONNRESET |
2594 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2595 | #define SOCK_EADDRINUSE EADDRINUSE |
2596 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2597 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2598 | #define SOCK_ECONNABORTED ECONNABORTED |
2599 | #define SOCK_EINPROGRESS EINPROGRESS |
2600 | |
2601 | === modified file 'src/libCom/osi/os/iOS/osdSock.h' |
2602 | --- src/libCom/osi/os/iOS/osdSock.h 2011-09-09 22:14:35 +0000 |
2603 | +++ src/libCom/osi/os/iOS/osdSock.h 2016-02-25 16:34:00 +0000 |
2604 | @@ -42,6 +42,7 @@ |
2605 | #define SOCK_ECONNRESET ECONNRESET |
2606 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2607 | #define SOCK_EADDRINUSE EADDRINUSE |
2608 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2609 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2610 | #define SOCK_ECONNABORTED ECONNABORTED |
2611 | #define SOCK_EINPROGRESS EINPROGRESS |
2612 | |
2613 | === modified file 'src/libCom/osi/os/solaris/osdSock.h' |
2614 | --- src/libCom/osi/os/solaris/osdSock.h 2011-09-09 22:14:35 +0000 |
2615 | +++ src/libCom/osi/os/solaris/osdSock.h 2016-02-25 16:34:00 +0000 |
2616 | @@ -52,6 +52,7 @@ |
2617 | #define SOCK_ECONNRESET ECONNRESET |
2618 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2619 | #define SOCK_EADDRINUSE EADDRINUSE |
2620 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2621 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2622 | #define SOCK_ECONNABORTED ECONNABORTED |
2623 | #define SOCK_EINPROGRESS EINPROGRESS |
2624 | |
2625 | === modified file 'src/libCom/osi/os/vxWorks/osdSock.h' |
2626 | --- src/libCom/osi/os/vxWorks/osdSock.h 2011-09-20 18:07:52 +0000 |
2627 | +++ src/libCom/osi/os/vxWorks/osdSock.h 2016-02-25 16:34:00 +0000 |
2628 | @@ -73,6 +73,7 @@ |
2629 | #define SOCK_ECONNRESET ECONNRESET |
2630 | #define SOCK_ETIMEDOUT ETIMEDOUT |
2631 | #define SOCK_EADDRINUSE EADDRINUSE |
2632 | +#define SOCK_EADDRNOTAVAIL EADDRNOTAVAIL |
2633 | #define SOCK_ECONNREFUSED ECONNREFUSED |
2634 | #define SOCK_ECONNABORTED ECONNABORTED |
2635 | #define SOCK_EINPROGRESS EINPROGRESS |
2636 | |
2637 | === modified file 'src/std/filters/arr.c' |
2638 | --- src/std/filters/arr.c 2014-09-30 14:19:13 +0000 |
2639 | +++ src/std/filters/arr.c 2016-02-25 16:34:00 +0000 |
2640 | @@ -182,7 +182,7 @@ |
2641 | static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent) |
2642 | { |
2643 | myStruct *my = (myStruct*) pvt; |
2644 | - printf("%*s plugin arr, start=%d, incr=%d, end=%d\n", indent, "", |
2645 | + printf("%*sArray (arr): start=%d, incr=%d, end=%d\n", indent, "", |
2646 | my->start, my->incr, my->end); |
2647 | } |
2648 | |
2649 | |
2650 | === modified file 'src/std/filters/dbnd.c' |
2651 | --- src/std/filters/dbnd.c 2014-08-28 18:24:48 +0000 |
2652 | +++ src/std/filters/dbnd.c 2016-02-25 16:34:00 +0000 |
2653 | @@ -102,7 +102,7 @@ |
2654 | static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent) |
2655 | { |
2656 | myStruct *my = (myStruct*) pvt; |
2657 | - printf("%*s plugin dbnd, mode=%s, delta=%g%s\n", indent, "", |
2658 | + printf("%*sDeadband (dbnd): mode=%s, delta=%g%s\n", indent, "", |
2659 | chfPluginEnumString(modeEnum, my->mode, "n/a"), my->cval, |
2660 | my->mode == 1 ? "%" : ""); |
2661 | } |
2662 | |
2663 | === modified file 'src/std/filters/sync.c' |
2664 | --- src/std/filters/sync.c 2014-10-03 19:23:04 +0000 |
2665 | +++ src/std/filters/sync.c 2016-02-25 16:34:00 +0000 |
2666 | @@ -156,7 +156,7 @@ |
2667 | static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent) |
2668 | { |
2669 | myStruct *my = (myStruct*) pvt; |
2670 | - printf("%*s plugin sync, mode=%s, state=%s\n", indent, "", |
2671 | + printf("%*sSynchronize (sync): mode=%s, state=%s\n", indent, "", |
2672 | chfPluginEnumString(modeEnum, my->mode, "n/a"), my->state); |
2673 | } |
2674 | |
2675 | |
2676 | === modified file 'src/std/filters/ts.c' |
2677 | --- src/std/filters/ts.c 2012-07-17 19:33:31 +0000 |
2678 | +++ src/std/filters/ts.c 2016-02-25 16:34:00 +0000 |
2679 | @@ -40,7 +40,7 @@ |
2680 | |
2681 | static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent) |
2682 | { |
2683 | - printf("%*s plugin ts\n", indent, ""); |
2684 | + printf("%*sTimestamp (ts)\n", indent, ""); |
2685 | } |
2686 | |
2687 | static chfPluginIf pif = { |
Needs compatibility testing