DIRECTORY Arpa USING [Address, IsBroadcast, nullAddress], ArpaUDP USING [nullPort, Port], Basics USING [CopyBytes, FWORD, HWORD, UnsafeBlock], DatagramSocket USING [Create, Destroy, Error, GetLocal, Handle, Kick, Recv, Send], FinalizeOps USING [CallQueue, CreateCallQueue, EnableFinalization, FinalizeProc], Process USING [Detach], RefText USING [New, ObtainScratch, ReleaseScratch], Rope USING [ROPE], SunRPC, SunRPCAuth USING [Authenticate, AuthenticateResult, CheckReplyVerifier, Conversation, Flavor, maxValueBytes, nullFlavor], SunRPCNumbers USING [], SunRPCOnUDP, SunRPCType USING [AcceptStat, AuthStat, MsgType, RejectStat, ReplyStat, rpcVersion] ; SunRPCOnUDPImpl: CEDAR MONITOR LOCKS sd USING sd: PacketServer IMPORTS Arpa, Basics, DatagramSocket, FinalizeOps, Process, RefText, SunRPC, SunRPCAuth EXPORTS SunRPCOnUDP ~ { OPEN RPCT: SunRPCType; ROPE: TYPE ~ Rope.ROPE; Address: TYPE ~ Arpa.Address; nullAddress: Address ~ Arpa.nullAddress; Port: TYPE ~ ArpaUDP.Port; nullPort: Port ~ ArpaUDP.nullPort; UnsafeBlock: TYPE ~ Basics.UnsafeBlock; Handle: TYPE ~ REF Object; Object: TYPE ~ SunRPC.Object; Conversation: TYPE ~ SunRPCAuth.Conversation; AuthFlavor: TYPE ~ SunRPCAuth.Flavor; nullFlavor: AuthFlavor ~ SunRPCAuth.nullFlavor; AuthValue: TYPE ~ REF TEXT; Error: ERROR[code: ATOM] ~ SunRPC.Error; udpFlavor: ATOM ~ $UDP; dataBufBytes: CARDINAL ~ 8704; maxAuthBytes: CARDINAL ~ SunRPCAuth.maxValueBytes; maxRefTextLength: CARDINAL ¬ 8*1024; maxUnsafeBlockLength: CARDINAL ¬ CARDINAL.LAST - 3; -- ensures stopIndexPlusOne fields won't overflow in calls to ByteBlt maxProcessesPerServer: CARDINAL ~ 6; minTimeout: CARD ¬ 100; maxTimeout: CARD ¬ 15*1000; maxRetries: CARDINAL ¬ 20; maxReads: CARDINAL ¬ 10; -- max reads before resend retryCeiling: CARDINAL ~ 6; getTimeouts: ARRAY [0..retryCeiling] OF CARD ~ [ 250, 250, 500, 1000, 2000, 4000, 8000 ]; ComputeGetTimeout: PROC [tryNo: CARDINAL, callTime: CARD] RETURNS [getTimeout: CARD] ~ INLINE { getTimeout ¬ MAX[callTime, getTimeouts[MIN[tryNo, retryCeiling]]]; }; rwCacheSize: CARDINAL ~ 8; defaultReplyTTL: CARDINAL ¬ 5; -- seconds TextPtrFromRefText: UNSAFE PROC [block: REF READONLY TEXT] RETURNS [LONG POINTER] ~ TRUSTED INLINE { RETURN[ LOOPHOLE[block, LONG POINTER] + UNITS[TEXT[0]] ] }; PacketData: TYPE ~ REF PacketDataObject; PacketDataObject: TYPE ~ RECORD [ datagramHandle: DatagramSocket.Handle, address: Arpa.Address ¬ Arpa.nullAddress, port: ArpaUDP.Port ¬ ArpaUDP.nullPort, lastRemoteAddress: Arpa.Address ¬ Arpa.nullAddress, lastRemotePort: ArpaUDP.Port ¬ ArpaUDP.nullPort, ttl: CARDINAL ¬ 0, busy: BOOL ¬ FALSE, sendBuf: REF TEXT, recvBuf: REF TEXT, index: CARDINAL ¬ 0 ]; Create: PUBLIC PROC [remoteAddress: Address ¬ nullAddress, remotePort: Port ¬ nullPort] RETURNS [h: Handle] ~ { d: PacketData; h ¬ NEW[Object]; h.flavor ¬ udpFlavor; h.procs ¬ packetProcs; h.flavorData ¬ d ¬ NEW[PacketDataObject]; d.sendBuf ¬ RefText.ObtainScratch[dataBufBytes]; d.recvBuf ¬ RefText.ObtainScratch[dataBufBytes]; d.datagramHandle ¬ DatagramSocket.Create[]; IF remoteAddress=nullAddress THEN remoteAddress ¬ DatagramSocket.GetLocal[d.datagramHandle].address; h ¬ SetRemote[h, remoteAddress, remotePort]; [] ¬ FinalizeOps.EnableFinalization[h, fQueue]; }; GetRemote: PUBLIC PROC [h: Handle] RETURNS [remoteAddress: Address, remotePort: Port] ~ { d: PacketData ¬ NARROW[h.flavorData]; remoteAddress ¬ d.address; remotePort ¬ d.port; }; SetRemote: PUBLIC PROC [h: Handle, remoteAddress: Address, remotePort: Port] RETURNS [newH: Handle] ~ { d: PacketData ¬ NARROW[h.flavorData]; d.address ¬ remoteAddress; d.port ¬ remotePort; newH ¬ h; }; GetReplyAddress: PUBLIC PROC [h: Handle] RETURNS [remoteAddress: Address, remotePort: Port] ~ { d: PacketData ~ NARROW[h.flavorData]; RETURN[d.lastRemoteAddress, d.lastRemotePort]; }; packetProcs: REF SunRPC.ProcsObject ~ NEW[ SunRPC.ProcsObject ¬ [ destroy~DestroyPacketHandle, sendCallAndReceiveReply~SendCallAndReceiveReply, receiveAnotherReply~ReceiveAnotherReply, releaseReply~ReleaseReply, bytesRemaining~BytesRemaining, getByte~GetByte, getAlign~GetAlign, getH~GetH, getF~GetF, unsafeGetBlock~UnsafeGetBlock, getBlock~GetBlock, putByte~PutByte, putAlign~PutAlign, putH~PutH, putF~PutF, unsafePutBlock~UnsafePutBlock, putBlock~PutBlock, prepareForMessage~PrepareForMessage ]]; readerWriterProcs: REF SunRPC.ProcsObject ~ NEW[ SunRPC.ProcsObject ¬ [ destroy~DestroyReaderOrWriter, sendCallAndReceiveReply~CantSendCallAndReceiveReply, receiveAnotherReply~CantReceiveAnotherReply, releaseReply~ReleaseReply, bytesRemaining~BytesRemaining, getByte~GetByte, getAlign~GetAlign, getH~GetH, getF~GetF, unsafeGetBlock~UnsafeGetBlock, getBlock~GetBlock, putByte~PutByte, putAlign~PutAlign, putH~PutH, putF~PutF, unsafePutBlock~UnsafePutBlock, putBlock~PutBlock, prepareForMessage~PrepareForMessage ]]; DestroyPacketHandle: PROC [h: Handle] ~ { WITH h.flavorData SELECT FROM d: PacketData => { IF d.sendBuf # NIL THEN { RefText.ReleaseScratch[d.sendBuf]; d.sendBuf ¬ NIL }; IF d.recvBuf # NIL THEN { RefText.ReleaseScratch[d.recvBuf]; d.recvBuf ¬ NIL }; IF d.datagramHandle # NIL THEN { DatagramSocket.Destroy[d.datagramHandle]; d.datagramHandle ¬ NIL }; h.flavorData ¬ NIL; }; ENDCASE; }; DestroyReaderOrWriter: PROC [h: Handle] ~ { SELECT h.flavor FROM $reader, $writer => { d: PacketData ~ NARROW[h.flavorData]; d.sendBuf ¬ NIL; d.recvBuf ¬ NIL; FreeLocalHandle[h~h]; }; ENDCASE => Error[$wrongFlavor]; }; SendCallAndReceiveReply: PROC [h: Handle, timeoutMsec: CARD, retries: CARD] ~ { SendAndReceive[h, timeoutMsec, retries, TRUE]; }; CantSendCallAndReceiveReply: PROC [h: Handle, timeoutMsec: CARD, retries: CARD] ~ { Error[$wrongFlavor]; }; ReceiveAnotherReply: PROC [h: Handle, timeoutMsec: CARD] ~ { SendAndReceive[h, timeoutMsec, 0, FALSE]; }; CantReceiveAnotherReply: PROC [h: Handle, timeoutMsec: CARD] ~ { Error[$wrongFlavor]; }; SendAndReceive: PROC [h: Handle, timeoutMsec: CARD, retries: CARD, doSend: BOOL] ~ { d: PacketData ¬ NARROW[h.flavorData]; errorCode: ATOM ¬ NIL; replyVerifier: AuthValue; tryNo: CARDINAL ¬ 0; retries ¬ MIN[retries, maxRetries]; timeoutMsec ¬ MAX[timeoutMsec, minTimeout]; IF retries > 0 THEN timeoutMsec ¬ MIN[timeoutMsec, maxTimeout]; FOR tryNo: CARD IN [0 .. retries] DO IF doSend THEN { errorCode ¬ NIL; DatagramSocket.Send[d.datagramHandle, d.address, d.port, d.sendBuf ! DatagramSocket.Error => { errorCode ¬ code; CONTINUE }]; SELECT errorCode FROM NIL => NULL; $transientError => LOOP; ENDCASE => GOTO Done; }; THROUGH [0 .. maxReads) DO d.index ¬ 0; errorCode ¬ NIL; [, d.lastRemoteAddress, d.lastRemotePort] ¬ DatagramSocket.Recv[d.datagramHandle, d.recvBuf, 0, NAT.LAST, ComputeGetTimeout[tryNo, timeoutMsec] ! DatagramSocket.Error => { errorCode ¬ code; CONTINUE }]; SELECT errorCode FROM NIL => { IF d.lastRemoteAddress # d.address THEN IF NOT Arpa.IsBroadcast[d.address] THEN LOOP; { ENABLE Error => LOOP; returnedXid, returnedMsgType: CARD32; returnedXid ¬ SunRPC.GetCard32[h]; returnedMsgType ¬ SunRPC.GetCard32[h]; IF (returnedXid # h.xid) OR (returnedMsgType # ORD[RPCT.MsgType.reply]) THEN LOOP; }; { ENABLE Error => { errorCode ¬ $protocolError; GOTO Done }; replyStat, acceptStat, rejectStat, authStat: CARD32; replyFlavor: AuthFlavor; SELECT (replyStat ¬ SunRPC.GetCard32[h]) FROM ORD[RPCT.ReplyStat.msgAccepted] => { [replyFlavor, replyVerifier] ¬ SunRPC.GetAuth[h]; errorCode ¬ SELECT SunRPCAuth.CheckReplyVerifier[NARROW[h.authData], replyFlavor, replyVerifier] FROM ok => NIL, badVerifier => $badReplyVerifier, wrongVerifier => $wrongReplyVerifier, ENDCASE => ERROR; IF errorCode # NIL THEN GOTO Done; acceptStat ¬ SunRPC.GetCard32[h]; errorCode ¬ SELECT acceptStat FROM ORD[RPCT.AcceptStat.success] => NIL, -- winner! ORD[RPCT.AcceptStat.progUnavail] => $wrongProgram, ORD[RPCT.AcceptStat.progMismatch] => $wrongProgramVersion, ORD[RPCT.AcceptStat.procUnavail] => $wrongProc, ENDCASE => $protocolError; GOTO Done; }; ORD[RPCT.ReplyStat.msgDenied] => { SELECT (rejectStat ¬ SunRPC.GetCard32[h]) FROM ORD[RPCT.RejectStat.rpcMismatch] => { errorCode ¬ $wrongRPCVersion; }; ORD[RPCT.RejectStat.authError] => { authStat ¬ SunRPC.GetCard32[h]; errorCode ¬ SELECT authStat FROM ORD[RPCT.AuthStat.authBadcred] => $badCredentials, ORD[RPCT.AuthStat.authRejectedcred] => $wrongCredentials, ORD[RPCT.AuthStat.authBadverf] => $badVerifier, ORD[RPCT.AuthStat.authRejectedverf] => $wrongVerifier, ORD[RPCT.AuthStat.authTooweak] => $weakCredentials, ENDCASE => $protocolError; }; ENDCASE => { errorCode ¬ $protocolError }; GOTO Done; }; ENDCASE => { errorCode ¬ $protocolError; GOTO Done; }; }; }; $timeout => { errorCode ¬ $timeout; EXIT; -- and repeat outer loop if we should }; $transientError => { LOOP; }; $unreachable => { errorCode ¬ $unreachable; EXIT; }; ENDCASE => { errorCode ¬ $protocolError; GOTO Done; }; ENDLOOP; REPEAT Done => NULL; ENDLOOP; IF replyVerifier # NIL THEN { RefText.ReleaseScratch[replyVerifier]; replyVerifier ¬ NIL }; IF errorCode # NIL THEN { ERROR Error[errorCode] }; }; ReleaseReply: PROC [h: Handle] ~ { h.authData ¬ NIL; -- help finalization }; Server: TYPE ~ SunRPC.Server; ServerObject: TYPE ~ SunRPC.ServerObject; PacketServer: TYPE ~ REF PacketServerObject; PacketServerObject: TYPE ~ MONITORED RECORD [ datagramHandle: DatagramSocket.Handle, serverPort: ArpaUDP.Port, dead: BOOL ¬ FALSE, freeHandle: CONDITION, freeHandleIndex: CARDINAL ¬ 0, handles: SEQUENCE concurrencyPlusOne: CARDINAL OF Handle ]; myServerMgtProcs: SunRPC.ServerMgtProcs ~ NEW[SunRPC.ServerMgtProcsObject ¬ [ destroyServer~DestroyServer ]]; CreateServer: PUBLIC PROC [pgm, version: CARD, serverProc: SunRPC.ServerProc, port: Port, concurrency: CARDINAL, clientData: REF] RETURNS [s: Server] ~ { sd: PacketServer; concurrency ¬ MAX[concurrency, 1]; concurrency ¬ MIN[concurrency, maxProcessesPerServer]; sd ¬ NEW[PacketServerObject[concurrency+1]]; s ¬ NEW[ServerObject]; s.pgm ¬ pgm; s.version ¬ version; s.flavor ¬ udpFlavor; s.flavorData ¬ sd; s.mgtProcs ¬ myServerMgtProcs; sd.datagramHandle ¬ DatagramSocket.Create[port]; sd.serverPort ¬ DatagramSocket.GetLocal[sd.datagramHandle].port; s.clientData ¬ clientData; s.serverProc ¬ serverProc; FOR i: CARDINAL IN [0..concurrency+1) DO h: Handle ¬ NEW[Object]; d: PacketData ¬ NEW[PacketDataObject]; h.flavor ¬ udpFlavor; h.flavorData ¬ d; h.procs ¬ packetProcs; d.sendBuf ¬ RefText.ObtainScratch[dataBufBytes]; d.recvBuf ¬ RefText.ObtainScratch[dataBufBytes]; d.datagramHandle ¬ sd.datagramHandle; sd.handles[i] ¬ h; ENDLOOP; createdServers ¬ createdServers.SUCC; [] ¬ FinalizeOps.EnableFinalization[s, fQueue]; TRUSTED { Process.Detach[ FORK Serve[s, sd] ] }; TRUSTED { Process.Detach[ FORK AgeResults[s, sd] ] }; }; GetServerPort: PUBLIC PROC [s: Server] RETURNS [port: Port] ~ { nS: Server ~ IF s.flavor=udpFlavor THEN s ELSE Error[$wrongFlavor]; d: PacketServer ~ NARROW[s.flavorData]; RETURN[ d.serverPort ]; }; DestroyServer: PROC [s: Server] ~ { sd: PacketServer ~ NARROW[s.flavorData]; LockedDestroyServer: ENTRY PROC[ s: Server, sd: PacketServer ] ~ { IF NOT s.dead THEN destroyedServers ¬ destroyedServers.SUCC; s.dead ¬ TRUE; BROADCAST sd.freeHandle; DatagramSocket.Kick[sd.datagramHandle]; }; LockedDestroyServer[s, sd]; }; createdServers: CARD ¬ 0; droppedServers: CARD ¬ 0; destroyedServers: CARD ¬ 0; finishedServers: CARD ¬ 0; FinalizeServer: PROC [s: Server] = { IF NOT s.dead THEN { -- Can't happen unless the daemons have failed for some reason ... droppedServers ¬ droppedServers.SUCC; [] ¬ FinalizeOps.EnableFinalization[s, fQueue]; DestroyServer[s]; } ELSE { -- Normal end of life sd: PacketServer ~ NARROW[s.flavorData]; finishedServers ¬ finishedServers.SUCC; FOR i: CARDINAL IN [0 .. sd.concurrencyPlusOne) DO h: Handle ~ sd.handles[i]; d: PacketData ~ IF h=NIL THEN NIL ELSE NARROW[h.flavorData]; IF d # NIL THEN { IF d.sendBuf # NIL THEN { RefText.ReleaseScratch[d.sendBuf]; d.sendBuf ¬ NIL }; IF d.recvBuf # NIL THEN { RefText.ReleaseScratch[d.recvBuf]; d.recvBuf ¬ NIL }; d.datagramHandle ¬ NIL; }; ENDLOOP; IF sd.datagramHandle # NIL THEN { DatagramSocket.Destroy[sd.datagramHandle]; sd.datagramHandle ¬ NIL }; }; }; GetFreeHandle: ENTRY PROC [s: Server, sd: PacketServer] RETURNS [handle: Handle] ~ { WHILE NOT s.dead DO i: CARDINAL ¬ sd.freeHandleIndex; bestTTL: CARDINAL ¬ CARDINAL.LAST; bestIndex: CARDINAL ¬ sd.concurrencyPlusOne; THROUGH [0 .. sd.concurrencyPlusOne) DO h: Handle; d: PacketData; IF (i ¬ i + 1) >= sd.concurrencyPlusOne THEN i ¬ 0; h ¬ sd.handles[i]; d ¬ NARROW[h.flavorData]; IF (NOT d.busy) AND (d.ttl < bestTTL) THEN { bestTTL ¬ d.ttl; bestIndex ¬ i }; ENDLOOP; IF bestIndex < sd.concurrencyPlusOne THEN { d: PacketData; handle ¬ sd.handles[bestIndex]; d ¬ NARROW[handle.flavorData]; d.busy ¬ TRUE; RETURN; }; WAIT sd.freeHandle; ENDLOOP; }; GetThisFreeHandle: ENTRY PROC [sd: PacketServer, h: Handle] RETURNS [gotIt: BOOL] ~ { d: PacketData ¬ NARROW[h.flavorData]; IF d.busy THEN RETURN [FALSE]; RETURN [d.busy ¬ TRUE]; }; NotifyFreeHandle: ENTRY PROC [sd: PacketServer, h: Handle] ~ { d: PacketData ¬ NARROW[h.flavorData]; d.busy ¬ FALSE; BROADCAST sd.freeHandle; }; AgeResults: ENTRY PROC [s: Server, sd: PacketServer] ~ { WHILE NOT s.dead DO FOR i: CARDINAL IN [0 .. sd.concurrencyPlusOne) DO h: Handle ~ sd.handles[i]; d: PacketData ¬ NARROW[h.flavorData]; IF d.busy THEN LOOP; IF d.ttl > 0 THEN d.ttl ¬ d.ttl - 1; ENDLOOP; WAIT sd.freeHandle; ENDLOOP; }; Serve: PROC [s: Server, sd: PacketServer] ~ { h: Handle ¬ GetFreeHandle[s, sd]; d: PacketData; WHILE NOT s.dead DO ENABLE DatagramSocket.Error => { SELECT code FROM $transientError, $datagramTooShort, $datagramTooLong, $protocol => NULL; ENDCASE => s.dead ¬ TRUE; LOOP; }; d ¬ NARROW[h.flavorData]; [, d.address, d.port] ¬ DatagramSocket.Recv[sd.datagramHandle, d.recvBuf, 0, NAT.LAST]; d.index ¬ 0; { ENABLE Error => CONTINUE; msgType: CARD32; h.xid ¬ SunRPC.GetCard32[h]; msgType ¬ SunRPC.GetCard32[h]; SELECT TRUE FROM (msgType # ORD[RPCT.MsgType.call]) => { NULL; }; ENDCASE => { isDuplicate: BOOL ¬ FALSE; finger: Handle; fingerD: PacketData; FOR i: CARDINAL IN [0 .. sd.concurrencyPlusOne) DO finger ¬ sd.handles[i]; fingerD ¬ NARROW[finger.flavorData]; IF (finger # h) AND (finger.xid = h.xid) AND (fingerD.port = d.port) AND (fingerD.address = d.address) AND (fingerD.ttl > 0) THEN { isDuplicate ¬ TRUE; EXIT }; ENDLOOP; IF isDuplicate THEN { IF GetThisFreeHandle[sd, finger] THEN { TRUSTED { Process.Detach[FORK SendDuplicateReply[s, finger]] }; }; } ELSE -- not a duplicate -- { finger ¬ GetFreeHandle[s, sd]; -- may block TRUSTED { Process.Detach[FORK CallServerProcAndSendReply[s, h]] }; h ¬ finger; }; }; }; ENDLOOP; }; SendDuplicateReply: PROC [s: Server, h: Handle] ~ { d: PacketData ~ NARROW[h.flavorData]; sd: PacketServer ~ NARROW[s.flavorData]; DatagramSocket.Send[d.datagramHandle, d.address, d.port, d.sendBuf]; d.ttl ¬ MAX[d.ttl, defaultReplyTTL]; NotifyFreeHandle[sd, h]; }; CallServerProcAndSendReply: PROC [s: Server, h: Handle] ~ { sd: PacketServer ~ NARROW[s.flavorData]; errorCode: ATOM; credentials, verifier: AuthValue; sendReply: BOOL ¬ TRUE; d: PacketData ~ NARROW[h.flavorData]; d.ttl ¬ defaultReplyTTL; BEGIN { ENABLE Error => { sendReply ¬ FALSE; GOTO Out }; rpcvers, prog, vers, proc: CARD32; cFlavor, vFlavor: AuthFlavor; authResult: SunRPCAuth.AuthenticateResult; conversation: Conversation; rpcvers ¬ SunRPC.GetCard32[h]; IF (rpcvers # RPCT.rpcVersion) THEN { errorCode ¬ $wrongRPCVersion; GOTO Reply }; prog ¬ SunRPC.GetCard32[h]; vers ¬ SunRPC.GetCard32[h]; proc ¬ SunRPC.GetCard32[h]; [cFlavor, credentials] ¬ SunRPC.GetAuth[h ! Error => { errorCode ¬ $badCredentials; GOTO Reply }]; [vFlavor, verifier] ¬ SunRPC.GetAuth[h ! Error => { errorCode ¬ $badVerifier; GOTO Reply }]; [authResult, h.authFlavor, h.authData, conversation] ¬ SunRPCAuth.Authenticate[cFlavor, credentials, vFlavor, verifier]; IF authResult # ok THEN { errorCode ¬ SELECT authResult FROM badCredentials => $badCredentials, wrongCredentials => $wrongCredentials, badVerifier => $badVerifier, wrongVerifier => $wrongVerifier, ENDCASE => ERROR; GOTO Reply; }; IF prog # s.pgm THEN { errorCode ¬ $wrongProgram; GOTO Reply }; IF vers # s.version THEN { errorCode ¬ $wrongProgramVersion; GOTO Reply }; [sendReply, d.ttl] ¬ s.serverProc[h, conversation, proc, s.clientData ! Error => { errorCode ¬ code; CONTINUE }]; EXITS Reply => NULL; }; { ENABLE Error => ERROR; SELECT errorCode FROM NIL => NULL; $wrongRPCVersion => { SunRPC.StartRejectReply[h, ORD[RPCT.RejectStat.rpcMismatch]]; SunRPC.PutCard32[h, RPCT.rpcVersion]; SunRPC.PutCard32[h, RPCT.rpcVersion]; }; $badCredentials => { SunRPC.StartRejectReply[h, ORD[RPCT.RejectStat.authError]]; SunRPC.PutCard32[h, ORD[RPCT.AuthStat.authBadcred]]; }; $wrongCredentials => { SunRPC.StartRejectReply[h, ORD[RPCT.RejectStat.authError]]; SunRPC.PutCard32[h, ORD[RPCT.AuthStat.authRejectedcred]]; }; $badVerifier => { SunRPC.StartRejectReply[h, ORD[RPCT.RejectStat.authError]]; SunRPC.PutCard32[h, ORD[RPCT.AuthStat.authBadverf]]; }; $wrongVerifier => { SunRPC.StartRejectReply[h, ORD[RPCT.RejectStat.authError]]; SunRPC.PutCard32[h, ORD[RPCT.AuthStat.authRejectedverf]]; }; $weakCredentials => { SunRPC.StartRejectReply[h, ORD[RPCT.RejectStat.authError]]; SunRPC.PutCard32[h, ORD[RPCT.AuthStat.authTooweak]]; }; $wrongProgram => { SunRPC.StartAcceptReply[h, ORD[RPCT.AcceptStat.progUnavail]]; }; $wrongProgramVersion => { SunRPC.StartAcceptReply[h, ORD[RPCT.AcceptStat.progMismatch]]; SunRPC.PutCard32[h, s.version]; SunRPC.PutCard32[h, s.version]; }; $wrongProc => { SunRPC.StartAcceptReply[h, ORD[RPCT.AcceptStat.procUnavail]]; }; $abortWithoutReturn => { sendReply ¬ FALSE; }; ENDCASE => { SunRPC.StartAcceptReply[h, ORD[RPCT.AcceptStat.garbageArgs]]; }; }; EXITS Out => NULL; END; IF sendReply THEN -- send the reply -- { d: PacketData ¬ NARROW[h.flavorData]; DatagramSocket.Send[d.datagramHandle, d.address, d.port, d.sendBuf ! DatagramSocket.Error => CONTINUE]; }; h.authData ¬ NIL; -- help finalization NotifyFreeHandle[sd, h]; IF credentials # NIL THEN { RefText.ReleaseScratch[credentials]; credentials ¬ NIL }; IF verifier # NIL THEN { RefText.ReleaseScratch[verifier]; verifier ¬ NIL }; }; rwCache: PacketServer ¬ NEW[PacketServerObject[rwCacheSize]]; AllocLocalHandle: ENTRY PROC [flavor: ATOM, sd: PacketServer ¬ rwCache] RETURNS [h: Handle] ~ { IF rwCache.freeHandleIndex > 0 THEN { rwCache.freeHandleIndex ¬ rwCache.freeHandleIndex - 1; h ¬ rwCache.handles[rwCache.freeHandleIndex]; rwCache.handles[rwCache.freeHandleIndex] ¬ NIL; } ELSE { d: PacketData ¬ NEW[PacketDataObject]; h ¬ NEW[Object]; h.flavor ¬ flavor; h.flavorData ¬ d; h.procs ¬ readerWriterProcs; }; }; FreeLocalHandle: ENTRY PROC [sd: PacketServer ¬ rwCache, h: Handle] ~ { IF rwCache.freeHandleIndex < rwCacheSize THEN { rwCache.handles[rwCache.freeHandleIndex] ¬ h; rwCache.freeHandleIndex ¬ rwCache.freeHandleIndex + 1; }; }; OpenReader: PUBLIC PROC [block: REF TEXT] RETURNS [h: Handle] ~ { h ¬ AllocLocalHandle[$reader]; { d: PacketData ¬ NARROW[h.flavorData]; d.recvBuf ¬ block; d.index ¬ 0; d.recvBuf ¬ block; }; }; OpenWriter: PUBLIC PROC [maxBytes: CARDINAL] RETURNS [h: Handle] ~ { dB: REF TEXT ~ RefText.New[maxBytes]; h ¬ AllocLocalHandle[$writer]; { d: PacketData ~ NARROW[h.flavorData]; d.sendBuf ¬ dB; }; dB.length ¬ 0; }; TextFromWriter: PUBLIC PROC [h: Handle] RETURNS [output: REF TEXT] ~ { hN: Handle ~ IF h.flavor=$writer THEN h ELSE Error[$wrongFlavor]; d: PacketData ~ NARROW[hN.flavorData]; output ¬ d.sendBuf; }; BytesRemaining: PROC [h: Handle] RETURNS [bytes: CARDINAL] ~ { d: PacketData ~ NARROW[h.flavorData]; bytes ¬ d.recvBuf.length - d.index; }; GetByte: PROC [h: Handle] RETURNS [byte: BYTE] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.recvBuf; IF (d.index+BYTES[BYTE]) > dB.length THEN ERROR Error[$outOfData]; byte ¬ ORD[dB[d.index]]; d.index ¬ d.index+BYTES[BYTE]; }; GetH: PROC [h: Handle] RETURNS [hword: Basics.HWORD] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.recvBuf; IF (d.index+BYTES[Basics.HWORD]) > dB.length THEN ERROR Error[$outOfData]; hword ¬ [hi~ORD[dB[d.index]], lo~ORD[dB[d.index+1]]]; d.index ¬ d.index+BYTES[Basics.HWORD]; }; GetF: PUBLIC PROC [h: Handle] RETURNS [fword: Basics.FWORD] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.recvBuf; IF (d.index+BYTES[Basics.FWORD]) > dB.length THEN ERROR Error[$outOfData]; fword ¬ [ hi~[hi~ORD[dB[d.index]], lo~ORD[dB[d.index+1]]], lo~[hi~ORD[dB[d.index+2]], lo~ORD[dB[d.index+3]]]]; d.index ¬ d.index+BYTES[Basics.FWORD]; }; UnsafeGetBlock: UNSAFE PROC [h: Handle, block: UnsafeBlock] ~ UNCHECKED { delta: INT ¬ block.startIndex / BYTES[WORD]; -- delta is in WORDs block.base ¬ block.base + delta*UNITS[WORD]; -- base is in UNITs block.startIndex ¬ (block.startIndex - delta*BYTES[WORD]); -- index is in BYTEs IF (CARD[block.count] > maxUnsafeBlockLength) OR (UnsafeGetBlockInner[h, block] # CARD[block.count]) THEN ERROR Error[$outOfData]; }; UnsafeGetBlockInner: UNSAFE PROC [h: Handle, block: UnsafeBlock] RETURNS[bytesMoved: CARDINAL] ~ { d: PacketData ~ NARROW[h.flavorData]; IF (bytesMoved ¬ MIN[CARD[block.count], d.recvBuf.length - d.index]) > 0 THEN { TRUSTED { Basics.CopyBytes[ dstBase: block.base, dstStart: block.startIndex, srcBase: TextPtrFromRefText[d.recvBuf], srcStart: d.index, count: bytesMoved]; }; d.index ¬ d.index + bytesMoved; }; }; GetBlock: PROC [h: Handle, block: REF TEXT, startIndex, count: CARDINAL] ~ { actualCount: CARDINAL; IF startIndex > block.length THEN ERROR; count ¬ MIN[count, CARDINAL[CARDINAL[block.maxLength]-startIndex]]; TRUSTED { actualCount ¬ UnsafeGetBlockInner[h, [base~TextPtrFromRefText[block], startIndex~startIndex, count~count]] }; block.length ¬ startIndex + actualCount; IF actualCount # count THEN ERROR Error[$outOfData]; }; GetAlign: PROC [h: Handle] ~ { n: CARDINAL ; d: PacketData ~ NARROW[h.flavorData]; IF (n ¬ (d.index MOD 4)) # 0 THEN d.index ¬ d.index + 4 - n; }; PutByte: PROC [h: Handle, byte: BYTE] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.sendBuf; index: CARDINAL ¬ dB.length; IF (index + BYTES[BYTE]) > dB.maxLength THEN ERROR Error[$outOfBufferSpace]; dB.length ¬ index + BYTES[BYTE]; dB[index] ¬ VAL[byte]; }; PutH: PROC [h: Handle, hword: Basics.HWORD] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.sendBuf; index: CARDINAL ¬ dB.length; IF (index + BYTES[Basics.HWORD]) > dB.maxLength THEN ERROR Error[$outOfBufferSpace]; dB.length ¬ index + BYTES[Basics.HWORD]; dB[index] ¬ VAL[hword.hi]; dB[index+1] ¬ VAL[hword.lo]; }; PutF: PROC [h: Handle, fword: Basics.FWORD] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.sendBuf; index: CARDINAL ¬ dB.length; IF (index + BYTES[Basics.FWORD]) > dB.maxLength THEN ERROR Error[$outOfBufferSpace]; dB.length ¬ index + BYTES[Basics.FWORD]; dB[index] ¬ VAL[fword.hi.hi]; dB[index+1] ¬ VAL[fword.hi.lo]; dB[index+2] ¬ VAL[fword.lo.hi]; dB[index+3] ¬ VAL[fword.lo.lo]; }; UnsafePutBlock: UNSAFE PROC [h: Handle, block: UnsafeBlock] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.sendBuf; TRUSTED { delta: INT ¬ block.startIndex / BYTES[WORD]; -- delta in WORDs block.base ¬ block.base + delta*UNITS[WORD]; -- base in UNITs block.startIndex ¬ (block.startIndex - delta*BYTES[WORD]); -- index in BYTEs }; SELECT CARD[block.count] FROM 0 => RETURN; > maxUnsafeBlockLength => ERROR Error[$outOfBufferSpace]; ENDCASE; IF (dB.length + block.count) > dB.maxLength THEN ERROR Error[$outOfBufferSpace]; TRUSTED { Basics.CopyBytes[ dstBase: TextPtrFromRefText[dB], dstStart: dB.length, srcBase: block.base, srcStart: block.startIndex, count: block.count]; }; dB.length ¬ dB.length + block.count; }; PutBlock: PROC [h: Handle, block: REF READONLY TEXT, startIndex: CARDINAL ¬ 0, count: CARDINAL] ~ TRUSTED { IF startIndex > block.length THEN ERROR; count ¬ MIN[count, CARDINAL[CARDINAL[block.length]-startIndex]]; UnsafePutBlock[h, [base~TextPtrFromRefText[block], startIndex~startIndex, count~count]]; }; PutAlign: PROC [h: Handle, padValue: BYTE] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.sendBuf; WHILE (dB.length MOD 4) # 0 DO PutByte[h, padValue]; ENDLOOP; }; PrepareForMessage: PROC [h: Handle] ~ { d: PacketData ~ NARROW[h.flavorData]; dB: REF TEXT ~ d.sendBuf; dB.length ¬ 0; }; fQueue: FinalizeOps.CallQueue ¬ FinalizeOps.CreateCallQueue[Finalizer]; Finalizer: FinalizeOps.FinalizeProc = { WITH object SELECT FROM h: Handle => SunRPC.Destroy[h]; s: Server => FinalizeServer[s]; ENDCASE; }; }... J SunRPCOnUDPImpl.mesa Copyright Σ 1989, 1991, 1992 by Xerox Corporation. All rights reserved. Demers, November 23, 1988 2:45:39 pm PST Carl Hauser, November 22, 1988 4:01:56 pm PST Willie-Sue, March 16, 1989 7:03:43 pm PST Michael Plass, September 23, 1991 11:51 am PDT David Nichols, January 15, 1991 5:44 pm PST Willie-s, August 21, 1991 12:27 pm PDT Chauser, January 14, 1992 1:21 pm PST Christian Jacobi, July 24, 1992 2:28 pm PDT Types Parameters LOOPHOLEs Client Handles Default remote address is ME: Class procs Is it from the guy I'm interested in? Is it a reply message for this call? At this point, committed to accepting the reply message. Parse it, switching on replyStat ... Server Registration Drop the server, let finalization finish it off. Server Finalization Statistics Servers client must assure that s.flavorData=sd client must assure s.flavorData=sd $timeout, $handleDestroyed => s.dead _ TRUE; Attach the incoming datagram to the free handle ... Check RPC version (else we can't parse the message) Get . There's nothing we can do with them yet, until we've examined the credentials and verifier, but that's the way they defined the protocol. Get credentials ... Get verifier ... Authenticate ... Check program, version ... Call the server proc! Readers / Writers Serializing / Deserializing Finalization Κ •NewlineDelimiter –(cedarcode) style™code™Kšœ Οeœ=™HK™(K™-K™)K™.K™+K™&K™%K™+K˜—šΟk ˜ Kšœžœ%˜/Kšœžœ˜Kšœžœ žœžœ˜4Kšœžœ>˜RKšœ žœ@˜QKšœžœ ˜Kšœžœ&˜3Kšœžœžœ˜K˜Kšœ˜Kšœ žœi˜yKšœžœ˜K˜ Kšœ žœC˜SK˜K˜—šΟnœžœž˜Kšžœžœ˜KšžœP˜WKšžœ ˜K˜Kšžœžœ ˜head™Kšžœžœžœ˜K˜Kšœ žœ˜K˜(K˜Kšœžœ˜K˜"K˜Kšœ žœ˜'K˜Kšœžœžœ˜Kšœžœ˜K˜Kšœžœ˜-šœ žœ˜%Kšœ/˜/—Kšœ žœžœžœ˜K˜KšŸœžœžœ˜(—™ Kšœ žœ˜K˜Kšœžœ˜K˜Kšœžœ˜2Kšœžœ ˜$KšœžœžœžœΟcE˜yK˜Kšœžœ˜$K˜Kšœ žœ˜Kšœ žœ ˜K˜Kšœ žœ˜Kšœ žœ ˜3K˜Kšœžœ˜Kšœ žœžœžœ-˜YK˜šŸœžœ žœ žœžœžœžœ˜_Kšœ žœžœ˜BK˜K˜—Kšœ žœ˜K˜Kšœžœ  ˜)—™ šŸœžœžœ žœžœžœžœžœžœžœžœ˜dKš žœžœžœžœžœžœ ˜;——™K˜(šœžœžœ˜!Kšœ&˜&K˜)K˜&K˜3K˜0Kšœžœ˜Kšœžœžœ˜Kšœ žœžœ˜Kšœ žœžœ˜Kšœžœ˜Kšœ˜K˜—šŸœžœžœDžœ ˜kK˜K˜Kšœžœ ˜Kšœ˜K˜Kšœžœ˜)Kšœ0˜0Kšœ0˜0Kšœ+˜+™šžœž˜!KšœB˜B——K˜,K˜/K˜K˜K˜—šŸ œžœžœ žœ+˜UK˜Kšœžœ˜%K˜K˜K˜K˜—šŸ œžœžœ7žœ˜cK˜Kšœžœ˜%Kšœ˜Kšœ˜K˜ K˜K˜—šŸœžœžœ žœ/˜_Kšœžœ˜%Kšžœ(˜.Kšœ˜——™ šœ žœžœ˜AKšœ˜Kšœ0˜0Kšœ(˜(Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜K˜#Kšœ˜K˜—šœžœžœ˜GKšœ˜Kšœ4˜4Kšœ,˜,Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜K˜#Kšœ˜K˜—šŸœžœ˜)šžœžœž˜šœ˜Kšžœ žœžœ2žœ˜OKšžœ žœžœ2žœ˜OKšžœžœžœ@žœ˜dKšœžœ˜Kšœ˜—Kšžœ˜—Kšœ˜K˜—šŸœžœ˜+šžœ ž˜šœ˜Kšœžœ˜%Kšœ žœ˜Kšœ žœ˜K˜Kšœ˜—Kšžœ˜—K˜K˜—šŸœžœžœ žœ˜OKšœ(žœ˜.Kšœ˜—K˜šŸœžœžœ žœ˜SKšœ˜Kšœ˜K˜—šŸœžœžœžœ˜Kšœžœ˜%Kšœ žœ˜Kšž œ˜K˜K˜—šŸ œžœžœ"˜8šžœžœž˜šžœžœžœž˜2K˜Kšœžœ˜%Kšžœžœžœ˜Kšžœ žœ˜$Kšžœ˜—Kšžœ˜Kšžœ˜—K˜K˜—šŸœžœ#˜.K™"Kšœ!˜!Kšœ˜šžœžœž˜šžœž˜ šžœž˜KšœCžœ˜HKšœ'žœ™,Kšž œ žœ˜—Kšžœ˜K˜—Kšœžœ˜™3KšœMžœžœ˜WK˜ —šœžœ žœ˜Kšœ žœ˜Kšœ˜Kšœ˜šžœžœž˜šœ žœžœ˜'Kšžœ˜K˜—šžœ˜ Kšœ žœžœ˜K˜K˜šžœžœžœž˜2K˜Kšœ žœ˜$š žœžœžœžœžœ˜|Kšžœžœžœ˜"—Kšžœ˜—šžœ ˜šžœ˜šžœžœ˜'Kšžœžœ"˜?K˜—K˜—šžœ œ˜Kšœ  ˜+Kšžœžœ%˜BK˜ K˜——K˜——K˜—Kšžœ˜—K˜K˜—šŸœžœ˜3Kšœžœ˜%Kšœžœ˜(K˜DKšœžœ˜$K˜K˜K˜—šŸœžœ˜;Kšœžœ˜(Kšœ žœ˜Kšœ!˜!Kšœ žœžœ˜Kšœžœ˜%K˜šž˜šœžœžœžœ˜2Kšœžœ˜"K˜K˜*K˜K˜™3Kšœ˜šžœ žœ ˜Kšžœ!žœ ˜2——™’Kšœ˜Kšœ˜Kšœ˜—™KšœTžœ ˜b—™KšœNžœ ˜\—™Kšœx˜xšžœžœ˜šœ žœ ž˜"Kšœ"˜"Kšœ&˜&Kšœ˜Kšœ ˜ Kšžœžœ˜—Kšžœ˜ K˜——™šžœ ˜Kšžœžœ ˜/—šžœ˜Kšžœ%žœ ˜6——™Kšœežœ˜q—šž˜Kšœ žœ˜—K˜K˜—šœžœ žœ˜šžœ ž˜Kšžœžœ˜ ˜Kšœžœžœ˜=Kšœžœ ˜%Kšœžœ ˜%K˜—˜Kšœžœžœ˜;Kšœžœžœ˜4K˜—˜Kšœžœžœ˜;Kšœžœžœ˜9K˜—˜Kšœžœžœ˜;Kšœžœžœ˜4K˜—˜Kšœžœžœ˜;Kšœžœžœ˜9K˜—˜Kšœžœžœ˜;Kšœžœžœ˜4K˜—˜Kšœžœžœ˜=K˜—˜Kšœžœžœ˜>Kšœ˜Kšœ˜K˜—˜Kšœžœžœ˜=K˜—˜Kšœ žœ˜K˜—šžœ˜ Kšœžœžœ˜=K˜——K˜—šž˜Kšœžœ˜ —Kšžœ˜—K˜šžœ ˜ šžœ œ˜Kšœžœ˜%Kšœ]žœ˜gK˜——K˜Kšœ žœ ˜&K˜Kšžœžœžœ6žœ˜UKšžœ žœžœ0žœ˜LK˜——™Kšœžœ"˜=K˜š Ÿœžœžœ žœžœ ˜[Kšœ˜Kšžœ˜šžœ˜Kšœ6˜6Kšœ-˜-Kšœ+žœ˜/K˜—šžœ˜Kšœžœ˜&Kšœžœ ˜K˜K˜K˜K˜—Kšœ˜K˜—šŸœžœžœ,˜Gšžœ'žœ˜/Kšœ-˜-Kšœ6˜6K˜—K˜K˜—š Ÿ œžœžœ žœžœžœ˜AKšœ˜šœ˜Kšœžœ˜%K˜K˜ K˜Kšœ˜—K˜K˜—š Ÿ œžœžœ žœžœ˜DKšœžœžœ˜%Kšœ˜šœ˜Kšœžœ˜%K˜Kšœ˜—K˜K˜K˜—š Ÿœžœžœ žœ žœžœ˜FKšœ žœžœžœ˜AKšœžœ˜&Kšœ˜K˜—K˜—™šŸœžœ žœ žœ˜>Kšœžœ˜%K˜#K˜K˜—šŸœžœ žœžœ˜2Kšœžœ˜%Kšœžœžœ ˜Kš žœ žœžœžœžœ˜BKšœžœ˜Kšœžœžœ˜K˜K˜—šŸœžœ žœžœ˜8Kšœžœ˜%Kšœžœžœ ˜Kš žœ žœžœžœžœ˜JKšœ žœžœ˜5Kšœžœžœ˜&Kšœ˜K˜—š Ÿœžœžœ žœžœ˜?Kšœžœ˜%Kšœžœžœ ˜Kš žœ žœžœžœžœ˜JKš œžœžœžœžœ˜nKšœžœžœ˜&Kšœ˜K˜—šŸœžœžœ ˜;Kšœž œ˜ Kšœžœžœžœ ˜AKšœ žœžœ ˜@Kšœ-žœžœ ˜Ošžœžœ&žœ"žœ˜dKšžœžœ˜—K˜K˜—š Ÿœžœžœ!žœ žœ˜^Kšœ˜Kšœžœ˜%šžœžœžœ0žœ˜Ošžœ˜ šœ˜Kšœ0˜0Kšœ:˜:Kšœ˜—Kšœ˜—Kšœ˜K˜—K˜K˜—š Ÿœžœžœžœžœ˜LKšœ žœ˜Kšžœžœžœ˜(Kšœžœžœžœ˜CKšžœp˜wKšœ(˜(Kšžœžœžœ˜4Kšœ˜K˜—šŸœžœ˜Kšœž œ˜ Kšœžœ˜%Kšžœžœ žœ˜Kšœ žœžœ ˜=Kšœ-žœžœ ˜LK˜—šžœžœž˜Kšœžœ˜ Kšœžœ˜9Kšžœ˜—Kšžœ*žœžœ˜Pšžœ˜ šœ˜Kšœ5˜5Kšœ0˜0Kšœ˜—Kšœ˜—Kšœ$˜$K˜K˜—šŸœžœžœžœžœžœ žœ˜_Kšœžœ˜ Kšžœžœžœ˜(Kšœžœžœžœ˜@KšœX˜XKšœ˜K˜—šŸœžœžœ˜.Kšœžœ˜%Kšœžœžœ ˜šžœ žœž˜K˜Kšžœ˜—K˜—K˜šŸœžœ˜'Kšœžœ˜%Kšœžœžœ ˜K˜K˜K˜——™ K˜GšŸ œ žœ˜'šžœžœž˜Kšœ˜Kšœ˜Kšžœ˜—K˜—K˜—K˜—K˜—…—_„ΰ