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 };
}.