file: STPsC.mesa - Simple/Stream Transfer Protocol
Remote Stream stuff in here
Edited by:
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
Last Edited by: Schroeder, August 10, 1983 5:56 pm
Last Edited by: 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 =
BEGIN 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
PROCEDURE [
stp: STPOps.Handle, file: Rope.ROPE, access: STP.Access, fileType: STP.Type, creation: BasicTime.GMT]
RETURNS [stream: IO.STREAM] =
BEGIN
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]]
END;
NextFileName:
PUBLIC
PROCEDURE [remoteStream:
IO.
STREAM]
RETURNS [file: Rope.ROPE] =
BEGIN
rs: RemoteStream ← ConvertHandle[remoteStream];
reason: PupStream.CloseReason;
IF rs.access # read THEN ERROR STP.Error[rs.stp, accessError, NIL];
BEGIN ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
SELECT rs.state
FROM
initial => RequestRetrieve[rs];
confirm =>
BEGIN
PutCommand[rs.stp, markNo, 0C, "No Thanks"];
IF LookAtMark[rs.stp] = markEOC THEN {[] ← MyGetMark[rs.stp]; rs.state ← end}
ELSE GetHereIsAndPList[rs.stp];
END;
data =>
BEGIN
ErrorIfNextNotYes[rs.stp];
IF LookAtMark[rs.stp] = markEOC THEN {[] ← MyGetMark[rs.stp]; rs.state ← end}
ELSE {GetHereIsAndPList[rs.stp]; rs.state ← confirm};
END;
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];
END;
RETURN[IF rs.state = end THEN NIL ELSE MakeRemoteName[rs.stp.plist, alto]]
END;
Procedures for Remote streams
ConvertHandle:
PROCEDURE [h:
IO.
STREAM]
RETURNS [rs: RemoteStream] =
INLINE
BEGIN RETURN[NARROW[h.streamData]] END;
UnsafeGetBlock:
UNSAFE
PROC[self:
IO.
STREAM, block:
IO.UnsafeBlock]
RETURNS[nBytesRead:
INT] =
UNCHECKED
BEGIN
rs: RemoteStream ← ConvertHandle[self];
reason: PupStream.CloseReason;
BEGIN
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
IF rs.state # data
THEN
BEGIN
StartRemote[rs, read];
IF rs.state = end THEN RETURN[0];
END;
nBytesRead ← rs.stp.byteStream.UnsafeGetBlock[block];
IF rs.stp.byteStream.EndOf[]
THEN
BEGIN
rs.stp.mark ← PupStream.ConsumeMark[rs.stp.byteStream];
rs.stp.gotMark ← TRUE;
SetupForNextOrEnd[rs.stp];
END;
EXITS
streamClosing => {rs.state ← end; GenerateStreamClosingError[rs.stp, reason]};
END;
END;
EndOf:
PROC[self:
IO.STREAM]
RETURNS[
BOOL] =
BEGIN
rs: RemoteStream ← ConvertHandle[self];
RETURN[rs.state # data OR rs.stp.byteStream.EndOf[]]
END;
PutChar:
PROC[self:
IO.STREAM, char:
CHAR] =
BEGIN
rs: RemoteStream ← ConvertHandle[self];
reason: PupStream.CloseReason;
BEGIN
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]};
END;
END;
UnsafePutBlock:
PROC[self:
IO.
STREAM, block:
IO.UnsafeBlock] =
BEGIN
rs: RemoteStream ← ConvertHandle[self];
reason: PupStream.CloseReason;
BEGIN
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]};
END;
END;
DeleteRemoteStream:
PROC[self:
IO.STREAM, abort:
BOOL ←
FALSE] =
BEGIN
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;};
END;
Utilities
SetupForNextOrEnd:
PROCEDURE [stp: STPOps.Handle] =
BEGIN
ErrorIfNextNotYes[stp];
SELECT LookAtMark[stp]
FROM
markEOC => {[] ← MyGetMark[stp]; stp.remoteStream.state ← end};
markHereIsPList => stp.remoteStream.state ← complete;
ENDCASE => GenerateProtocolError[stp, badMark, MyGetMark[stp]];
END;
RequestRetrieve:
PROCEDURE [rs: RemoteStream] =
BEGIN
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;
END;
StartRemote:
PROCEDURE [rs: RemoteStream, access:
STP.Access] =
BEGIN
reason: PupStream.CloseReason;
IF rs.access # access
THEN
ERROR STP.Error[rs.stp, accessError, "Remote stream access Error"];
BEGIN
ENABLE PupStream.StreamClosing => {reason ← why; GOTO streamClosing};
SELECT access
FROM
read =>
BEGIN
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
BEGIN
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];
END;
END;
write =>
BEGIN
PutPList[rs.stp, markNewStore];
GetHereIsAndPList[rs.stp];
PupStream.SendMark[rs.stp.byteStream, markHereIsFile];
END;
ENDCASE => ERROR;
rs.state ← data;
EXITS streamClosing => GenerateStreamClosingError[rs.stp, reason];
END;
END;
END. of STPsC