EnetUdp.Mod 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. MODULE EnetUdp;
  2. (**
  3. AUTHOR: Alexey Morozov, HighDim GmbH, 2015
  4. PURPOSE: Ethernet networking stack, UDP protocol
  5. *)
  6. IMPORT
  7. SYSTEM, EnetBase, Interfaces := EnetInterfaces, EnetUtils, EnetTiming, Trace := EnetTrace;
  8. CONST
  9. MaxNumSockets* = 32; (** maximal number of UDP sockets *)
  10. TYPE
  11. Int32 = EnetBase.Int32;
  12. Int16 = EnetBase.Int16;
  13. Int = EnetBase.Int;
  14. (* UDP received datagram handler *)
  15. RecvDatagramHandler* = PROCEDURE{DELEGATE}(
  16. socket: Socket;
  17. CONST srcAddr: EnetBase.IpAddr;
  18. srcPort: Int;
  19. VAR data: ARRAY OF CHAR;
  20. dataOffs, dataLen: Int;
  21. packet: EnetBase.Packet
  22. );
  23. (**
  24. UDP socket (must not be shared among multiple threads)
  25. *)
  26. Socket* = POINTER TO RECORD
  27. intf*: EnetBase.Interface; (** the used interface; selection of the interface is done based on the IP address of the destination *)
  28. localPort*: Int; (** local (source) port *)
  29. sendToIpAddr*: EnetBase.IpAddr; (** IP address to send to *)
  30. sendToPort*: Int; (** port to send to *)
  31. resolvedSendToIpAddr: BOOLEAN;
  32. recvHandler*: RecvDatagramHandler; (** installed handler of received datagrams *)
  33. recvHandlerParam *: ANY; (** user-defined parameter for the receiver handler *)
  34. sendToMacAddr*: EnetBase.MacAddr;
  35. sendToIpAddrLast: EnetBase.IpAddr;
  36. sendToMacAddrLast: EnetBase.MacAddr;
  37. localPortNet: Int16; (* local port in the network byte order *)
  38. END;
  39. VAR
  40. sockets: ARRAY MaxNumSockets OF Socket;
  41. numSockets: Int;
  42. (**
  43. Create a UDP socket given a local port number
  44. localPort: local (source) port
  45. recvHandler: handler of received datagrams
  46. socket: reference to the created socket (NIL in case of an error)
  47. res: result code
  48. returns NIL in case of an error
  49. *)
  50. PROCEDURE NewSocket*(
  51. VAR socket: Socket;
  52. localPort: Int;
  53. VAR res: Int
  54. ): BOOLEAN;
  55. BEGIN
  56. IF numSockets >= MaxNumSockets THEN
  57. res := EnetBase.ErrOutOfResources;
  58. RETURN FALSE;
  59. END;
  60. IF (localPort < 0) OR (localPort > 65536) THEN
  61. res := EnetBase.ErrInvalidValue;
  62. RETURN FALSE;
  63. END;
  64. NEW(socket);
  65. socket.localPort := localPort;
  66. socket.sendToPort := 0;
  67. socket.recvHandler := NIL;
  68. IF EnetBase.LittleEndianSystem THEN
  69. socket.localPortNet := EnetUtils.SwitchEndianness16(Int16(localPort));
  70. ELSE
  71. socket.localPortNet := Int16(localPort);
  72. END;
  73. socket.sendToIpAddrLast := EnetBase.NilIpAddr;
  74. sockets[numSockets] := socket;
  75. INC(numSockets);
  76. res := 0;
  77. RETURN TRUE;
  78. END NewSocket;
  79. (**
  80. Setup socket's received datagram handler
  81. *)
  82. PROCEDURE SetRecvHandler*(socket: Socket; recvHandler: RecvDatagramHandler; VAR res: Int): BOOLEAN;
  83. BEGIN
  84. socket.recvHandler := recvHandler;
  85. res := 0;
  86. RETURN TRUE;
  87. END SetRecvHandler;
  88. (**
  89. Setup default destination of datagrams sent on a given socket using Send procedure
  90. *)
  91. PROCEDURE SetDestination*(socket: Socket; CONST sendToIpAddr: EnetBase.IpAddr; sendToPort: Int; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  92. BEGIN
  93. IF (sendToPort <= 0) OR (sendToPort >= 65535) THEN
  94. res := EnetBase.ErrInvalidValue;
  95. RETURN FALSE;
  96. END;
  97. IF ~Interfaces.ResolveIpAddr(sendToIpAddr,socket.sendToMacAddr,socket.intf,completionHandler,res) THEN RETURN FALSE; END;
  98. IF res = 0 THEN socket.resolvedSendToIpAddr := TRUE;
  99. ELSE socket.resolvedSendToIpAddr := FALSE;
  100. END;
  101. socket.sendToIpAddr := sendToIpAddr;
  102. socket.sendToPort := sendToPort;
  103. RETURN TRUE;
  104. END SetDestination;
  105. (**
  106. Send a datagram on a given socket
  107. *)
  108. PROCEDURE Send*(socket: Socket; CONST data: ARRAY OF CHAR; offset, length: Int; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  109. VAR
  110. packet: EnetBase.Packet;
  111. intf: EnetBase.Interface;
  112. dev: EnetBase.LinkDevice;
  113. payloadOffs: Int;
  114. BEGIN
  115. IF socket.sendToPort = 0 THEN res := EnetBase.ErrInvalidValue; RETURN FALSE; END;
  116. IF socket.intf = NIL THEN res := EnetBase.ErrNoIntfFound; RETURN FALSE; END;
  117. intf := socket.intf;
  118. IF ~socket.resolvedSendToIpAddr THEN
  119. IF ~Interfaces.ResolveIpAddr(socket.sendToIpAddr,socket.sendToMacAddr,socket.intf,NIL,res) THEN RETURN FALSE; END;
  120. END;
  121. dev := intf.dev;
  122. IF ~Interfaces.GetTxPacket(intf,packet) THEN res := EnetBase.ErrTxPacketPoolEmpty; RETURN FALSE; END;
  123. IF socket.sendToIpAddr.ver = 4 THEN
  124. EnetBase.SetUdpPacket(packet,
  125. intf.dev.macAddr,
  126. socket.sendToMacAddr,
  127. intf.ipv4Addr,
  128. socket.sendToIpAddr,
  129. socket.localPort,
  130. socket.sendToPort,
  131. length
  132. );
  133. ELSE
  134. EnetBase.SetUdpPacket(packet,
  135. intf.dev.macAddr,
  136. socket.sendToMacAddr,
  137. intf.ipv6Addr,
  138. socket.sendToIpAddr,
  139. socket.localPort,
  140. socket.sendToPort,
  141. length
  142. );
  143. END;
  144. IF ~dev.setPacketPayload(dev,packet,data,offset,flags,res) THEN
  145. RETURN FALSE;
  146. END;
  147. RETURN Interfaces.SendPacket(intf,packet,flags,completionHandler,res);
  148. END Send;
  149. (**
  150. Send at datagram on a given socket to a specified destination
  151. *)
  152. PROCEDURE SendTo*(socket: Socket; CONST sendToIpAddr: EnetBase.IpAddr; sendToPort: LONGINT; CONST data: ARRAY OF CHAR; offset, length: Int; flags: SET; completionHandler: EnetBase.TaskHandler; VAR res: Int): BOOLEAN;
  153. VAR
  154. packet: EnetBase.Packet;
  155. intf: EnetBase.Interface;
  156. dev: EnetBase.LinkDevice;
  157. payloadOffs: Int;
  158. BEGIN
  159. IF sendToPort = 0 THEN
  160. res := EnetBase.ErrInvalidValue;
  161. RETURN FALSE;
  162. END;
  163. IF ~(sendToIpAddr = socket.sendToIpAddrLast) THEN
  164. IF Interfaces.ResolveIpAddr(sendToIpAddr,socket.sendToMacAddrLast,socket.intf,NIL,res) THEN
  165. socket.sendToIpAddrLast := sendToIpAddr;
  166. ELSE RETURN FALSE;
  167. END;
  168. END;
  169. intf := socket.intf;
  170. dev := intf.dev;
  171. IF ~Interfaces.GetTxPacket(intf,packet) THEN
  172. res := EnetBase.ErrTxPacketPoolEmpty;
  173. RETURN FALSE;
  174. END;
  175. IF socket.sendToIpAddrLast.ver = 4 THEN
  176. EnetBase.SetUdpPacket(packet,
  177. intf.dev.macAddr,
  178. socket.sendToMacAddrLast,
  179. intf.ipv4Addr,
  180. socket.sendToIpAddrLast,
  181. socket.localPort,
  182. sendToPort,
  183. length
  184. );
  185. ELSE
  186. EnetBase.SetUdpPacket(packet,
  187. intf.dev.macAddr,
  188. socket.sendToMacAddrLast,
  189. intf.ipv6Addr,
  190. socket.sendToIpAddrLast,
  191. socket.localPort,
  192. sendToPort,
  193. length
  194. );
  195. END;
  196. IF ~dev.setPacketPayload(dev,packet,data,offset,flags,res) THEN
  197. RETURN FALSE;
  198. END;
  199. RETURN Interfaces.SendPacket(intf,packet,flags,completionHandler,res);
  200. END SendTo;
  201. (**
  202. Handling of an UDP packet
  203. *)
  204. PROCEDURE HandlePacket*(intf: EnetBase.Interface; packet: EnetBase.Packet; flags: SET);
  205. VAR
  206. i: Int;
  207. socket: Socket;
  208. srcPort: Int;
  209. dstPort: Int16;
  210. srcIpAddr: EnetBase.IpAddr;
  211. payloadOffs, payloadLen: Int;
  212. BEGIN
  213. dstPort := packet.udpHdr.dstPort;
  214. (*
  215. search a socket bound to the packet's destination port
  216. *)
  217. i := 0;
  218. WHILE (i < numSockets) & (dstPort # sockets[i].localPortNet) DO (*! optimize socket search (e.g. search only among the sockets with installed recv handlers etc.) *)
  219. INC(i);
  220. END;
  221. IF i < numSockets THEN
  222. IF EnetBase.EnableTrace THEN Trace.StringLn("EnetUdp: Received UDP datagram for open port " & dstPort); END;
  223. socket := sockets[i];
  224. IF socket.recvHandler # NIL THEN
  225. payloadOffs := SIZEOF(EnetBase.EthFrameHdr)+SIZEOF(EnetBase.UdpHdr);
  226. IF ~(EnetBase.FlagIpv6 IN flags) THEN (* IPv4 *)
  227. srcIpAddr.addr[0] := packet.ipv4Hdr.srcIpAddr;
  228. srcIpAddr.ver := 4;
  229. INC(payloadOffs,SIZEOF(EnetBase.Ipv4Hdr));
  230. ELSE (* IPv6 *)
  231. srcIpAddr.addr[0] := packet.ipv6Hdr.srcIpAddr[0];
  232. srcIpAddr.addr[1] := packet.ipv6Hdr.srcIpAddr[1];
  233. srcIpAddr.addr[2] := packet.ipv6Hdr.srcIpAddr[2];
  234. srcIpAddr.addr[3] := packet.ipv6Hdr.srcIpAddr[3];
  235. srcIpAddr.ver := 6;
  236. INC(payloadOffs,SIZEOF(EnetBase.Ipv6Hdr));
  237. END;
  238. srcPort := Int(EnetUtils.SwitchEndianness16(packet.udpHdr.srcPort)) MOD 10000H;
  239. packet.payloadOffs := payloadOffs;
  240. payloadLen := EnetUtils.SwitchEndianness16(packet.udpHdr.length) - SIZEOF(EnetBase.UdpHdr);
  241. socket.recvHandler(socket,srcIpAddr,srcPort,packet.data^,packet.dataOffs+payloadOffs,payloadLen,packet);
  242. END;
  243. ELSE
  244. IF EnetBase.EnableTrace THEN Trace.StringLn("EnetUdp: Received UDP datagram on closed port " & dstPort); END;
  245. END;
  246. END HandlePacket;
  247. PROCEDURE Install*(intf: EnetBase.Interface);
  248. BEGIN
  249. EnetBase.SetIpPacketHandler(intf,EnetBase.ProtoUdp,HandlePacket);
  250. END Install;
  251. END EnetUdp.