DatagramSocketImpl.mesa
Copyright Ó 1988, 1989, 1991 by Xerox Corporation. All rights reserved.
Demers, November 15, 1988 11:24:41 am PST
Carl Hauser, November 23, 1988 3:52:27 pm PST
Willie-Sue Orr, March 14, 1989 1:45:14 pm PST
Willie-s, August 13, 1991 4:18 pm PDT
Michael Plass, August 27, 1991 2:22 pm PDT
DIRECTORY
Arpa,
ArpaUDP,
Basics,
DatagramSocket,
UnixErrno,
UnixNetInet,
UnixSysCallExtensions,
UnixSysCalls,
UnixTypes
;
DatagramSocketImpl: CEDAR PROGRAM
IMPORTS UnixErrno, UnixSysCalls, UnixSysCallExtensions
EXPORTS DatagramSocket
~ {
Parameters
maxDatagramBytes: CARD ¬ 8*1024 + 512;
Types
CHARPtr: TYPE ~ UnixTypes.CHARPtr;
FileDescriptor: TYPE ~ UnixTypes.FileDescriptor;
RES: TYPE ~ UnixTypes.SysCallResult;
Handle: TYPE ~ REF Object;
Object: PUBLIC TYPE ~ RECORD [
onlySocket: FileDescriptor
];
Procedures
Create: PUBLIC PROC [localPort: ArpaUDP.Port ¬ ArpaUDP.nullPort] RETURNS [Handle] ~ {
sIn: FileDescriptor;
res: RES;
sockAddr: UnixNetInet.SockAddrIn ¬ [];
ArpaUDP.Port and UnixNetInet.IPPort are known to conform to Basics.HWORD here ...
sockAddr.port ¬ ( SELECT localPort FROM
ArpaUDP.nullPort => UnixNetInet.unspecifiedPort,
ENDCASE => localPort );
sIn ¬ UnixSysCalls.Socket[UnixTypes.AddressFamily.inet, UnixTypes.SocketType.dgram, UnixTypes.ProtocolFamily.unspec];
IF sIn = error THEN RaiseError[];
TRUSTED { res ¬ UnixSysCalls.Bind[sIn, LOOPHOLE[@sockAddr], BYTES[UnixNetInet.SockAddrIn]] };
IF res # success THEN {
savedErrno: UnixErrno.Errno ¬ UnixErrno.GetErrno[];
[] ¬ UnixSysCalls.Close[sIn];
RaiseError[savedErrno];
};
sOut ← UnixSysCalls.Dup[sIn];
IF sIn = error THEN {
savedErrno: UnixErrno.Errno ¬ UnixErrno.GetErrno[];
[] ¬ UnixSysCalls.Close[sIn];
RaiseError[savedErrno];
};
RETURN[ NEW[Object ¬ [sIn]] ];
};
GetLocal: PUBLIC PROC [h: Handle] RETURNS [address: Arpa.Address, port: ArpaUDP.Port]
~ {
res: RES;
sockAddr: UnixNetInet.SockAddrIn;
sockAddrLen: INT ¬ BYTES[UnixNetInet.SockAddrIn];
TRUSTED { res ¬ UnixSysCalls.GetSockName[h.onlySocket, LOOPHOLE[@sockAddr], @sockAddrLen] };
IF res # success THEN RaiseError[];
RETURN [LOOPHOLE[sockAddr.addr], sockAddr.port];
};
GetMaxDatagramSize: PUBLIC PROC [h: Handle] RETURNS [maxBytes: CARD] ~ {
maxBytes ¬ maxDatagramBytes;
};
Destroy: PUBLIC PROC [h: Handle] ~ {
IF h.onlySocket # error THEN { [] ¬ UnixSysCalls.Close[h.onlySocket]; h.onlySocket ¬ error };
};
Send: PUBLIC PROC [h: Handle, toAddress: Arpa.Address, toPort: ArpaUDP.Port, b: REF TEXT, startIndex: NAT ¬ 0, count: NAT ¬ NAT.LAST]
~ {
ans: INT;
sockAddr: UnixNetInet.SockAddrIn;
IF startIndex > b.length THEN ERROR Error[$datagramTooShort];
count ¬ MIN[count, (b.length - startIndex)];
sockAddr.addr ¬ LOOPHOLE[toAddress];
sockAddr.port ¬ toPort;
TRUSTED {
ans ¬ UnixSysCalls.SendTo[
s~h.onlySocket,
msg~LOOPHOLE[LOOPHOLE[b, CHARPtr]+UNITS[TEXT[0]]+startIndex],
len~count,
flags~[],
to~LOOPHOLE[@sockAddr],
toLen~BYTES[UnixNetInet.SockAddrIn]
];
};
IF ans # count THEN RaiseError[];
};
UnsafeSend: PUBLIC UNSAFE PROC [h: Handle, toAddress: Arpa.Address, toPort: ArpaUDP.Port, b: Basics.UnsafeBlock]
~ {
ans: INT;
sockAddr: UnixNetInet.SockAddrIn;
sockAddr.addr ¬ LOOPHOLE[toAddress];
sockAddr.port ¬ toPort;
TRUSTED {
ans ¬ UnixSysCalls.SendTo[
s~h.onlySocket,
msg~LOOPHOLE[LOOPHOLE[b.base, CHARPtr]+b.startIndex],
len~b.count,
flags~[],
to~LOOPHOLE[@sockAddr],
toLen~BYTES[UnixNetInet.SockAddrIn]
];
};
IF ans # b.count THEN RaiseError[];
};
Recv: PUBLIC PROC [h: Handle, b: REF TEXT, startIndex: NAT ¬ 0, count: NAT ¬ NAT.LAST, timeoutMsec: CARD ¬ UnixSysCallExtensions.waitForever] RETURNS [nBytesRead: NAT, fromAddress: Arpa.Address, fromPort: ArpaUDP.Port]
~ {
ans: INT;
res: RES;
sockAddr: UnixNetInet.SockAddrIn;
addrLen: INT ¬ BYTES[UnixNetInet.SockAddrIn];
IF startIndex > b.maxLength THEN ERROR Error[$invalidBuffer];
count ¬ MIN[count, (b.maxLength - startIndex)];
res ¬ UnixSysCallExtensions.SetGetTimeout[h.onlySocket, timeoutMsec];
IF res # success THEN RaiseError[];
TRUSTED {
ans ¬ UnixSysCalls.RecvFrom[
fd~h.onlySocket,
buf~LOOPHOLE[LOOPHOLE[b, CHARPtr]+UNITS[TEXT[0]]+startIndex],
len~count,
flags~[],
from~LOOPHOLE[@sockAddr],
fromLen~@addrLen
];
};
IF ans < 0 THEN RaiseError[];
b.length ¬ startIndex + ans;
RETURN [ans, LOOPHOLE[sockAddr.addr], sockAddr.port];
};
UnsafeRecv: PUBLIC UNSAFE PROC [h: Handle, b: Basics.UnsafeBlock, timeoutMsec: CARD ¬ UnixSysCallExtensions.waitForever] RETURNS [nBytesRead: NAT, fromAddress: Arpa.Address, fromPort: ArpaUDP.Port]
~ {
ans: INT;
res: RES;
sockAddr: UnixNetInet.SockAddrIn;
addrLen: INT ¬ BYTES[UnixNetInet.SockAddrIn];
res ¬ UnixSysCallExtensions.SetGetTimeout[h.onlySocket, timeoutMsec];
IF res # success THEN RaiseError[];
TRUSTED {
ans ¬ UnixSysCalls.RecvFrom[
fd~h.onlySocket,
buf~LOOPHOLE[LOOPHOLE[b.base, CHARPtr]+b.startIndex],
len~b.count,
flags~[],
from~LOOPHOLE[@sockAddr],
fromLen~@addrLen
];
};
IF ans < 0 THEN RaiseError[];
b.count ¬ ans;
RETURN [ans, LOOPHOLE[sockAddr.addr], sockAddr.port];
};
Kick: PUBLIC PROC [h: Handle] ~ { NULL };
Error
Error: PUBLIC ERROR [code: ATOM] ~ CODE;
Following would need to be fixed to handle TCP stream errors ...
RaiseError: PROC [errno: UnixErrno.Errno ¬ VAL[CARD.LAST]] ~ {
code: ATOM;
IF errno = VAL[CARD.LAST] THEN errno ¬ UnixErrno.GetErrno[];
code ¬ SELECT errno FROM
EIO, ENFILE, EMFILE => $transientError,
EDESTADDRREQ, ENETDOWN, ENETUNREACH, EHOSTDOWN, EHOSTUNREACH => $unreachable,
ETIMEDOUT => $timeout,
EMSGSIZE => $datagramTooLong,
ENDCASE => $failure;
ERROR Error[code];
};
}.