NetworkStreamSupportTCPImpl.mesa
Copyright Ó 1989, 1991 by Xerox Corporation. All rights reserved.
Demers, November 6, 1990 3:05 pm PST
Willie-s, September 30, 1991 1:13 pm PDT
DIRECTORY
Arpa,
Basics,
Convert,
IO,
NetworkStream,
NetworkStreamSupportTCP,
Rope,
UnixTypes,
UnixSysCalls
;
NetworkStreamSupportTCPImpl: CEDAR MONITOR
IMPORTS Basics, Convert, Rope, UnixSysCalls
EXPORTS NetworkStreamSupportTCP
~ {
OPEN NS: NetworkStream, NSS: NetworkStreamSupportTCP, USC: UnixSysCalls;
Types
ROPE: TYPE ~ Rope.ROPE;
PCRMsec: TYPE ~ CARD;
pcrWaitForever: PCRMsec ~ 0;
PCRFildes: TYPE ~ UnixTypes.FileDescriptor;
pcrErrorFildes: PCRFildes ~ error;
AttnType: TYPE ~ NSS.AttnType;
CC: TYPE ~ NSS.CompletionCode;
successCC: CC ~ NSS.successCC;
ioErrorCC: CC ~ 5; -- Unix EIO
addressSyntaxCC: CC ~ 1024;
StreamDescriptor: TYPE ~ REF StreamDescriptorObject;
StreamDescriptorObject: PUBLIC TYPE ~ RECORD [
descriptor: PCRFildes
];
ListenerDescriptor: TYPE ~ REF ListenerDescriptorObject;
ListenerDescriptorObject: PUBLIC TYPE ~ RECORD [
descriptor: PCRFildes
];
Address: TYPE ~ Arpa.Address;
nullAddress: Address ~ Arpa.nullAddress;
Port: TYPE ~ Basics.HWORD;
nullPort: Port ~ [0, 0];
SockAddrIN: TYPE ~ REF SockAddrINStruct;
SockAddrINStruct: TYPE ~ WORD16 MACHINE DEPENDENT RECORD [
addressFamily(0): UnixTypes.AddressFamily ¬ inet,
port(1): Port ¬ nullPort,
address(2): Address ¬ nullAddress,
zeroes(4): PACKED ARRAY[0..8) OF BYTE ¬ [0, 0, 0, 0, 0, 0, 0, 0]
];
Public Utilities
RopeFromCC: PUBLIC PROC [cc: CC] RETURNS [ROPE] ~ {
SELECT cc FROM
successCC => RETURN ["success"];
addressSyntaxCC => RETURN ["address syntax error"];
ENDCASE => RETURN [ Rope.Concat["Unix(tm) error number ", Convert.RopeFromInt[cc]] ];
};
AtomFromCC: PUBLIC PROC [cc: CC] RETURNS [atom: ATOM] ~ {
SELECT cc FROM
successCC => RETURN [$success];
addressSyntaxCC => RETURN [$addressSyntax];
ENDCASE => RETURN [ Convert.AtomFromRope[ Rope.Concat["UnixError", Convert.RopeFromInt[cc]] ] ];
};
Private Utilities
FixTimeout: PROC [ms: NS.Milliseconds] RETURNS [pcrms: PCRMsec] ~ {
pcrms ¬ (SELECT TRUE FROM
(ms = NS.waitForever) => pcrWaitForever,
(ms = NS.dontWait) => 1,
ENDCASE => ms);
};
UnFixTimeout: PROC [pcrms: PCRMsec] RETURNS [ms: NS.Milliseconds] ~ {
ms ¬ (SELECT TRUE FROM
(pcrms = NS.dontWait) => 1,
(pcrms = NS.waitForever) => pcrWaitForever,
ENDCASE => pcrms);
};
PortFromRope: PROC [r: ROPE] RETURNS [Port] ~ {
pos: INT;
lo, hi: CARD ¬ 0;
pos ¬ Rope.Find[r, ":"];
IF pos >= 0 THEN r ¬ Rope.Substr[r, pos+1];
IF Rope.IsEmpty[r] THEN RETURN [nullPort];
pos ¬ Rope.Find[r, "."];
IF pos > 0 THEN hi ¬ Convert.CardFromWholeNumberLiteral[Rope.Substr[r, 0, pos]];
IF (pos+1) < Rope.Length[r] THEN lo ¬ Convert.CardFromWholeNumberLiteral[Rope.Substr[r, pos+1]];
RETURN [ Basics.HFromCard16[(hi*256) + lo] ];
};
AddressFromRope: PROC [r: ROPE] RETURNS [address: Address] ~ {
RETURN [Convert.ArpaAddressFromRope[r]];
};
AddressAndPortFromRope: PROC [r: ROPE] RETURNS [address: Address ¬ nullAddress, port: Port ¬ nullPort] ~ {
portPos, addrLen: INT;
BEGIN
addrLen ¬ Rope.Find[r, ":"];
IF addrLen >= 0 THEN { portPos ¬ addrLen + 1; GOTO Found };
addrLen ¬ Rope.Find[r, "]"];
IF addrLen >= 0 THEN { addrLen ¬ addrLen + 1; portPos ¬ addrLen; GOTO Found };
portPos ¬ addrLen ¬ Rope.Length[r];
EXITS
Found => NULL;
END;
address ¬ AddressFromRope[Rope.Substr[r, 0, addrLen]]; -- nullAddress if empty rope
port ¬ PortFromRope[Rope.Substr[r, portPos]]; -- nullPort if empty rope
};
RopeFromAddressAndPort: PROC [address: Address ¬ nullAddress, port: Port ¬ nullPort] RETURNS [r: ROPE ¬ NIL] ~ {
IF address # nullAddress THEN r ¬ Convert.RopeFromArpaAddress[address];
IF port # nullPort THEN r ¬ Rope.Cat[r, ":",
Convert.RopeFromCard[Basics.Card16FromH[port]]];
};
SockAddrINFromRope: PROC [r: ROPE] RETURNS [cc: CC ¬ successCC, inap: SockAddrIN] ~ {
ENABLE Convert.Error => { cc ¬ addressSyntaxCC; inap ¬ NIL; CONTINUE };
inap ¬ NEW[ SockAddrINStruct ¬ [] ];
[address~inap.address, port~inap.port] ¬ AddressAndPortFromRope[r];
};
RopeFromSockAddrIN: PROC [inap: SockAddrIN] RETURNS [r: ROPE] ~ {
r ¬ RopeFromAddressAndPort[inap.address, inap.port];
};
Glue
GetCC: PROC RETURNS [CC] ~ TRUSTED MACHINE CODE { "XR←GetErrno" };
GCreateStreamFildes: PROC [inap: SockAddrIN, timeout: PCRMsec] RETURNS [PCRFildes] ~ TRUSTED MACHINE CODE { "XR←NSSTCPCreateStreamFildes" };
GDestroyStreamFildes: PROC [sock: PCRFildes, abort: INT] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPDestroyStreamFildes" };
GAddressesFromStreamFildes: PROC [sock: PCRFildes, local: SockAddrIN, remote: SockAddrIN] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPAddressesFromStreamFildes" };
GSend: PROC [sock: PCRFildes, buf: POINTER TO Basics.RawBytes, nBytes: INT] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPSend" };
GSetPutTimeout: PROC [sock: PCRFildes, timeout: PCRMsec] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←SetPutTimeout" };
GGetPutTimeout: PROC [sock: PCRFildes] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←GetPutTimeout" };
GSendAttn: PROC [sock: PCRFildes, attnType: AttnType] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPSendAttn" };
GReceive: UNSAFE PROC [sock: PCRFildes, buf: POINTER TO Basics.RawBytes, nBytes: INT] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPReceive" };
GSetGetTimeout: PROC [sock: PCRFildes, timeout: PCRMsec] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←SetGetTimeout" };
GGetGetTimeout: PROC [sock: PCRFildes] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←GetGetTimeout" };
GInputReady: PROC [sock: PCRFildes, timeout: PCRMsec] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPInputReady" };
GWaitOOBAttn: PROC [sock: PCRFildes, timeout: PCRMsec] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPWaitOOBAttn" };
GAtIBAttn: PROC [sock: PCRFildes] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPAtIBAttn" };
GCreateListenerFildes: PROC [inap: SockAddrIN] RETURNS [PCRFildes] ~ TRUSTED MACHINE CODE { "XR←NSSTCPCreateListenerFildes" };
GDestroyListenerFildes: PROC [listener: PCRFildes] RETURNS[INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPDestroyListenerFildes" };
GAddressFromListenerFildes: PROC [listener: PCRFildes, local: SockAddrIN] RETURNS [INT] ~ TRUSTED MACHINE CODE { "XR←NSSTCPAddressFromListenerFildes" };
GAccept: PROC [listener: PCRFildes] RETURNS [PCRFildes] ~ TRUSTED MACHINE CODE { "XR←NSSTCPAccept" };
Stream Operations
CreateStreamDescriptor: PUBLIC PROC [remote: ROPE, timeout: NS.Milliseconds]
RETURNS [cc: CC ¬ successCC, sd: StreamDescriptor ¬ NIL] ~ {
fd: PCRFildes;
ina: SockAddrIN;
[cc, ina] ¬ SockAddrINFromRope[remote];
IF cc # successCC
THEN RETURN;
fd ¬ GCreateStreamFildes[ina, timeout];
IF fd = pcrErrorFildes
THEN cc ¬ GetCC[]
ELSE sd ¬ NEW [ StreamDescriptorObject ¬ [fd] ];
};
DestroyStreamDescriptor: PUBLIC PROC [sd: StreamDescriptor, abort: BOOL]
RETURNS [cc: CC ¬ successCC] ~ {
ans: INT ¬ GDestroyStreamFildes[sd.descriptor, IF abort THEN 1 ELSE 0];
IF ans = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
AddressesFromStreamDescriptor: PUBLIC PROC [sd: StreamDescriptor]
RETURNS [cc: CC ¬ successCC, local: ROPE ¬ NIL, remote: ROPE ¬ NIL] ~ {
ls: SockAddrIN ¬ NEW[ SockAddrINStruct ];
rs: SockAddrIN ¬ NEW[ SockAddrINStruct ];
ans: INT ¬ GAddressesFromStreamFildes[sd.descriptor, ls, rs];
IF ans = (-1)
THEN { cc ¬ GetCC[]; RETURN };
local ¬ RopeFromSockAddrIN[ls];
remote ¬ RopeFromSockAddrIN[rs];
};
Send: PUBLIC PROC [sd: StreamDescriptor, block: IO.UnsafeBlock]
RETURNS [cc: CC ¬ successCC] ~ {
ans: INT;
ans ¬ GSend[sd.descriptor, block.base + block.startIndex, block.count];
IF ans = (-1) THEN { cc ¬ GetCC[]; RETURN };
IF ans # block.count THEN { cc ¬ ioErrorCC; RETURN };
};
SetPutTimeout: PUBLIC PROC [sd: StreamDescriptor, timeout: NS.Milliseconds]
RETURNS [cc: CC ¬ successCC] ~ {
IF GSetPutTimeout[sd.descriptor, FixTimeout[timeout]] = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
GetPutTimeout: PUBLIC PROC [sd: StreamDescriptor] RETURNS [cc: CC ¬ successCC, timeout: NS.Milliseconds ¬ 0] ~ {
ans: INT ¬ GGetPutTimeout[sd.descriptor];
IF ans = (-1)
THEN { cc ¬ GetCC[]; RETURN };
timeout ¬ UnFixTimeout[LOOPHOLE[ans]];
};
SendAttn: PUBLIC PROC [sd: StreamDescriptor, attnType: AttnType]
RETURNS [cc: CC ¬ successCC] ~ {
IF GSendAttn[sd.descriptor, attnType] = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
Receive: PUBLIC UNSAFE PROC [sd: StreamDescriptor, block: IO.UnsafeBlock]
RETURNS [cc: CC ¬ successCC, nBytesReceived: INT] ~ {
TRUSTED {
nBytesReceived ¬ USC.Read[sd.descriptor, LOOPHOLE[block.base+block.startIndex], block.count] };
IF nBytesReceived = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
SetGetTimeout: PUBLIC PROC [sd: StreamDescriptor, timeout: NS.Milliseconds]
RETURNS [cc: CC ¬ successCC] ~ {
IF GSetGetTimeout[sd.descriptor, FixTimeout[timeout]] = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
GetGetTimeout: PUBLIC PROC [sd: StreamDescriptor] RETURNS [cc: CC ¬ successCC, timeout: NS.Milliseconds ¬ 0] ~ {
ans: INT ¬ GGetGetTimeout[sd.descriptor];
IF ans = (-1)
THEN { cc ¬ GetCC[]; RETURN };
timeout ¬ UnFixTimeout[LOOPHOLE[ans]];
};
InputReady: PUBLIC PROC [sd: StreamDescriptor, wait: BOOL]
RETURNS [cc: CC ¬ successCC, inputReady: BOOL ¬ FALSE] ~ {
ans: INT;
timeout: PCRMsec ¬ 0;
IF wait THEN {
[cc, timeout] ¬ GetGetTimeout[sd];
IF cc # successCC THEN RETURN;
};
IF (ans ¬ GInputReady[sd.descriptor, timeout]) = (-1)
THEN { cc ¬ GetCC[]; RETURN };
inputReady ¬ (ans > 0);
};
WaitOOBAttn: PUBLIC PROC [sd: StreamDescriptor, timeout: NS.Milliseconds]
RETURNS [cc: CC ¬ successCC, attnType: AttnType] ~ {
attnType ¬ 0; -- the only one there is!
IF GWaitOOBAttn[sd.descriptor, FixTimeout[timeout]] = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
AtIBAttn: PUBLIC PROC [sd: StreamDescriptor] RETURNS [cc: CC ¬ successCC, atIBAttn: BOOL ¬ FALSE] ~ {
ans: INT;
IF (ans ¬ GAtIBAttn[sd.descriptor]) = (-1)
THEN { cc ¬ GetCC[]; RETURN };
atIBAttn ¬ (ans > 0);
};
Listener Operations
CreateListenerDescriptor: PUBLIC PROC [local: ROPE ¬ NIL]
RETURNS [cc: CC, ld: ListenerDescriptor ¬ NIL] ~ {
fd: PCRFildes;
ina: SockAddrIN;
[cc, ina] ¬ SockAddrINFromRope[local];
IF cc # successCC
THEN RETURN;
fd ¬ GCreateListenerFildes[ina];
IF fd = pcrErrorFildes
THEN { cc ¬ GetCC[]; RETURN };
ld ¬ NEW [ ListenerDescriptorObject ¬ [fd] ];
};
DestroyListenerDescriptor: PUBLIC PROC [ld: ListenerDescriptor]
RETURNS [cc: CC ¬ successCC] ~ {
IF GDestroyListenerFildes[ld.descriptor] = (-1)
THEN { cc ¬ GetCC[]; RETURN };
};
AddressFromListenerDescriptor: PUBLIC PROC [ld: ListenerDescriptor]
RETURNS [cc: CC ¬ successCC, local: ROPE ¬ NIL] ~ {
ls: SockAddrIN ¬ NEW[ SockAddrINStruct ];
IF GAddressFromListenerFildes[ld.descriptor, ls] = (-1)
THEN { cc ¬ GetCC[]; RETURN };
local ¬ RopeFromSockAddrIN[ls];
};
AcceptConnection: PUBLIC PROC [ld: ListenerDescriptor]
RETURNS [cc: CC ¬ successCC, sd: StreamDescriptor ¬ NIL] ~ {
fd: PCRFildes ¬ GAccept[ld.descriptor];
IF fd = pcrErrorFildes
THEN { cc ¬ GetCC[]; RETURN };
sd ¬ NEW [ StreamDescriptorObject ¬ [fd] ];
};
}.