<> <> <> <> <> <> <> DIRECTORY FS USING [Error, StreamOpen], GVPDefs, IO USING [Close, GetLength, PutChar, PutF, PutFR, PutText, STREAM, SetIndex, SetLength, UnsafeGetBlock, UnsafePutBlock], GVProtocol USING [CreateStream, Close, Failed, Handle, ReceiveByte, ReceiveBytes, ReceiveCount, ReceiveGVString, SendByte, SendBytes, SendCount, SendNow, SendRName, SendGVString], PupDefs USING [PupAddress, PupNameLookup, PupNameTrouble, PupPackageDestroy, PupPackageMake, PupSocketID], Rope USING [Concat, Fetch, Length], UserCredentials USING [Get]; GVPDriver: CEDAR PROGRAM IMPORTS FS, GVPDefs, IO, GVProtocol, PupDefs, Rope, UserCredentials EXPORTS GVPDefs = BEGIN OPEN GVPDefs; byteStream: GVProtocol.Handle _ NIL; <> <> KillByteStream: PROC[h: GVPRef] = BEGIN IF byteStream#NIL THEN BEGIN GVProtocol.Close[byteStream]; h.logStream.PutText["\nConnection with server broken\n"] END; byteStream _ NIL END; <> <> CheckByteStream: PROC[h: GVPRef] RETURNS [r: ROPE _ NIL]= BEGIN IF byteStream=NIL THEN r _ ConnectToServer[h] END; <> <> <> <> <> ConnectToServer: PROC[h: GVPRef] RETURNS [r: ROPE _ NIL] = BEGIN serverAddress: PupDefs.PupAddress; GVPatchSocket: PupDefs.PupSocketID = [0, 47B]; user, password, server: ROPE; server _ GetServerName[]; Set[Rope.Concat["Trying to connect to server ", server]]; serverAddress _ PupDefs.PupNameLookup[GVPatchSocket, server ! PupDefs.PupNameTrouble => BEGIN r _ IO.PutFR["Name lookup trouble, %g", [rope[e]]]; GOTO fail END]; byteStream _ GVProtocol.CreateStream[serverAddress, none, 600 ! GVProtocol.Failed => BEGIN r _ "Unable to open byte stream"; GOTO fail END]; [user, password] _ UserCredentials.Get[]; GVProtocol.SendByte[byteStream, login]; GVProtocol.SendRName[byteStream, user]; GVProtocol.SendGVString[byteStream, password]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, login ! GVProtocol.Failed => BEGIN r _ "Server timed out during login"; GOTO fail END]; IF r#NIL THEN GOTO fail; h.logStream.PutF["\nConnected to Grapevine server %l%g%l\n", [rope["b"]], [rope[server]], [rope[" "]]]; Set["Connected to server"] EXITS fail => KillByteStream[h]; END; <> <> <> <> RestartServer: PUBLIC PROC [h: GVPRef, line: ROPE] RETURNS[r: ROPE] = BEGIN ENABLE GVProtocol.Failed => {r _ "Byte stream trouble"; KillByteStream[h]; GOTO fail}; remcm: IO.STREAM = FS.StreamOpen[fileName: "rem.cm", accessOptions: create ! FS.Error => {r _ "Unable to open local file rem.cm"; GOTO fail}]; Set["Creating local file rem.cm"]; FOR i: INT IN [0..Rope.Length[line]) DO remcm.PutChar[Rope.Fetch[line, i]] ENDLOOP; remcm.PutChar['\n]; remcm.Close[]; r _ CheckByteStream[h]; IF r#NIL THEN RETURN; r _ WriteFile[h, "rem.cm"]; IF r#NIL THEN RETURN; Set["Restarting server"]; GVProtocol.SendByte[byteStream, restartServer]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, restartServer]; IF r#NIL THEN GOTO fail; h.logStream.PutF["\n%lServer restarted%l with command - %g\n", [rope["b"]], [rope[" "]], [rope[line]]]; Set[]; KillByteStream[h] EXITS fail => NULL END; <> <> <> <> ServerError: PROC [h: GVPRef, command: Byte] RETURNS [r: ROPE] = BEGIN reply: Byte _ GVProtocol.ReceiveByte[byteStream]; IF reply = errorCode THEN BEGIN r _ Rope.Concat["Server: ", GVProtocol.ReceiveGVString[byteStream]] END ELSE IF reply # command THEN ERROR GVProtocol.Failed[protocolError, "?? reply # command"] END; <> <> <> <> <> GetHeapFile: PUBLIC PROC [h: GVPRef] RETURNS [r: ROPE _ NIL] = BEGIN ENABLE GVProtocol.Failed => {r _ "Byte stream trouble"; KillByteStream[h]; GOTO fail}; bothHdrByteSize: CARDINAL = pageHdrByteSize+objHdrByteSize; fileStream: IO.STREAM; mapStream: IO.STREAM = FS.StreamOpen[fileName: "heap.map", accessOptions: create ! FS.Error => {r _ "Trouble opening heap.map here"; GOTO fail}]; pageBuffer: REF PageByteVec = NEW[PageByteVec]; RxVec: TYPE = PACKED ARRAY [0..bothHdrByteSize) OF Byte; rxBuffer: REF RxVec _ NEW[RxVec]; toIndex: CARDINAL; heapSize, mapSize: CARDINAL; heapByteSize: INT; r _ CheckByteStream[h]; IF r#NIL THEN GOTO fail; r _ ReadFile[h, "heap.segments"]; IF r#NIL THEN GOTO fail; Set["Reading heap structure"]; GVProtocol.SendByte[byteStream, readHeaders]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, readHeaders]; IF r#NIL THEN GOTO fail; heapSize _ GVProtocol.ReceiveCount[byteStream]; -- pages mapSize _ (heapSize/segSize)*segSize; heapByteSize _ LONG[heapSize]*bytesPerPage; fileStream _ FS.StreamOpen[fileName: "heap.data", accessOptions: create, createByteCount: heapByteSize ! FS.Error => {r _ "Trouble opening heap.data here"; GOTO fail} ]; FOR curPage: CARDINAL IN [1..heapSize] DO -- copy one page objCount: CARDINAL _ GVProtocol.ReceiveCount[byteStream]; IF curPage MOD 10 = 0 THEN Set[IO.PutFR["Reading page %d of %d", [cardinal[curPage]], [cardinal[heapSize]]]]; TRUSTED { GVProtocol.ReceiveBytes[byteStream, [LOOPHOLE[rxBuffer], 0, bothHdrByteSize]]; }; FOR i: CARDINAL IN [0..bothHdrByteSize) DO -- copy page and first object header pageBuffer[i] _ rxBuffer[i] ENDLOOP; toIndex _ pageHdrByteSize; TRUSTED { THROUGH [0..objCount-1) DO foo: LONG POINTER = LOOPHOLE[pageBuffer]; objH: LONG POINTER TO ObjectHeader = foo + toIndex/bytesPerWord; toIndex _ toIndex+objHdrByteSize+objH.size*bytesPerWord; GVProtocol.ReceiveBytes[byteStream, [LOOPHOLE[rxBuffer], 0, objHdrByteSize]]; FOR i: CARDINAL IN [0..objHdrByteSize) DO pageBuffer[toIndex+i] _ rxBuffer[i] ENDLOOP ENDLOOP; }; fileStream.UnsafePutBlock[[LOOPHOLE[pageBuffer], 0, pageByteSize]]; ENDLOOP; h.logStream.PutF["\nFile %lheap.data%l created, size is %d bytes\n", [rope["b"]], [rope[" "]], [cardinal[LONG[heapSize]*pageByteSize]]]; FOR i: CARDINAL IN [0..mapSize) DO mapStream.PutChar[emptyPage] ENDLOOP; mapStream.Close[]; h.logStream.PutF["\nFile %lheap.map%l created, size is %d bytes\n", [rope["b"]], [rope[" "]], [cardinal[mapSize]]]; fileStream.Close[]; r _ CheckStructure[h] EXITS fail => NULL END; <> <> <> <> OpenFile: PROC[h: GVPRef, fileName: ROPE, oldNew: Byte] RETURNS [r: ROPE _ NIL, page, byte: CARDINAL] = BEGIN ENABLE GVProtocol.Failed => {r _ "Byte stream trouble"; GOTO fail}; r _ CheckByteStream[h]; IF r#NIL THEN GOTO fail; GVProtocol.SendByte[byteStream, openFile]; GVProtocol.SendGVString[byteStream, fileName]; GVProtocol.SendByte[byteStream, oldNew]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, openFile]; IF r = NIL THEN BEGIN page _ GVProtocol.ReceiveCount[byteStream]; byte _ GVProtocol.ReceiveCount[byteStream] END EXITS fail => KillByteStream[h] END; <> <> SetFileLength: PROC[h: GVPRef, page, byte: CARDINAL] RETURNS [r: ROPE _ NIL] = BEGIN ENABLE GVProtocol.Failed => {r _ "Byte stream trouble"; GOTO fail}; r _ CheckByteStream[h]; IF r#NIL THEN GOTO fail; GVProtocol.SendByte[byteStream, setLength]; GVProtocol.SendCount[byteStream, page]; GVProtocol.SendCount[byteStream, byte]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, setLength]; EXITS fail => KillByteStream[h] END; <> <> ReadPage: PUBLIC PROC[h: GVPRef, page: CARDINAL, pageBuffer: REF PageByteVec] RETURNS[r: ROPE _ NIL] = BEGIN ENABLE GVProtocol.Failed => {r _ "Byte stream trouble"; GOTO fail}; r _ CheckByteStream[h]; IF r#NIL THEN GOTO fail; GVProtocol.SendByte[byteStream, readPage]; GVProtocol.SendCount[byteStream, page]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, readPage]; IF r#NIL THEN GOTO fail; TRUSTED { GVProtocol.ReceiveBytes[byteStream, [LOOPHOLE[pageBuffer], 0, pageByteSize]]; }; EXITS fail => KillByteStream[h] END; <> <> <> WritePage: PUBLIC PROC[h: GVPRef, page: CARDINAL, pageBuffer: REF PageByteVec] RETURNS[r: ROPE _ NIL] = BEGIN ENABLE GVProtocol.Failed => {r _ "Byte stream trouble"; GOTO fail}; r _ CheckByteStream[h]; IF r#NIL THEN GOTO fail; GVProtocol.SendByte[byteStream, writePage]; GVProtocol.SendCount[byteStream, page]; GVProtocol.SendBytes[byteStream, [LOOPHOLE[pageBuffer], 0, pageByteSize]]; GVProtocol.SendNow[byteStream]; r _ ServerError[h, writePage]; EXITS fail => KillByteStream[h] END; <> <> ReadFile: PUBLIC PROC[h: GVPRef, name: ROPE] RETURNS[r: ROPE _ NIL] = BEGIN page, byte, pagesToRead: CARDINAL; fileStream: IO.STREAM; pageBuffer: REF PageByteVec _ NIL; fileByteSize: INT; fileStream _ FS.StreamOpen[fileName: name, accessOptions: create ! FS.Error => {r _ "Trouble opening local file"; GOTO fail}]; [r, page, byte] _ OpenFile[h, name, oldFile]; IF r#NIL THEN GOTO fail; Set[Rope.Concat["Reading file ", name]]; pagesToRead _ IF byte=0 AND page#0 THEN page ELSE page+1; fileByteSize _ LONG[page]*pageByteSize+byte; pageBuffer _ NEW[PageByteVec]; FOR i: CARDINAL IN [0..pagesToRead) DO r _ ReadPage[h, i, pageBuffer]; IF r#NIL THEN GOTO fail; fileStream.UnsafePutBlock[[LOOPHOLE[pageBuffer], 0, pageByteSize]]; ENDLOOP; fileStream.SetLength[fileByteSize]; fileStream.Close[]; h.logStream.PutF["\nFile %l%g%l read from server, size is %d bytes\n", [rope["b"]], [rope[name]], [rope[" "]], [cardinal[fileByteSize]]] EXITS fail => NULL END; <> <> WriteFile: PUBLIC PROC[h: GVPRef, name: ROPE] RETURNS[r: ROPE _ NIL] = BEGIN page, byte, pagesToWrite: CARDINAL; length: INT; fileStream: IO.STREAM; pageBuffer: REF PageByteVec _ NIL; fileStream _ FS.StreamOpen[fileName: name, accessOptions: read ! FS.Error => {r _ "Trouble opening local file"; GOTO fail}]; [r, page, byte] _ OpenFile[h, name, oldOrNewFile]; IF r#NIL THEN GOTO fail; Set[Rope.Concat["Writing file ", name]]; length _ fileStream.GetLength[]; pagesToWrite _ (length+pageByteSize-1) / pageByteSize; page _ length / pageByteSize; byte _ length MOD pageByteSize; pageBuffer _ NEW[PageByteVec]; FOR i: CARDINAL IN [0..pagesToWrite) DO TRUSTED { [] _ fileStream.UnsafeGetBlock[[LOOPHOLE[pageBuffer], 0, pageByteSize]]; }; r _ WritePage[h, i, pageBuffer]; IF r#NIL THEN {pageBuffer _ NIL; GOTO fail} ENDLOOP; r _ SetFileLength[h, page, byte]; IF r#NIL THEN GOTO fail; h.logStream.PutF["\nFile %l%g%l written to server, size is %d bytes\n", [rope["b"]], [rope[name]], [rope[" "]], [cardinal[length]]] EXITS fail => NULL END; <> <> SetServerLength: PUBLIC PROC[h: GVPRef, name: ROPE, pages, bytes: CARDINAL] RETURNS[r: ROPE _ NIL] = BEGIN [r: r] _ OpenFile[h, name, oldFile]; IF r#NIL THEN RETURN; r _ SetFileLength[h, pages, bytes]; IF r#NIL THEN RETURN; h.logStream.PutF["\nLength of server file %l%g%l set to %d pages, %d bytes\n", [rope["b"]], [rope[name]], [rope[" "]], [cardinal[pages]], [cardinal[bytes]]] END; <> SetLocalLength: PUBLIC PROC[h: GVPRef, name: ROPE, pages, bytes: CARDINAL] RETURNS[r: ROPE _ NIL] = BEGIN fileStream: IO.STREAM = FS.StreamOpen[fileName: name, accessOptions: write ! FS.Error => BEGIN r _ "Unable to open local file"; GOTO fail END]; fileStream.SetLength[pages*bytesPerPage+bytes]; fileStream.Close[]; h.logStream.PutF["\nLength of local file %l%g%l set to %d pages, %d bytes\n", [rope["b"]], [rope[name]], [rope[" "]], [cardinal[pages]], [cardinal[bytes]]] EXITS fail => NULL END; <> <> <> ReadServerPage: PUBLIC PROC[h: GVPRef, page: CARDINAL, pageBuffer: REF PageByteVec] RETURNS [r: ROPE _ NIL] = BEGIN Set["Fetching page from server"]; [r: r] _ OpenFile[h, "heap.data", oldFile]; IF r#NIL THEN RETURN; r _ ReadPage[h, page, pageBuffer]; IF r#NIL THEN RETURN; h.heapStream.SetIndex[LONG[page] * bytesPerPage]; [] _ h.heapStream.UnsafePutBlock[[LOOPHOLE[pageBuffer], 0, bytesPerPage]]; h.logStream.PutF["\nHeap page %d read from server\n", [cardinal[page]]]; SetPageState[page, fullPage] END; <> WriteServerPage: PUBLIC PROC[h: GVPRef, page: CARDINAL, pageBuffer: REF PageByteVec] RETURNS [r: ROPE _ NIL] = BEGIN h.heapStream.SetIndex[LONG[page] * bytesPerPage]; TRUSTED { [] _ h.heapStream.UnsafeGetBlock[[LOOPHOLE[pageBuffer], 0, bytesPerPage]]; }; [r: r] _ OpenFile[h, "heap.data", oldFile]; IF r#NIL THEN RETURN; r _ WritePage[h, page, pageBuffer]; IF r#NIL THEN RETURN; h.logStream.PutF["\nHeap page %d updated on server\n", [cardinal[page]]] END; <> DriverInit: PUBLIC PROC = BEGIN PupDefs.PupPackageMake[] END; DriverTidyUp: PUBLIC PROC = BEGIN PupDefs.PupPackageDestroy[] END; END.