Difference between revisions of "CA over TCP"
RalphLange (talk | contribs) m |
RalphLange (talk | contribs) (Adde status section with links to Launchpad) |
||
(16 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
: ''[[User:JeffHill|Jeff Hill]] and [[User:RalphLange|Ralph Lange]], Codeathon 2008'' | : ''Initial changes: [[User:JeffHill|Jeff Hill]] and [[User:RalphLange|Ralph Lange]], Codeathon 2008'' | ||
: ''Rebase/merge to 3.14 and additional fixes: [[User:RalphLange|Ralph Lange]], April 2010'' | |||
: (This refers to the [[User:AndrewJohnson/V3_Evolution#CA_over_TCP| CA over TCP]] topic of Andrew's project list.) | : (This refers to the [[User:AndrewJohnson/V3_Evolution#CA_over_TCP| CA over TCP]] topic of Andrew's project list.) | ||
Line 13: | Line 14: | ||
=== Beacons === | === Beacons === | ||
We are just ignoring the beacon topic for the time being. With the current EPICS release, CA clients do not raise the search interval above a certain limit. Even without beacon anomalies being detected, all unresolved channels will connect sooner or later. That should be good enough for a start. | We are just ignoring the beacon topic for the time being. With the current EPICS release, CA clients do not raise the search interval above a certain limit. Even without beacon anomalies being detected, all unresolved channels will connect sooner or later. That should be good enough for a start. | ||
A possible implementation would be a client-side caRepeater which connects through a 5065/TCP connection to a server-side caRepeater. That way neither client nor server code would have to be changed. | |||
=== Name Resolution === | === Name Resolution === | ||
A new environment variable EPICS_CA_NAME_SERVERS will be used to configure TCP name resolution. This variable takes a list of IP addresses. The client will open regular TCP connections (default port 5064) to those servers at init time and issue name resolution requests over TCP in addition to issuing the UDP requests to addresses in EPICS_CA_ADDR_LIST. | A new environment variable EPICS_CA_NAME_SERVERS will be used to configure TCP name resolution. This variable takes a list of IP addresses. The client will open regular TCP connections (default port 5064) to those servers at init time and issue name resolution requests over TCP in addition to issuing the UDP requests to addresses in EPICS_CA_ADDR_LIST. | ||
The | The CA server will be changed to forward the name resolution requests coming from TCP directly to the server tool. | ||
Servers that are not capable of handling name requests over TCP (e.g. older rsrv or CAS version) will be ignored, i.e. the client will not see the requested channels through TCP and not connect unless a different (name) server answers the request. | |||
== List of Necessary Changes == | == List of Necessary Changes == | ||
Line 37: | Line 40: | ||
*** restarts the send thread | *** restarts the send thread | ||
*** exits | *** exits | ||
** | ** class deriving from SearchDest called SearchDestTCP | ||
** private member of type | ** private member of type SearchDestTCP called _searchDest | ||
** implement code calling Callback :: notify () when resp to search request arrives | ** implement code calling Callback :: notify () when resp to search request arrives | ||
** implement SearchDest :: searchRequest () that issues a tcp search request if server is capable, else directly calls the Callback :: notify () | ** implement friend SearchDest::searchRequest () that issues a tcp search request if server is capable, else directly calls the Callback::notify () | ||
* udpiiu changes | * udpiiu changes | ||
** private member class deriving from SearchDest called | ** private member class deriving from SearchDest called SearchDestUDP | ||
*** instances on the search list | *** instances on the search list | ||
** private member class deriving from SearchDest :: Callback called | ** private member class deriving from SearchDest :: Callback called SearchRespCallback | ||
*** implement | *** implement SearchRespCallback :: notify () | ||
** implement code calling Callback :: notify () when resp to search request arrives | ** implement code calling Callback :: notify () when resp to search request arrives | ||
** build udp search dest objects | ** build udp search dest objects | ||
Line 58: | Line 61: | ||
* cac changes | * cac changes | ||
** code parsing EPICS_CA_NAME_SERVERS (in constructor | ** code parsing EPICS_CA_NAME_SERVERS (in constructor) | ||
** creates tcpiiu specifying | ** creates SearchDestTCP and adds it to the search list | ||
** creates tcpiiu specifying the SeachDestTCP to its constructor | |||
** add public register/unregister SearchDest to cac (called by tcpiiu const and dest) | ** add public register/unregister SearchDest to cac (called by tcpiiu const and dest) | ||
** in destructor guarantee that udpiiu is shutdown prior to deleting nameService tcpiiu | ** in destructor guarantee that udpiiu is shutdown prior to deleting nameService tcpiiu | ||
=== CAS === | === CAS === | ||
''to | * casStrmClient changes | ||
** add private client addr member (init'd through constructor arg) | |||
** add casStrmClient::searchAction that does roughly the same as the casDGClient::searchAction ''(maybe this could be refactored and moved to a separate name resolver class to avoid code repetition)'' | |||
** add casStrmClient::asyncSearchResponse and casStrmClient::searchResponse ''(again: same as casDGClient methods)'' | |||
* casStreamIO changes | |||
** add private client address member | |||
** add public methods to get client host name and address | |||
=== rsrv === | === rsrv === | ||
* camessage.c changes | |||
** rename search_reply() to search_reply_udp() | |||
** add search_reply_tcp() with similar functionality | |||
** change jump table accordingly | |||
== Issues == | |||
=== ''Fixed:'' TCP Nameserver Connections Do Not Reconnect === | |||
When a TCP nameserver connection goes away (e.g. if the nameserver dies), the client does not reconnect when the connection comes back (e.g. the nameserver is restarted). | |||
''Fix (2010-04-09):'' The private member SearchDestTCP::_addr must be an osiSockAddr, not a reference to it. The constructor cac::cac() frees the list of destinations after creating the SearchDestTCP instances. The SearchDestTCP couldn't reconnect, because it had lost the target address. | |||
=== ''Fixed:'' TCP Nameserver Connection Down Blocks All Callbacks === | |||
When a TCP nameserver connection goes away (e.g. if the nameserver dies), the client's TCP receive thread tries to reconnect in an endless loop, doing a epicsThreadSleep(cac.connectionTimeout) between attempts. | |||
While the receive thread is sleeping, no other CA callbacks are executed. | |||
''Fix: (2010-04-15)'' tcpRecvThread::connect() holds the cac mutex lock. That lock must be released during the epicsThreadSleep(). | |||
== Status == | |||
The original changes (against 3.15 aka CVS trunk) have been pulled out and merged into a development branch. | |||
Development branch: https://code.launchpad.net/~ralph-lange/epics-base/ca-over-tcp | |||
Blueprint: https://blueprints.launchpad.net/epics-base/+spec/ca-over-tcp |
Latest revision as of 20:55, 15 April 2010
- Initial changes: Jeff Hill and Ralph Lange, Codeathon 2008
- Rebase/merge to 3.14 and additional fixes: Ralph Lange, April 2010
- (This refers to the CA over TCP topic of Andrew's project list.)
Goal
Provide a way to run CA on TCP circuits. Intended use: Run CA clients remotely that use an ssh tunnel to safely and securely connect to the control system. For security reasons these tunneled connections should connect to a CA Gateway.
Approach
TCP connections can easily be tunneled through ssh. To allow CA connections through a TCP tunnel, the use of UDP (currently for name resolution and server beacons) must be avoided.
Beacons
We are just ignoring the beacon topic for the time being. With the current EPICS release, CA clients do not raise the search interval above a certain limit. Even without beacon anomalies being detected, all unresolved channels will connect sooner or later. That should be good enough for a start.
A possible implementation would be a client-side caRepeater which connects through a 5065/TCP connection to a server-side caRepeater. That way neither client nor server code would have to be changed.
Name Resolution
A new environment variable EPICS_CA_NAME_SERVERS will be used to configure TCP name resolution. This variable takes a list of IP addresses. The client will open regular TCP connections (default port 5064) to those servers at init time and issue name resolution requests over TCP in addition to issuing the UDP requests to addresses in EPICS_CA_ADDR_LIST.
The CA server will be changed to forward the name resolution requests coming from TCP directly to the server tool.
Servers that are not capable of handling name requests over TCP (e.g. older rsrv or CAS version) will be ignored, i.e. the client will not see the requested channels through TCP and not connect unless a different (name) server answers the request.
List of Necessary Changes
CA Client
- tcpiiu changes
- add bool _nameService private member data flag
- pass bool nameService arg to tcpiiu constructor (setting private bool flag)
- if _nameService, constructor registers member SearchDest with cac
- if _nameService, destructor unregisters member SearchDest with cac
- if _nameService flag is set send thread sleeps and then tries to connect again if connect fails
- if _nameService flag set the receive thread, upon receiving disconnect notification from the socket
- command send thread to exit
- waits for send thread exit
- (clear all buffers)
- sleep
- restarts the send thread
- exits
- class deriving from SearchDest called SearchDestTCP
- private member of type SearchDestTCP called _searchDest
- implement code calling Callback :: notify () when resp to search request arrives
- implement friend SearchDest::searchRequest () that issues a tcp search request if server is capable, else directly calls the Callback::notify ()
- udpiiu changes
- private member class deriving from SearchDest called SearchDestUDP
- instances on the search list
- private member class deriving from SearchDest :: Callback called SearchRespCallback
- implement SearchRespCallback :: notify ()
- implement code calling Callback :: notify () when resp to search request arrives
- build udp search dest objects
- remove "dest" member data
- add private tsDLLList < SearchDest > list called _searchDestList
- build address list ELLLIST using iocinf.c code parsing addr list and traversing NICs
- for each member of this list create private SearchDest derived objects
- install the SearchDest derived objects in _searchDestList
- destroy ELLLIST members
- add public register/unregister SearchDest to udpiiu (called by cac)
- private member class deriving from SearchDest called SearchDestUDP
- cac changes
- code parsing EPICS_CA_NAME_SERVERS (in constructor)
- creates SearchDestTCP and adds it to the search list
- creates tcpiiu specifying the SeachDestTCP to its constructor
- add public register/unregister SearchDest to cac (called by tcpiiu const and dest)
- in destructor guarantee that udpiiu is shutdown prior to deleting nameService tcpiiu
CAS
- casStrmClient changes
- add private client addr member (init'd through constructor arg)
- add casStrmClient::searchAction that does roughly the same as the casDGClient::searchAction (maybe this could be refactored and moved to a separate name resolver class to avoid code repetition)
- add casStrmClient::asyncSearchResponse and casStrmClient::searchResponse (again: same as casDGClient methods)
- casStreamIO changes
- add private client address member
- add public methods to get client host name and address
rsrv
- camessage.c changes
- rename search_reply() to search_reply_udp()
- add search_reply_tcp() with similar functionality
- change jump table accordingly
Issues
Fixed: TCP Nameserver Connections Do Not Reconnect
When a TCP nameserver connection goes away (e.g. if the nameserver dies), the client does not reconnect when the connection comes back (e.g. the nameserver is restarted).
Fix (2010-04-09): The private member SearchDestTCP::_addr must be an osiSockAddr, not a reference to it. The constructor cac::cac() frees the list of destinations after creating the SearchDestTCP instances. The SearchDestTCP couldn't reconnect, because it had lost the target address.
Fixed: TCP Nameserver Connection Down Blocks All Callbacks
When a TCP nameserver connection goes away (e.g. if the nameserver dies), the client's TCP receive thread tries to reconnect in an endless loop, doing a epicsThreadSleep(cac.connectionTimeout) between attempts. While the receive thread is sleeping, no other CA callbacks are executed.
Fix: (2010-04-15) tcpRecvThread::connect() holds the cac mutex lock. That lock must be released during the epicsThreadSleep().
Status
The original changes (against 3.15 aka CVS trunk) have been pulled out and merged into a development branch.
Development branch: https://code.launchpad.net/~ralph-lange/epics-base/ca-over-tcp
Blueprint: https://blueprints.launchpad.net/epics-base/+spec/ca-over-tcp