Chapter 3 Management
4.10 Console server algorithms
4.10.8 Console carrier requester
The console carrier requester algorithm is shown below.
The central part of the algorithm is a polling loop in which the target station is polled peri- odically for new console carrier data. New console input is also sent to the target in this loop as needed.
4.10.8: Consolecarrier requester
79
Note:
The polling should be done frequently enough tocarry console data from the tar-
get to the requester promptly and avoid console response data loss, but not so often that the target station is overloaded by the polling activity. The minimum permitted poll interval is 80 milliseconds. Somewhat longer poll intervals are generally more appropriate (several hundred milliseconds). Adaptive algo-
rithms may be used for increased efficiency; for example, poll at 100 ms inter-
vals until no new data is seen for some time (e.g., 10 seconds); then poll at 1 s intervals; switch back to 100 ms intervals when new data is seen in either direc-
tion.
The timeout for each poll should be substantially longer than the poll rate (the default time- out of 4 seconds is appropriate) to ensure that the timeout is longer than the likely packet life-
time in the network. This is necessary because the protocol only has a one bit sequence num-
ber.
The purpose of the console carrier is to provide the common ASCII local console function via a simple low level network protocol. Character stream data is sent by the console carrier re-
quester and any console output is returned in a character stream by the console carrier server. The requester should assume that the server will echo input (characters received from the re-
quester) in the same manner as local console data; therefore the requester should not echochar-
acters locally.
PROCEDURE LAN.CarrierRequester (circ: POINTER TO Circuit) RAISES {InvalidResponse, DataLinkError, Unavailable, Timeout}; VAR op: POINTER TO Operation;
buff: POINTER TO Buffer; seq, cflags, rseq: INTEGER; target: LANAddress; BEGIN
DLI.Alloc (op, buff); (* Allocate necessary resources, if available *) TRY op^.Op := ConsoleCarrier; op^.CircPtr := circ; op^.Address := NullAddress; op^.Version := Unknown; LOOP IF op^.Addresses = { }
THEN RAISE (Timeout) (* No response from anything *) END;
target := « select and remove an address from op^.Addresses »; LAN.BuildReqID (buff, target);
TRY
DLI.Transact (op, buff, buff);
op^.Address := target; (* If it works, that’s the target address *) EXIT
EXCEPT
| Timeout: (* If no answer, keep on trying addresses *) END
END;
IF « console carrier not supported » THEN RAISE (Unavailable) END;
FOR i := 1 TO RetransmitMax DO
LAN.BuildReserve (buff, op^.Address); (* Try to reserve console *) DLI.Send (op, buff, op^.Version);
System.Wait ( « a few milliseconds » );
(* Wait to allow target to make the reservation and update the System ID it sends to reflect the reservation *)
LAN.BuildReqID (buff, op^.Address); (* Check the result *) DLI.Transact (op, buff, buff);
IF « console reserved by circ^.DataLinkAddress » THEN EXIT
ELSEIF « console reserved »
THEN RAISE (Unavailable) (* Someone else got it first *) END;
IF i = RetransmitMax THEN RAISE (Timeout) END
END;
seq := 1; (* Initial sequence number *)
LOOP
IF « user is finished with console carrier »
THEN EXIT (* Leave the polling loop *)
System.Wait (« poll delay »); (* See note above *) LAN.BuildConsolePoll (buff, op^.Address, seq); DLI.Transact (op, buff, buff);
cflags := buff^.Data[1]; (* Control flags from console response message *) rseq := cflags MOD 2; (* Received sequence number *)
IF rseq = seq
THEN (* Valid response to our poll *)
seq := (seq + 1) MOD 2; (* Update the transmit sequence number *) « send console response data to user »;
(* This queues the data, it doesn’t wait for it to be handled. If there is no room for more, discard the data *)
IF (cflags DIV 2) MOD 2 = 1
THEN (* Data lost flag(s) set *)
« send data lost error indication(s) to user » END;
« get new console command data from user » END END; FOR i := 1 TO RetransmitMax DO buff^.Length := 1; buff^.Destination := op^.Address; buff^.Data[0] := ReleaseConsole;
DLI.Send (op, buff, op^.Version) (* Release the console *) System.Wait ( « a few milliseconds » );
(* Wait to allow target to release the reservation and update the System ID it sends to reflect the release *)
LAN.BuildReqID (buff, op^.Address); (* Check the result *) DLI.Transact (op, buff, buff);
IF NOT « console reserved by circ^.DataLinkAddress »
THEN EXIT (* Leave loop if not reserved, or reserved by another *) END
END FINALLY
DLI.Free (op, buff) END
END LAN.CarrierRequester;
LAN.BuildReqID (buff: POINTER TO Buffer; target: LANAddress); buff^.Length := 4;
4.11: MOP protocol primitives
81
buff^.Destination := target; buff^.Data[0] := RequestID;
buff^.Data[1] := 0; (* reserved field *) DLI.PutInteger (buff, 2, « a suitable non-zero receipt number ») END LAN.BuildReqID;
LAN.BuildReserve (buff: POINTER TO Buffer; target: LANAddress); buff^.Length := 9;
buff^.Destination := target; buff^.Data[0] := ReserveConsole; « load verification value into bytes 1–8 » END LAN.BuildRereserve;
LAN.BuildConsolePoll (buff: POINTER TO Buffer; target: LANAddress, seq: INTEGER); buff^.Destination := target;
buff^.Data[0] := ConsoleCommand; IF « break requested by user » THEN buff^.Data[1] := seq+2 ELSE buff^.Data[1] := seq END;
« load user console command data, if any, into bytes 2 and up »; buff^.Length := 2 + « length of command data »
END LAN.BuildConsolePoll;