The attachment process is summarised in Figure 10.3. It is initiated from the ECLiPSe side, by either calling remote_connect/3 or the more flexible remote_connect_setup/3 and remote_connect_accept/6 pair. In fact, remote_connect/3 is implemented using remote_connect_setup/3 and remote_connect_accept/6 with default values for some of the arguments.
The attachment can be divided into several phases:
The remote protocol version is stored in the flag remote_protocol_version, accessible via get_flag/2 as an integer version number. This version number should only change when the protocol is modified. Checking of the version ensures that the same (or at least compatible) versions of the protocol are used, so that the two sides behaves correctly. The version information is sent from the remote side (which must have its own copy of the version information), and the ECLiPSe side checks that this is compatible with the protocol version it is using. In order to cope with remote connections which may not be using the remote protocol, the ECLiPSe side waits only for a fixed period of time for the remote side to send the version information before timing out.
Time-out on the ECLiPSe side can also occur for forming any of the connections between the two sides, from the control connection to the peer queue. This is specified by the user in remote_connect_accept/6. If time-out occurs during the attachment, then the attachment process is abandoned, and the predicate fails (any connected sockets will be closed).
The detailed sequence of events for the attachment for the remote side (with some description of the relevant ECLiPSe side actions) are:
At the end of this, the remote side should be ready for normal interaction with the ECLiPSe side.
The remote_connect/3 or remote_connect_accept/6 predicate waits for the control to be handed back by the remote side before exiting. Thus when the predicate succeeds, the remote side has been attached and properly initialised, with ECLiPSe side having control.
The protocol does not specify how the remote side should be informed of the Host/Port address for the initial socket connection. The Address can be fixed before hand (with the Address argument instantiated, or the information can be transmitted either manually or via files. In addition, the remote process can be started from within ECLiPSe using the exec/3 command, with the host and port supplied as arguments.
In accepting client socket connections from the remote side, the ECLiPSe side is informed of the host of the remote side. This should either be the client’s hostname, or ’localhost’. After accepting the control connection, subsequent connections (for ec_rpc and any peer queues) are checked to ensure that they are from the same client. If not, the attachment is terminated by ECLiPSe. Using ’localhost’ as the name on either side will restrict the two sides to be on the same machine (and they must both use localhost for Host in the address, rather than the actual hostname).
The following is a simple example of making a remote attachment on the remote side. In this case, the remote side is also an ECLiPSe program. A remote attachment by a program written in another programming language will need to provide a similar function in that language:
% Example code for making a remote attachment on the remote side :- local variable(ecsidehost). % remote_attach/6 makes a remote attachment to a host ECLiPSe program. % Args: % +Host: host name on ECLiPSe side % +Port: port on ECLiPSe side % +Pass: `pass-term' - used to verify the connection % +Init: goal to call to perform any application specific initialisation % -Control: the remote side (local) name of the control connection % -Ec_rpc: the remote side name of the ec_rpc connection % -EcSideControl: the ECLiPSe side name for the control connection remote_attach(Host, Port, Pass, Init, Control, Ec_rpc, EcSideControl) :- % control connection new_client_socket(Host, Port, Control), % send the protocol version information to the ECLiPSe side % we are the remote side, so must have our own version info. write_exdr(Control, remote_protocol(1)), flush(Control), % read response from ECLiPSe side to make sure it is compatible... read_exdr(Control, IsSameVersion), (IsSameVersion == "yes" -> true ; writeln("Incompatible versions of remote protocol. Failing...."), fail ), % send pass-term; if this does not match the pass-term on the ECLiPSe % side, it will terminate the attachment write_exdr(Control, Pass), flush(Control), % ECLiPSe side name for connection read_exdr(Control, EcSideControl), % send language name to ECLiPSe side write_exdr(Control, "eclipse"), flush(Control), % Ec_rpc connection new_client_socket(Host, Port, Ec_rpc), % read control name again on Ec_rpc to verify connection % in a more sophisticated implementation, this should time-out (read_exdr(Ec_rpc, EcSideControl) -> true ; % if not verified, terminate connection close(Control), close(Ec_rpc), fail ), % Remote side now has control, call Init to perform application % specific initialisations call(Init), % hand control over to ECLiPSe side... write_exdr(Control, resume), flush(Control). new_client_socket(Host, Port, Socket) :- socket(internet, stream, Socket), connect(Socket, Host/Port). %---------------------------------------------------- % the following code make use of remote_attach/6 to make an attachment, % and then disconnect immediately when ECLiPSe side returns control test(Host, Port) :- % make the remote attachment. For this simple example, there is no % application specific initialisations, and the default pass-term % of an empty string is used... remote_attach(Host, Port, "", true, Control, Ec_rpc, _), % control has been given to ECLiPSe side, % wait for ECLiPSe side to return control.... read_exdr(Control, _), % immediately disconnect from ECLiPSe side write_exdr(Control, disconnect), flush(Control), % wait for ECLiPSe side to acknowledge disconnect... read_exdr(Control, disconnect_yield), % clean up close(Control), close(Ec_rpc).
In addition to the attachment, the example contains a very simple example of using the protocol by exchanging control messages with the ECLiPSe side. After attachment, it disconnects the remote attachment as soon as control is handed back to it. For more details on the messages, see next section.
To try out the example, start an ECLiPSe session and initiate a remote attachment. This process is the ECLiPSe side:
(ECLiPSe side) [eclipse 1]: remote_connect(Host/Port, Control, _). Socket created at address chicken.icparc.ic.ac.uk/32436
Now start another ECLiPSe session, compile the example program, and make the attachment to the ECLiPSe side:
(Remote side) [eclipse 4]: test('chicken.icparc.ic.ac.uk', 32436).
On the ECLiPSe side, remote_connect/3 should now succeed:
(ECLiPSe side) Host = 'chicken.icparc.ic.ac.uk' Port = 32436 Control = peer3 yes. [eclipse 2]:
The remote side is suspended, awaiting the ECLiPSe side to return control. To return control to the remote side, the ECLiPSe side should call remote_yield/1 (see section 10.6 for a description of remote_yield/1):
(ECLiPSe side) [eclipse 2]: remote_yield(peer3). Abort [eclipse 3]:
In this simple example, when control is returned to remote side, it immediately disconnects, thus the remote_yield/1 on the ECLiPSe side is aborted (as disconnect was initiated from the remote side), as per the disconnect protocol.
(Remote side) [eclipse 4]: test('chicken.icparc.ic.ac.uk', 32436). yes. [eclipse 5]: