MODULE UDP;
IMPORT SYSTEM, IP, WSock32, KernelLog;
CONST
Ok* = 0; AddressInUse* = 3501; Timeout* = 3502; BufferOverflow* = 3503; AlreadyBlocked* = 3504;
unknown = 1; IPAdrLen = 4;
NilPort* = 0;
TYPE
TYPE
Socket* = OBJECT
VAR sock: WSock32.Socket;
PROCEDURE & Open*( lport: LONGINT; VAR res: LONGINT );
VAR sadr: WSock32.sockaddrIn; err: LONGINT;
BEGIN
sock := WSock32.socket( WSock32.PFINet, WSock32.SockDGram, WSock32.IPProtoUDP );
IF sock # WSock32.InvalidSocket THEN
sadr.sinFamily := WSock32.PFINet; sadr.sinAddr := 0;
IF lport # NilPort THEN sadr.sinPort := WSock32.htons( SHORT( lport ) ) ELSE sadr.sinPort := 0 END;
res := WSock32.bind( sock, sadr, SYSTEM.SIZEOF( WSock32.sockaddrIn ) );
IF res # Ok THEN
err := WSock32.WSAGetLastError(); SockFinalizer( SELF ); res := unknown;
ELSE res := Ok
END
ELSE res := unknown;
END;
IF trace THEN
KernelLog.String( "UDP.Open : " ); KernelLog.Int( lport, 1 ); KernelLog.String( "(" ); KernelLog.Int( res, 1 );
KernelLog.String( ")" ); KernelLog.Ln;
END;
END Open;
PROCEDURE Send*( fip: IP.Adr; fport: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: LONGINT );
VAR sadr: WSock32.sockaddrIn; err: LONGINT;
BEGIN
ASSERT ( LEN( data ) >= (ofs + len) );
IF (fip.usedProtocol = IP.IPv4) THEN
SYSTEM.MOVE( SYSTEM.ADR( fip ), SYSTEM.ADR( sadr.sinAddr ), IPAdrLen );
sadr.sinFamily := WSock32.PFINet; sadr.sinPort := WSock32.htons( SHORT( fport ) );
res := WSock32.sendto( sock, data[ofs], len, 0, sadr, SYSTEM.SIZEOF( WSock32.sockaddrIn ) );
IF res = len THEN res := Ok; ELSE err := WSock32.WSAGetLastError(); res := unknown; END;
ELSE res := unknown;
END;
IF trace THEN
IF (fip.usedProtocol = IP.IPv4) THEN
KernelLog.String( "UDP.Send : " ); KernelLog.Int( fip.ipv4Adr, 1 ); KernelLog.String( " , " ); KernelLog.Int( fport, 1 );
KernelLog.String( "(" ); KernelLog.Int( res, 1 ); KernelLog.String( ")" ); KernelLog.Ln;
ELSE
KernelLog.String("UDP.Send : Error, only works with IPv4 addresses!"); KernelLog.Ln;
END;
END;
END Send;
PROCEDURE Receive*( VAR data: ARRAY OF CHAR; ofs, size, ms: LONGINT; VAR fip: IP.Adr;
VAR fport, len, res: LONGINT );
VAR sadr: WSock32.sockaddrIn; err: LONGINT; l: LONGINT;
ret: LONGINT; fdset: WSock32.FDSet; avail: BOOLEAN; time: WSock32.TimeVal;
BEGIN
ASSERT ( ofs+size <= LEN( data ) );
l := SYSTEM.SIZEOF( WSock32.sockaddrIn );
IF ms=-1 THEN
avail := TRUE;
ELSE
ret := WSock32.ioctlsocket( sock, WSock32.FIONRead, res );
IF ret # 0 THEN
err := WSock32.WSAGetLastError(); res := unknown; avail := FALSE;
ELSE
avail := res > 0;
IF ~avail THEN
fdset.fdcount := 1; fdset.socket[0] := sock;
NEW(time);
time.sec := ms DIV 1000; time.musec := 1000* (ms MOD 1000);
ret := WSock32.select( 0, fdset, NIL , NIL , time );
avail := ret = 1;
IF ~avail THEN
len := 0; res := Timeout
END;
END;
END;
END;
IF avail THEN
len := WSock32.recvfrom( sock, data[ofs], size, 0, sadr, l );
IF len < 0 THEN err := WSock32.WSAGetLastError(); res := unknown;
ELSE res := Ok;
END;
END;
fport := WSock32.ntohs( sadr.sinPort );
SYSTEM.MOVE( SYSTEM.ADR( sadr.sinAddr ), SYSTEM.ADR( fip ), IPAdrLen );
IF fip.ipv4Adr # 0 THEN fip.usedProtocol := IP.IPv4 END;
IF trace THEN
IF (fip.usedProtocol = IP.IPv4) THEN
KernelLog.String( "UDP.Receive : " ); KernelLog.Int( fip.ipv4Adr, 1 ); KernelLog.String( " , " ); KernelLog.Int( fport, 1 );
KernelLog.String( "(" ); KernelLog.Int( res, 1 ); KernelLog.String( ")" ); KernelLog.Ln;
ELSE
KernelLog.String("UDP.Receive : Warning, received UDP packet from non-IPv4 source!"); KernelLog.Ln;
END;
END;
END Receive;
PROCEDURE Close*;
BEGIN
SockFinalizer( SELF );
IF trace THEN KernelLog.String( "UDP.Close" ); KernelLog.Ln; END;
END Close;
END Socket;
VAR
trace: BOOLEAN;
PROCEDURE SockFinalizer( S: ANY );
VAR ret: LONGINT; BEGIN
WITH S: Socket DO
IF S.sock # WSock32.InvalidSocket THEN ret:= WSock32.closesocket( S.sock ); S.sock := WSock32.InvalidSocket END
END
END SockFinalizer;
PROCEDURE ToggleTrace*;
BEGIN
trace := ~trace;
IF trace THEN KernelLog.String( "UDP: tracing ON" ); KernelLog.Ln;
ELSE KernelLog.String( "UDP: tracing OFF" ); KernelLog.Ln
END;
END ToggleTrace;
END UDP.