The Session module provides a communication channel respecting this set of properties:
A Session instance obtained by Session.new represents one side of a communication.
When two instances are connected together, they offer a bidirectional communication channel between these two points. Messages are received on a stream. There is only one reception stream per session instance that receives all messages from all successive connections of this instance.
At maximum two instances can be connected together at any time.
Any one of the two sides of a session communication channel can break the connection. Each side can then be connected back again together or to other session instances.
Each session instance also provides a free-for-all communication channel where anyone can send messages freely without having to connect. These messages are received on a distinctive stream. For example, an application wants to provide a remote control to several remote clients, but only one at a time. With the Session module, the application can use a single session instance to let only one remote client connect at a time. When the client wants to stop working with the application, it can stop the session, and another client can then take over. If a client is already connected to the application and another one wants to connect to it also, it can use the free-for-all channel to notify the application so. If there are several applications the client wants to connect to successively, it can do so using a single session instance.
Each session instance produces a link state stream. Connections, change of the communication link with the currently connected session and disconnections generate messages on that stream. This can be used to create fault-tolerant applications without using the Fault module. The possible messages on that stream are:
connect: this session instance has just been connected to another session instance. Messages can be sent to the other site.
disconnect: this session instance has been disconnected by the other session instance. No message can be sent while disconnected.
tempFail: there is a communication problem that temporarily prevents the messages from arriving to the other site. A tempFail may change into permFail or ok, or stays forever (until the site decides to break the session). Note that the application can still send messages in this state, they will be buffered and send correctly if the communication turns ok or dropped if the communication is broken.
permFail: the other site was detected crashed. It is the same as disconnect, except that there is no use to try and contact the other site anymore: it is dead forever.
ok: after a tempFail, this state means the communication is fine again, messages are normally arriving at the other site.
This module also offers a session gate, which is a single access point for spawning multiple sessions. Typically, a server can start a gate that will create a different session per client. When a client has finished to work with the server, the session is closed and no more communication is possible between them. However, the client can use the gate again to create a new session with the server.
This module doesn't provide an access control over the session instances and the gates. The application should define its own using the Connection and Ticket modules, or the SocketConnection module.
First example: a client-server implementation.
%% Server side
proc{Server Msg}
... %% insert here the code that responds to Msg
end
L
G={Session.newGate L}
{SocketConnection.offerOn 5000 G}
{ForAll L
proc{$ S}
thread
{ForAll {Session.getStream S}
proc{$ M} {Server M} end}
end
end}
%% client side
G={SocketConnection.take IP 5000} %% IP contains the IP of the server
S={Session.gateConnect G} %% S is a session connected to the server
{S.aSend run} %% sends the run message to the server
...Second example: a timer server that sends a tick every second. Only one client can connect at a time.
%% server side
S={Session.new}
{SocketConnection.offerOn 5000 S}
thread
proc{Tick}
try {Session.aSend S tick} catch _ then skip end
{Delay 1000} {Tick}
end
in
{Tick}
end
%% client side
LS={Session.new}
{Browse {Session.getStream LS}}
RS={SocketConnection.take IP 5000}
{Session.connect LS RS} %% will fail if the server is not free
...
{Session.disconnect S} %% disconnects from the server => another client can take overWarning: local and remote session instances play a different role in the functions and procedures below. Except when otherwise stated, the first parameter is always a locally created session. Let's assume Offer is a function that makes an Oz entity remotely available, and Obtain the function that gets the offered reference:
|
|
|---|---|
|
|
|
|
|
|
At this stage, SiteB has the remote reference SR to SA of SiteA. SiteB can connect both sessions by:
{Session.connect SB SR}However swapping the parameters is invalid:
{Session.connect SR SB} The first parameter of Session.connect must be session local to SiteB, which is not the case here.
is
{Session.is+X?B}
tests whether X is a Session. X can be a remote session.
new
{Session.new?S}
returns a new session instance.
connect
{Session.connectS1S2}
Connects S1 with S2. Raises an exception if S1 or S2 are already connected to another session. Raises an exception if S2 is unreachable.
disconnect
{Session.disconnectS}
Disconnects S to whatever other session it was connected to. This is a synchronous disconnection, ie it waits for all pending messages to arrive before disconnecting. In case of permFail, the disconnection waits for a change of the communication status. If it resolves to ok, all pending messages are sent before disconnecting. If it resolves to permFail or disconnect, the disconnection is immediate, and pending messages may be lost in the process.
break
{Session.breakS}
Disconnects S to whatever other session it was connected to. This is an as soon as possible disconnection: if the communication state was ok then all sent messages are garanteed to arrive before the disconnection. On the contrary, if the communication was in the permFail state, the disconnection is immediate and pending messages may be lost in the process. Note that break is the only way to terminate a session if it goes to permFail for an infinite amount of time.
getStream
{Session.getStreamS?Xs}
Returns the stream of messages sent by sessions connected to S. The returned stream doesn't start from the creation of S but from the moment it is asked. For that reason, it is often better to getStream before connecting to another session, otherwise messages might be lost.
getStateStream
{Session.getStateStreamS?Xs}
Returns the stream of communication states of S with the other sessions it is successively connected to. The returned stream doesn't start from the creation of S, but from the last known communication state change. So Xs has the form C|Cs where C is the current communication state of S and Cs is the stream that will receive the updates when that state changes. This stream can be composed of one of the following atoms: connect, disconnect, tempFail, ok, permFail.
getSideStream
{Session.getSideStreamS?Xs}
Returns the free-for-all stream of S. There is no need to connect to S to send an element to this stream. The returned stream doesn't start from the creation of S but from the moment it is asked. Elements of Xs are composed of pairs RS#M where RS is a reference to the session object used to send the message M.
getState
{Session.getStateS?T}
Returns current state of S, ie {Session.getStateStream S}.1.
getPeer
{Session.getPeerS1?S2}
Returns the session instance S1 is currently connected with, or unit if S1 is not currently connected.
sSend
{Session.sSendSM}
Sends M to the reception stream of the session S is connected to in a synchronous way: this command blocks until this message has arrived on the reception stream of the other site. Raises an exception if S is not currently connected.
aSend
{Session.aSendSM}
Sends M to the reception stream of the session S is connected to. Doesn't block. Raises an exception if S is not currently connected.
lSend
{Session.lSendSM}
Sends M to the reception stream of S itself.
sideSend
{Session.sideSendS1S2M}
Sends M to the free-for-all reception stream of S2. S2 receives the pair S1#M on his free-for-all stream. Nothing happens if S2 is unreachable.
bind
{Session.bindSEventProc}
This procedure provides an event based way of managing communication state changes. Event must be one of these atoms: connect, disconnect, tempFail, ok, permFail. Proc is a zero parameter procedure that is executed each time the state change specified by Event occurs on S.
configure
{Session.configureSParamValue}
Changes the paramater Param of S to Value. Currently, the only configurable parameter is:
autoBreakAfter: either an integer representing milliseconds, or the atom inf for an infinite time (default). Specifies a time to wait before automatically breaking a session when a permFail occurs.
isConnected
{Session.isConnectedS?B}
Returns true if S is currently connected, false otherwise.
wait
{Session.wait[Ok|NotOk|Connect|Disconnect]S}
{Session.wait[Ok|NotOk|Connect|Disconnect]OrSV}
{Session.wait[Ok|NotOk|Connect|Disconnect]OrsSLV}
If the communication status of S is not in the specified state, then blocks until it is. Supported states are:
Ok means S is connected to another session instance and the link between them is fine.
NotOk in all situations that are not Ok.
Connect means S is connected to another session instance.
Disconnect means S is not connected to another session instance.
The Or flavour also specifies a logic variable V and blocks until the specified state occurs, or V is determined. The Ors flavour also specifies a list logic variable LV and blocks until the specified state occurs, or any of the elements of LV is determined.
isGate
{Session.isGate+X?B}
tests whether X is a Gate.
newGate
{Session.newGate?S?G}
returns a new gate and binds S to a list of futures. Each time a connection is created on this gate by Session.gateConnect, the next element of S is bound to the local session created for the communication.
gateConnect
{Session.gateConnectG?S}
returns a local session S connected to a session created by the gate G.
closeGate
{Session.closeGateG}
Stops the gate G from accepting new connections and closes the associated list of sessions. G must be a local gate.