UdpSocket.hx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package asys.net;
  2. import haxe.Error;
  3. import haxe.NoData;
  4. import haxe.async.*;
  5. import haxe.io.Bytes;
  6. import asys.net.SocketOptions.UdpSocketOptions;
  7. private typedef Native =
  8. #if doc_gen
  9. Void;
  10. #elseif eval
  11. eval.uv.UdpSocket;
  12. #elseif hl
  13. hl.uv.UdpSocket;
  14. #elseif neko
  15. neko.uv.UdpSocket;
  16. #else
  17. #error "UDP socket not supported on this platform"
  18. #end
  19. class UdpSocket {
  20. public static function create(type:IpFamily, ?options:UdpSocketOptions, ?listener:Listener<UdpMessage>):UdpSocket {
  21. var res = new UdpSocket(type);
  22. // TODO: use other options, register listener
  23. if (options == null)
  24. options = {};
  25. if (options.recvBufferSize != null)
  26. res.recvBufferSize = options.recvBufferSize;
  27. if (options.sendBufferSize != null)
  28. res.sendBufferSize = options.sendBufferSize;
  29. return res;
  30. }
  31. public final type:IpFamily;
  32. /**
  33. Remote address and port that `this` socket is connected to. See `connect`.
  34. **/
  35. public var remoteAddress(default, null):Null<SocketAddress>;
  36. private function get_localAddress():Null<SocketAddress> {
  37. return try native.getSockName() catch (e:Dynamic) null;
  38. }
  39. public var localAddress(get, never):Null<SocketAddress>;
  40. private function get_recvBufferSize():Int {
  41. return native.getRecvBufferSize();
  42. }
  43. private function set_recvBufferSize(size:Int):Int {
  44. return native.setRecvBufferSize(size);
  45. }
  46. public var recvBufferSize(get, set):Int;
  47. private function get_sendBufferSize():Int {
  48. return native.getSendBufferSize();
  49. }
  50. private function set_sendBufferSize(size:Int):Int {
  51. return native.setSendBufferSize(size);
  52. }
  53. public var sendBufferSize(get, set):Int;
  54. // final closeSignal:Signal<NoData>;
  55. // final connectSignal:Signal<NoData>;
  56. // final listeningSignal:Signal<NoData>;
  57. public final errorSignal:Signal<Error> = new ArraySignal();
  58. /**
  59. Emitted when a message is received by `this` socket. See `UdpMessage`.
  60. **/
  61. public final messageSignal:Signal<UdpMessage> = new ArraySignal();
  62. /**
  63. Joins the given multicast group.
  64. **/
  65. public function addMembership(multicastAddress:String, ?multicastInterface:String):Void {
  66. if (multicastInterface == null)
  67. multicastInterface = "";
  68. native.addMembership(multicastAddress, multicastInterface);
  69. }
  70. /**
  71. Leaves the given multicast group.
  72. **/
  73. public function dropMembership(multicastAddress:String, ?multicastInterface:String):Void {
  74. if (multicastInterface == null)
  75. multicastInterface = "";
  76. native.dropMembership(multicastAddress, multicastInterface);
  77. }
  78. /**
  79. Binds `this` socket to a local address and port. Packets sent to the bound
  80. address will arrive via `messageSignal`. Outgoing packets will be sent from
  81. the given address and port. If any packet is sent without calling `bind`
  82. first, an address and port is chosen automatically by the system - it can
  83. be obtained with `localAddress`.
  84. **/
  85. public function bind(?address:Address, ?port:Int):Void {
  86. if (address == null)
  87. address = AddressTools.all(type);
  88. if (port == null)
  89. port = 0;
  90. native.bindTcp(address, port, false);
  91. native.startRead((err, msg) -> {
  92. if (err != null)
  93. return errorSignal.emit(err);
  94. messageSignal.emit(msg);
  95. });
  96. }
  97. /**
  98. Closes `this` socket and all underlying resources.
  99. **/
  100. public function close(?cb:Callback<NoData>):Void {
  101. native.stopRead();
  102. native.close(Callback.nonNull(cb));
  103. }
  104. /**
  105. Connects `this` socket to a remote address and port. Any `send` calls after
  106. `connect` is called must not specify `address` nor `port`, they will
  107. automatically use the ones specified in the `connect` call.
  108. **/
  109. public function connect(?address:Address, port:Int):Void {
  110. if (remoteAddress != null)
  111. throw "already connected";
  112. if (address == null)
  113. address = AddressTools.localhost(type);
  114. remoteAddress = Network(address, port);
  115. }
  116. /**
  117. Clears any remote address and port previously set with `connect`.
  118. **/
  119. public function disconnect():Void {
  120. if (remoteAddress == null)
  121. throw "not connected";
  122. remoteAddress = null;
  123. }
  124. /**
  125. Sends a message.
  126. @param msg Buffer from which to read the message data.
  127. @param offset Position in `msg` at which to start reading.
  128. @param length Length of message in bytes.
  129. @param address Address to send the message to. Must be `null` if `this`
  130. socket is connected.
  131. @param port Port to send the message to. Must be `null` if `this` socket is
  132. connected.
  133. **/
  134. public function send(msg:Bytes, offset:Int, length:Int, ?address:Address, ?port:Int, ?cb:Callback<NoData>):Void {
  135. if (address == null && port == null) {
  136. if (remoteAddress == null)
  137. throw "not connected";
  138. } else if (address != null && port != null) {
  139. if (remoteAddress != null)
  140. throw "already connected";
  141. } else
  142. throw "invalid arguments";
  143. if (address == null) {
  144. switch (remoteAddress) {
  145. case Network(a, p):
  146. address = a;
  147. port = p;
  148. case _:
  149. throw "!";
  150. }
  151. }
  152. native.send(msg, offset, length, address, port, cb);
  153. }
  154. /**
  155. Sets broadcast on or off.
  156. **/
  157. public function setBroadcast(flag:Bool):Void {
  158. native.setBroadcast(flag);
  159. }
  160. /**
  161. Sets the multicast interface on which to send and receive data.
  162. **/
  163. public function setMulticastInterface(multicastInterface:String):Void {
  164. native.setMulticastInterface(multicastInterface);
  165. }
  166. /**
  167. Set IP multicast loopback on or off. Makes multicast packets loop back to
  168. local sockets.
  169. **/
  170. public function setMulticastLoopback(flag:Bool):Void {
  171. native.setMulticastLoopback(flag);
  172. }
  173. /**
  174. Sets the multicast TTL (time-to-live).
  175. **/
  176. public function setMulticastTTL(ttl:Int):Void {
  177. native.setMulticastTTL(ttl);
  178. }
  179. /**
  180. Sets the TTL (time-to-live) for outgoing packets.
  181. @param ttl Number of hops.
  182. **/
  183. public function setTTL(ttl:Int):Void {
  184. native.setTTL(ttl);
  185. }
  186. public function ref():Void {
  187. native.asStream().ref();
  188. }
  189. public function unref():Void {
  190. native.asStream().unref();
  191. }
  192. var native:Native;
  193. function new(type) {
  194. native = new Native();
  195. this.type = type;
  196. }
  197. }
  198. /**
  199. A packet received emitted by `messageSignal` of a `UdpSocket`.
  200. **/
  201. typedef UdpMessage = {
  202. /**
  203. Message data.
  204. **/
  205. var data:Bytes;
  206. /**
  207. Remote IPv4 or IPv6 address from which the message originates.
  208. **/
  209. var remoteAddress:Address;
  210. /**
  211. Remote port from which the message originates.
  212. **/
  213. var remotePort:Int;
  214. };