123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
- MODULE UDP; (** AUTHOR "pjm, mvt, G.F."; PURPOSE "UDP protocol"; *)
- IMPORT IP, Sockets, Unix;
- CONST
- (** Error codes *)
- Ok* = 0; PortInUse* = 3501; Timeout* = 3502; BufferOverflow* = 3503; NoInterface* = 3504;
- Closed* = 3505; Error* = 9999;
- NilPort* = 0; anyport = 0;
- UDPHdrLen = 8;
- MaxUDPDataLen = 10000H - UDPHdrLen;
- VAR
- anyIP: IP.Adr;
- TYPE
- (** Socket. Stores the state of a UDP communication endpoint. *)
- Socket* = OBJECT
- VAR
- socket: LONGINT;
- lport: LONGINT; (* local port *)
- open: BOOLEAN;
- (** Constructor *)
- PROCEDURE & Open*( lport: LONGINT; VAR res: WORD );
- VAR laddr: Sockets.SocketAdr;
- BEGIN
- ASSERT( (lport >= 0) & (lport < 10000H) );
- SELF.lport := lport; res := Error;
- socket := Sockets.Socket( Unix.AFINET, Unix.SockDGram, Unix.IpProtoUDP );
- IF socket # 0 THEN
- IF lport # anyport THEN
- (* server *)
- laddr := Sockets.NewSocketAdr( anyIP, lport );
- IF Sockets.Bind( socket, laddr ) THEN
- res := Ok; open := TRUE
- ELSE
- Sockets.Close( socket )
- END
- ELSE
- (* client *)
- res := Ok; open := TRUE
- END
- END
- END Open;
- (** Send a UDP datagram to the foreign address specified by "fip" and "fport".
- The data is in "data[ofs..ofs+len-1]". In case of concurrent sends the datagrams are serialized.
- *)
- PROCEDURE Send*( fip: IP.Adr;
- fport: LONGINT;
- CONST data: ARRAY OF CHAR; ofs, len: LONGINT;
- VAR res: WORD );
- VAR addr: Sockets.SocketAdr;
- BEGIN {EXCLUSIVE}
- ASSERT( (fport >= 0) & (fport < 10000H) );
- ASSERT( (len >= 0) & (len <= MaxUDPDataLen) );
- addr := Sockets.NewSocketAdr( fip, fport );
- IF Sockets.SendTo( socket, addr, data, ofs, len ) THEN res := Ok ELSE res := Error END
- END Send;
- (** Send a broadcast UDP datagram via interface "int" to port "lport". Normally only used by DHCP.
- The data is in "data[ofs..ofs+len-1]". In case of concurrent sends the datagrams are serialized.
- *)
- PROCEDURE SendBroadcast*( int: IP.Interface; fport: LONGINT;
- CONST data: ARRAY OF CHAR; ofs, len: LONGINT );
- BEGIN (*{EXCLUSIVE}*)
- ASSERT( (fport >= 0) & (fport < 10000H) ); ASSERT( (len >= 0) & (len <= MaxUDPDataLen) );
- HALT( 99 ) (* not implemented yet *)
- END SendBroadcast;
- (** Receive a UDP datagram. If none is available, wait up to the specified timeout for one to arrive.
- "data[ofs..ofs+size-1]" is the data buffer to hold the returned datagram.
- "ms" is a wait timeout value in milliseconds, 0 means "don't wait", -1 means "infinite wait".
- On return, "fip" and "fport" hold the foreign address and port.
- "len" returns the actual datagram size and "data[ofs..ofs+len-1]" returns the data.
- "res" returns "Timeout" in case of a timeout and "BufferOverflow" if the received datagram was
- too big.
- *)
- PROCEDURE Receive*( VAR data: ARRAY OF CHAR; ofs, size, ms: LONGINT;
- VAR fip: IP.Adr; VAR fport, len: LONGINT; VAR res: WORD );
- VAR
- addr: Sockets.SocketAdr; i: LONGINT;
- BEGIN {EXCLUSIVE}
- IF ~open THEN res := Closed; RETURN END;
- IF (ms >= 0) & ~Sockets.AwaitPacket( socket, ms ) THEN
- res := Timeout; RETURN
- END;
- IF Sockets.RecvFrom( socket, addr, data, ofs, len ) THEN
- fport := Sockets.GetPortNumber( addr );
- IF addr IS Sockets.SocketAdrV4 THEN
- fip.usedProtocol := IP.IPv4;
- fip.ipv4Adr := addr(Sockets.SocketAdrV4).v4Adr;
- ELSE
- fip.usedProtocol := IP.IPv6;
- FOR i := 0 TO 15 DO
- fip.ipv6Adr[i] := addr(Sockets.SocketAdrV6).v6Adr[i]
- END
- END;
- res := Ok;
- ELSE
- res := Error
- END
- END Receive;
- (** Close the Socket, freeing its address for re-use. *)
- PROCEDURE Close*;
- BEGIN
- Sockets.Close( socket ); open := FALSE
- END Close;
- END Socket;
- BEGIN
- anyIP := IP.NilAdr;
- END UDP.
|