STPsC.mesa - Simple/Stream Transfer Protocol (Remote Stream)
Copyright © 1985 by Xerox Corporation. All rights reserved.
Smokey, 16-Jul-81 17:24:59
Sandman, 17-Aug-81 11:32:55
Karlton, 9-Dec-81 18:36:06
SHayes, 11-Sep-81 16:15:34
Bruce, 20-Oct-81 11:24:17
Johnsson, 16-Dec-81 17:39:42
Daniels, 21-Sep-82 13:06:31
Davirro, 24-Sep-82 10:45:37
Schmidt, January 20, 1983 7:10 pm
Andrew Birrell, June 1, 1983 5:39 pm
Schroeder, August 10, 1983 5:56 pm
MBrown, September 12, 1983 8:37 pm
DIRECTORY
BasicTime USING [GMT],
IO USING [CreateStream, CreateStreamProcs, EndOf, PutChar, STREAM, StreamProcs, UnsafeBlock, UnsafeGetBlock, UnsafePutBlock],
PupStream USING [CloseReason, ConsumeMark, SendMark, StreamClosing],
Rope USING [ROPE],
STP USING [Access, CredentialsErrors, Error, FileErrors, Type],
STPOps USING [CheckConnection, ErrorIfNextNotEOC, ErrorIfNextNotYes, GenerateProtocolError, GenerateStreamClosingError, GetHereIsAndPList, Handle, LookAtMark, MakeRemoteName, markEOC, markHereIsFile, markHereIsPList, markNewStore, markNo, markRetrieve, markYes, MyGetMark, NameToPList, Object, ResetPList, PList, PutCommand, PutPList, RemoteObject, RemoteStream, SelectError, SetByteSize, SetCreateTime, SetFileType, SmashClosed, UserStateToPList];
STPsC: CEDAR PROGRAM
IMPORTS IO, PupStream, STP, STPOps
EXPORTS STP =
{ OPEN PupStream, STPOps;
Object: PUBLIC TYPE = STPOps.Object;
Procedures implementing STP interface
remoteStreamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[
variety: $inputOutput, class: $FTP,
endOf: EndOf,
unsafeGetBlock: UnsafeGetBlock,
putChar: PutChar,
unsafePutBlock: UnsafePutBlock,
close: DeleteRemoteStream];
CreateRemoteStream: PUBLIC PROC [stp: STPOps.Handle, file: Rope.ROPE, access: STP.Access, fileType: STP.Type, creation: BasicTime.GMT] RETURNS [stream: IO.STREAM] = {
rs: STPOps.RemoteStream = NEW[STPOps.RemoteObject ← [access: access, state: initial, stp: stp]];
CheckConnection[stp];
IF stp.remoteStream # NIL THEN ERROR STP.Error[stp, accessError, "Remote Stream Exists"];
ResetPList[stp.plist];
UserStateToPList[stp];
NameToPList[stp.plist, file, alto];
SetFileType[stp, fileType];
IF access = write THEN {
STPOps.SetCreateTime[stp, creation];
SetByteSize[stp, fileType]};
IF fileType = text THEN stp.plist[eolConversion] ← "CR";
stp.remoteStream ← rs;
RETURN[IO.CreateStream[remoteStreamProcs, rs]]
};
NextFileName: PUBLIC PROC [remoteStream: IO.STREAM] RETURNS [file: Rope.ROPE] = {
rs: RemoteStream ← ConvertHandle[remoteStream];
reason: PupStream.CloseReason;
IF rs.access # read THEN ERROR STP.Error[rs.stp, accessError, NIL];
{
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
SELECT rs.state FROM
initial => RequestRetrieve[rs];
confirm => {
PutCommand[rs.stp, markNo, 0C, "No Thanks"];
IF LookAtMark[rs.stp] = markEOC THEN {[] ← MyGetMark[rs.stp]; rs.state ← end}
ELSE GetHereIsAndPList[rs.stp];
};
data => {
ErrorIfNextNotYes[rs.stp];
IF LookAtMark[rs.stp] = markEOC THEN {[] ← MyGetMark[rs.stp]; rs.state ← end}
ELSE {GetHereIsAndPList[rs.stp]; rs.state ← confirm};
};
complete =>
IF LookAtMark[rs.stp] = markEOC THEN {[] ← MyGetMark[rs.stp]; rs.state ← end}
ELSE {GetHereIsAndPList[rs.stp]; rs.state ← confirm};
end => NULL;
ENDCASE;
EXITS
streamClosing => GenerateStreamClosingError[rs.stp, reason];
};
RETURN[IF rs.state = end THEN NIL ELSE MakeRemoteName[rs.stp.plist, alto]]
};
Procedures for Remote streams
ConvertHandle: PROC [h: IO.STREAM] RETURNS [rs: RemoteStream] = INLINE {
RETURN[NARROW[h.streamData]] };
UnsafeGetBlock: UNSAFE PROC[self: IO.STREAM, block: IO.UnsafeBlock] RETURNS[nBytesRead: INT] = UNCHECKED {
rs: RemoteStream ← ConvertHandle[self];
reason: PupStream.CloseReason;
{
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
IF rs.state # data THEN
{
StartRemote[rs, read];
IF rs.state = end THEN RETURN[0];
};
nBytesRead ← rs.stp.byteStream.UnsafeGetBlock[block];
IF rs.stp.byteStream.EndOf[]
THEN {
rs.stp.mark ← PupStream.ConsumeMark[rs.stp.byteStream];
rs.stp.gotMark ← TRUE;
SetupForNextOrEnd[rs.stp];
};
EXITS
streamClosing => {rs.state ← end; GenerateStreamClosingError[rs.stp, reason]};
};
};
EndOf: PROC[self: IO.STREAM] RETURNS[BOOL] = {
rs: RemoteStream ← ConvertHandle[self];
RETURN[rs.state # data OR rs.stp.byteStream.EndOf[]]
};
PutChar: PROC[self: IO.STREAM, char: CHAR] = {
rs: RemoteStream ← ConvertHandle[self];
reason: PupStream.CloseReason;
{
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
IF rs.state # data THEN StartRemote[rs, write];
rs.stp.byteStream.PutChar[char];
EXITS streamClosing => {rs.state ← end; GenerateStreamClosingError[rs.stp, reason]};
};
};
UnsafePutBlock: PROC[self: IO.STREAM, block: IO.UnsafeBlock] = {
rs: RemoteStream ← ConvertHandle[self];
reason: PupStream.CloseReason;
{
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
IF rs.state # data THEN StartRemote[rs, write];
rs.stp.byteStream.UnsafePutBlock[block];
EXITS streamClosing => {rs.state ← end; GenerateStreamClosingError[rs.stp, reason]};
};
};
DeleteRemoteStream: PROC[self: IO.STREAM, abort: BOOLFALSE] = {
rs: RemoteStream ← ConvertHandle[self];
stp: STPOps.Handle = rs.stp;
{
ENABLE UNWIND => stp.remoteStream ← NIL;
IF rs.access = read THEN {IF rs.state # end THEN SmashClosed[stp]} -- in mid-transfer
ELSE SELECT rs.state FROM
initial => NULL;
data => {
PutCommand[rs.stp, markYes, 0C, "Transfer Completed"
! PupStream.StreamClosing => CONTINUE]; -- OK, if closed in advance
ErrorIfNextNotYes[rs.stp];
ErrorIfNextNotEOC[rs.stp]};
confirm, complete, end => NULL; -- worry about later
ENDCASE;
stp.remoteStream ← NIL;};
};
Utilities
SetupForNextOrEnd: PROC [stp: STPOps.Handle] = {
ErrorIfNextNotYes[stp];
SELECT LookAtMark[stp] FROM
markEOC => {[] ← MyGetMark[stp]; stp.remoteStream.state ← end};
markHereIsPList => stp.remoteStream.state ← complete;
ENDCASE => GenerateProtocolError[stp, badMark, MyGetMark[stp]];
};
RequestRetrieve: PROC [rs: RemoteStream] = {
PutPList[rs.stp, markRetrieve];
GetHereIsAndPList[rs.stp ! STP.Error =>
SELECT code FROM
IN STP.CredentialsErrors, IN STP.FileErrors => rs.state ← end;
ENDCASE];
rs.state ← confirm;
};
StartRemote: PROC [rs: RemoteStream, access: STP.Access] = {
reason: PupStream.CloseReason;
IF rs.access # access THEN ERROR STP.Error[rs.stp, accessError, "Remote stream access Error"];
{
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
SELECT access FROM
read =>
{
IF rs.state = initial THEN RequestRetrieve[rs];
IF rs.state = complete THEN {
IF LookAtMark[rs.stp] = markEOC THEN {rs.state ← end; RETURN}
ELSE GetHereIsAndPList[rs.stp]; rs.state ← confirm};
IF rs.state = confirm THEN
{
mark: [0..256);
PutCommand[rs.stp, markYes, 0C, "Yes, please"];
SELECT (mark ← MyGetMark[rs.stp]) FROM
markHereIsFile => NULL;
markNo => {rs.state ← complete; SelectError[rs.stp, "He says NO", mark]};
ENDCASE => SelectError[rs.stp, "HereIsFile Expected", mark];
};
};
write =>
{
PutPList[rs.stp, markNewStore];
GetHereIsAndPList[rs.stp];
PupStream.SendMark[rs.stp.byteStream, markHereIsFile];
};
ENDCASE => ERROR;
rs.state ← data;
EXITS streamClosing => GenerateStreamClosingError[rs.stp, reason];
};
};
}.