• No results found

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;