-- Copyright (C) 1983, 1984, 1985 by Xerox Corporation. All rights reserved. -- GVPServer.mesa, the ALTO end of the GVPatch system -- HGM, 15-Sep-85 11:48:37 -- Steve Temple, September 29, 1982 9:50 am -- Brenda Hankins 2-Jun-83 15:52:06 -- kludge to get around authentication problem for Mission. DIRECTORY BodyDefs: TYPE USING [maxRNameLength, RName], IODefs USING [WriteDecimal, WriteLine, WriteString], HeapXDefs USING [ObjectHeader, PageHeader], NameInfoDefs USING [Authenticate, IsMemberClosure], ProtocolDefs USING [ DestroyStream, Failed, Handle, ReceiveByte, ReceiveBytes, ReceiveCount, ReceiveRName, ReceiveString, SendByte, SendBytes, SendCount, SendNow, SendString], PupDefs USING [PupAddress, PupPackageMake, PupSocketID], PupStream USING [CreatePupByteStreamListener, veryLongWait], String USING [AppendString, EqualStrings], TemporaryBooting USING [BootFromVolume], VMDefs USING [ AllocatePage, CantOpen, CantReadBackingStore, CantWriteBackingStore, CloseFile, Deactivate, Error, FileHandle, GetFileLength, InitializeVM, MarkStartWait, OpenFile, OpenOptions, Page, PageByteIndex, pageByteSize, PageNumber, Position, ReadPage, RemapPage, SetFileLength, UnmapPage], Volume USING [systemID]; GVPServer: PROGRAM IMPORTS IODefs, NameInfoDefs, ProtocolDefs, PupDefs, PupStream, String, TemporaryBooting, VMDefs, Volume = BEGIN OPEN IODefs, VMDefs; Byte: TYPE = [0..255]; Command: TYPE = Byte; login: Command = 1; readHeaders: Command = 2; openFile: Command = 3; readPage: Command = 4; writePage: Command = 5; restartServer: Command = 6; setLength: Command = 7; errorCode: Command = 255; oldFile: Byte = 0; oldOrNewFile: Byte = 1; GVPatchSocket: PupDefs.PupSocketID = [0, 47B]; maxString: CARDINAL = 64; voidString: STRING = "? ? ? \\ ? ? ? "L; --============================================================================== currentUser: STRING ← [maxString]; session: CARDINAL ← 0; fileName: STRING ← [maxString]; file: FileHandle ← NIL; fileEnd: Position; pageBuffer: Page ← NIL; Open: PROC [name: STRING, option: Byte] RETURNS [openAlready: BOOLEAN ← TRUE] = BEGIN IF NOT String.EqualStrings[name, fileName] THEN { opener: OpenOptions = IF option = oldFile THEN old ELSE oldOrNew; Close[]; file ← OpenFile[name: name, cacheFraction: 100, options: opener]; fileName.length ← 0; String.AppendString[to: fileName, from: name]; fileEnd ← GetFileLength[file]; openAlready ← FALSE} END; Close: PROC = BEGIN IF pageBuffer # NIL THEN Deactivate[pageBuffer]; pageBuffer ← NIL; IF file # NIL THEN CloseFile[file]; file ← NIL; fileName.length ← 0; String.AppendString[to: fileName, from: voidString] END; TrashUser: PROC = BEGIN currentUser.length ← 0; String.AppendString[to: currentUser, from: voidString] END; NewLine: PROC [s: STRING] = {WriteLine[""L]; WriteString[s]}; --============================================================================== CommandInterpreter: PROC [ stream: ProtocolDefs.Handle, from: PupDefs.PupAddress] = BEGIN ENABLE ProtocolDefs.Failed => GOTO clearOut; -- other end died probably userName: BodyDefs.RName ← [BodyDefs.maxRNameLength]; password: STRING ← [maxString]; ok: BOOLEAN; IF ProtocolDefs.ReceiveByte[stream] # login THEN GOTO closeOut; -- we are quitting ProtocolDefs.ReceiveRName[stream, userName]; ProtocolDefs.ReceiveString[stream, password]; IF String.EqualStrings[userName, "Wizard.gv"L] THEN ok ← TRUE ELSE BEGIN ok ← NameInfoDefs.Authenticate[userName, password] = individual; IF ok THEN ok ← (NameInfoDefs.IsMemberClosure["Transport↑.ms"L, userName] = yes); END; IF NOT ok THEN BEGIN SendError[stream, "Login failed"L]; GOTO closeOut END; IF NOT String.EqualStrings[userName, currentUser] AND NOT String.EqualStrings[currentUser, voidString] THEN BEGIN SendError[stream, "Server in use by someone else"L]; GOTO closeOut END; currentUser.length ← 0; String.AppendString[to: currentUser, from: userName]; ProtocolDefs.SendByte[stream, login]; ProtocolDefs.SendNow[stream]; session ← session + 1; NewLine["Session "L]; WriteDecimal[session]; WriteString[" started, user is "L]; WriteLine[userName]; DO SELECT ProtocolDefs.ReceiveByte[stream] FROM --+++++++++++++++++++++++++++++++++++++++++++++++++++++ -- -- readHeaders, transmit structural info of "heap.data". -- -- We receive - just the command byte -- We send - error item or... -- (a) readHeaders command (byte) -- (b) X, number of pages in file then X items.. -- (1) Y, number of MS objects on this page (count) -- (2) page header for this page (2 words) -- (3) Y object headers (each 3 words) -- --+++++++++++++++++++++++++++++++++++++++++++++++++++++ readHeaders => BEGIN heapPages: CARDINAL; byteVec: TYPE = PACKED ARRAY [0..pageByteSize) OF Byte; packBufferVec: byteVec; packBuffer: POINTER TO byteVec ← @packBufferVec; PackPage: PROC [from: Page, to: POINTER TO byteVec] RETURNS [objects, bytes: CARDINAL] = BEGIN OPEN HeapXDefs; bpw: CARDINAL = 2; pageHdrByteSize: CARDINAL = SIZE[PageHeader] * bpw; objHdrByteSize: CARDINAL = SIZE[ObjectHeader] * bpw; offset: CARDINAL ← pageHdrByteSize; toIndex: PageByteIndex ← pageHdrByteSize; objH: LONG POINTER TO ObjectHeader; FOR i: CARDINAL IN [0..pageHdrByteSize) DO -- copy the page header to[i] ← from.bytes[i] ENDLOOP; objects ← 0; WHILE offset <= pageByteSize - objHdrByteSize DO -- copy each object header objects ← objects + 1; objH ← LOOPHOLE[from + offset / bpw]; FOR i: CARDINAL IN [0..objHdrByteSize) DO -- copy an object header to[toIndex] ← from.bytes[offset]; offset ← offset + 1; toIndex ← toIndex + 1 ENDLOOP; offset ← offset + objH.size * bpw; ENDLOOP; bytes ← toIndex END; NewLine["Reading of heap file "L]; [] ← Open[ name: "heap.data"L, option: oldFile ! CantOpen => {SendError[stream, "Unable to open file"L]; GOTO getOut}]; heapPages ← fileEnd.page + (IF fileEnd.byte = 0 THEN 0 ELSE 1); ProtocolDefs.SendByte[stream, readHeaders]; ProtocolDefs.SendCount[stream, heapPages]; ProtocolDefs.SendNow[stream]; -- help things along a little FOR i: CARDINAL IN [0..heapPages) DO bytes, objects: CARDINAL; pageBuffer ← ReadPage[ [file, i], 0 ! CantReadBackingStore, Error => { SendError[stream, "File read error"L]; GOTO getOut}]; [objects, bytes] ← PackPage[pageBuffer, packBuffer]; ProtocolDefs.SendCount[stream, objects]; ProtocolDefs.SendBytes[stream, packBuffer, bytes]; Deactivate[pageBuffer]; pageBuffer ← NIL ENDLOOP; ProtocolDefs.SendNow[stream]; Close[]; WriteLine["succeeded"L] EXITS getOut => WriteLine["failed"L] END; --+++++++++++++++++++++++++++++++++++++++++++++++++++++ -- -- open File, open a file on the server and send back some info -- -- We receive - -- (a) openFile command (byte) -- (b) file name (string) -- (c) read/write (byte) -- -- We send - an error item or... -- (a) openFile command (byte) -- (b) end of file page (count) -- (c) end of file byte (count) -- --+++++++++++++++++++++++++++++++++++++++++++++++++++++ openFile => BEGIN name: STRING ← [maxString]; oldNew: Byte; ProtocolDefs.ReceiveString[stream, name]; oldNew ← ProtocolDefs.ReceiveByte[stream]; IF NOT Open[ name: name, option: oldNew ! CantOpen => { SendError[stream, "Unable to open file"L]; NewLine["Open "L]; WriteString[name]; WriteLine[ IF oldNew = oldFile THEN " old only - failed"L ELSE " old or new - failed"L]; GOTO getOut}] THEN BEGIN NewLine["Open "L]; WriteString[name]; WriteString[ IF oldNew = oldFile THEN " old only"L ELSE " old or new"L]; WriteString[", length ("L]; WriteDecimal[fileEnd.page]; WriteString[", "L]; WriteDecimal[fileEnd.byte]; WriteLine[") OK"L] END; ProtocolDefs.SendByte[stream, openFile]; ProtocolDefs.SendCount[stream, fileEnd.page]; ProtocolDefs.SendCount[stream, fileEnd.byte]; ProtocolDefs.SendNow[stream] EXITS getOut => NULL END; --+++++++++++++++++++++++++++++++++++++++++++++++++++++ -- -- setLength, set length of file -- -- We receive - -- (a) setLength command (byte) -- (b) end of file page (count) -- (c) end of file byte (count) -- -- We send - an error item or... -- (a) setLength command (byte) -- --+++++++++++++++++++++++++++++++++++++++++++++++++++++ setLength => BEGIN p: CARDINAL; b: CARDINAL; NewLine["Set "L]; WriteString[fileName]; p ← ProtocolDefs.ReceiveCount[stream]; b ← ProtocolDefs.ReceiveCount[stream]; WriteString[" ("L]; WriteDecimal[p]; WriteString[", "L]; WriteDecimal[b]; WriteString[")"L]; IF b NOT IN [0..pageByteSize) THEN BEGIN SendError[stream, "Bad byte number"L]; GOTO getOut END; IF file = NIL THEN BEGIN SendError[stream, "No file open"L]; GOTO getOut END; SetFileLength[file, [p, b]]; fileEnd ← GetFileLength[file]; ProtocolDefs.SendByte[stream, setLength]; ProtocolDefs.SendNow[stream]; WriteLine[" OK"L]; EXITS getOut => WriteLine["failed"L]; END; --+++++++++++++++++++++++++++++++++++++++++++++++++++++ -- -- readPage, read a page from the currently open file on the server. -- -- We receive - -- (a) readPage command (byte) -- (b) page number (count) -- -- We send - an error item or... -- (a) readPage command (byte) -- (b) data from the page (bytes) -- --+++++++++++++++++++++++++++++++++++++++++++++++++++++ readPage => BEGIN pageNum: CARDINAL; WriteString["RP "L]; pageNum ← ProtocolDefs.ReceiveCount[stream]; WriteDecimal[pageNum]; IF file = NIL THEN {SendError[stream, "No file open"]; GOTO getOut}; IF fileEnd.page = 0 AND fileEnd.byte = 0 THEN { SendError[stream, "Empty file"]; GOTO getOut}; IF NOT (pageNum IN [0..fileEnd.page) OR (fileEnd.byte # 0 AND pageNum = fileEnd.page)) THEN { SendError[stream, "Bad page number for read"L]; GOTO getOut}; pageBuffer ← ReadPage[ [file, pageNum], 0 ! CantReadBackingStore, Error => { SendError[stream, "File read error"L]; GOTO getOut}]; ProtocolDefs.SendByte[stream, readPage]; ProtocolDefs.SendBytes[stream, pageBuffer, pageByteSize]; ProtocolDefs.SendNow[stream]; Deactivate[pageBuffer]; pageBuffer ← NIL; WriteString[", "] EXITS getOut => WriteLine[" failed"L]; END; --+++++++++++++++++++++++++++++++++++++++++++++++++++++ -- -- writePage, write a page onto currently open file on the server. -- -- We receive - -- (a) writePage command (byte) -- (b) page number of this page (count) -- (c) data for the page (bytes) -- -- We send - an error item or... -- (a) writePage command (byte)) -- --+++++++++++++++++++++++++++++++++++++++++++++++++++++ writePage => BEGIN pageNum: CARDINAL; WriteString["WP "L]; pageBuffer ← AllocatePage[]; pageNum ← ProtocolDefs.ReceiveCount[stream]; ProtocolDefs.ReceiveBytes[stream, pageBuffer, pageByteSize]; WriteDecimal[pageNum]; IF file = NIL THEN {SendError[stream, "No file open"]; GOTO getOut}; fileEnd ← GetFileLength[file]; IF NOT pageNum IN [0..fileEnd.page] THEN BEGIN SendError[stream, "Bad page number for write"L]; GOTO getOut END; RemapPage[pageBuffer, [file, pageNum]]; MarkStartWait[ pageBuffer ! CantWriteBackingStore, Error => { SendError[stream, "File write error"L]; GOTO getOut}]; ProtocolDefs.SendByte[stream, writePage]; ProtocolDefs.SendNow[stream]; UnmapPage[pageBuffer]; Deactivate[pageBuffer]; pageBuffer ← NIL; WriteString[", "L] EXITS getOut => WriteLine[" failed"L] END; --+++++++++++++++++++++++++++++++++++++++++++++++++++++ -- -- restartServer, start up the Grapevine server again. -- -- We receive - -- (a) restartServer command (byte) -- (b) command line (string) -- -- We send - acknowledgement --+++++++++++++++++++++++++++++++++++++++++++++++++++++ restartServer => BEGIN commandLine: STRING ← [maxString]; WriteLine["Server restart commencing..."L]; -- "START ME UP" ProtocolDefs.SendByte[stream, restartServer]; ProtocolDefs.SendNow[stream]; ProtocolDefs.DestroyStream[stream]; TemporaryBooting.BootFromVolume[Volume.systemID, ]; END; ENDCASE => BEGIN NewLine["Bad command received, stopping"L]; GOTO closeOut END; ENDLOOP; EXITS closeOut => {ProtocolDefs.DestroyStream[stream]; Close[]; TrashUser[]}; clearOut => {Close[]; TrashUser[]} END; -- of CommandLoop --============================================================================== SendError: PROC [stream: ProtocolDefs.Handle, error: STRING] = BEGIN WriteString[" (error - "L]; WriteString[error]; WriteString[") "L]; ProtocolDefs.SendByte[stream, errorCode]; ProtocolDefs.SendString[stream, error]; ProtocolDefs.SendNow[stream] END; [] ← PupDefs.PupPackageMake[]; InitializeVM[min: 2, max: 8]; Close[]; TrashUser[]; [] ← PupStream.CreatePupByteStreamListener[ GVPatchSocket, CommandInterpreter, PupStream.veryLongWait]; END.