2
0

Socket.hx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package sys.net;
  23. import haxe.io.Error;
  24. import cpp.NativeSocket;
  25. import cpp.NativeString;
  26. import cpp.Pointer;
  27. private class SocketInput extends haxe.io.Input {
  28. var __s:Dynamic;
  29. public function new(s:Dynamic) {
  30. __s = s;
  31. }
  32. public override function readByte() {
  33. return try {
  34. NativeSocket.socket_recv_char(__s);
  35. } catch (e:Dynamic) {
  36. if (e == "Blocking")
  37. throw Blocked;
  38. else if (__s == null)
  39. throw Custom(e);
  40. else
  41. throw new haxe.io.Eof();
  42. }
  43. }
  44. public override function readBytes(buf:haxe.io.Bytes, pos:Int, len:Int):Int {
  45. var r;
  46. if (__s == null)
  47. throw "Invalid handle";
  48. try {
  49. r = NativeSocket.socket_recv(__s, buf.getData(), pos, len);
  50. } catch (e:Dynamic) {
  51. if (e == "Blocking")
  52. throw Blocked;
  53. else
  54. throw Custom(e);
  55. }
  56. if (r == 0)
  57. throw new haxe.io.Eof();
  58. return r;
  59. }
  60. public override function close() {
  61. super.close();
  62. if (__s != null)
  63. NativeSocket.socket_close(__s);
  64. }
  65. }
  66. private class SocketOutput extends haxe.io.Output {
  67. var __s:Dynamic;
  68. public function new(s:Dynamic) {
  69. __s = s;
  70. }
  71. public override function writeByte(c:Int) {
  72. if (__s == null)
  73. throw "Invalid handle";
  74. try {
  75. NativeSocket.socket_send_char(__s, c);
  76. } catch (e:Dynamic) {
  77. if (e == "Blocking")
  78. throw Blocked;
  79. else
  80. throw Custom(e);
  81. }
  82. }
  83. public override function writeBytes(buf:haxe.io.Bytes, pos:Int, len:Int):Int {
  84. return try {
  85. NativeSocket.socket_send(__s, buf.getData(), pos, len);
  86. } catch (e:Dynamic) {
  87. if (e == "Blocking")
  88. throw Blocked;
  89. else if (e == "EOF")
  90. throw new haxe.io.Eof();
  91. else
  92. throw Custom(e);
  93. }
  94. }
  95. public override function close() {
  96. super.close();
  97. if (__s != null)
  98. NativeSocket.socket_close(__s);
  99. }
  100. }
  101. @:coreApi
  102. class Socket {
  103. private var __s:Dynamic;
  104. // We need to keep these values so that we can restore
  105. // them if we re-create the socket for ipv6 as in
  106. // connect() and bind() below.
  107. private var __timeout:Float = 0.0;
  108. private var __blocking:Bool = true;
  109. private var __fastSend:Bool = false;
  110. public var input(default, null):haxe.io.Input;
  111. public var output(default, null):haxe.io.Output;
  112. public var custom:Dynamic;
  113. public function new():Void {
  114. init();
  115. }
  116. private function init():Void {
  117. if (__s == null)
  118. __s = NativeSocket.socket_new(false);
  119. // Restore these values if they changed. This can happen
  120. // in connect() and bind() if using an ipv6 address.
  121. setTimeout(__timeout);
  122. setBlocking(__blocking);
  123. setFastSend(__fastSend);
  124. input = new SocketInput(__s);
  125. output = new SocketOutput(__s);
  126. }
  127. public function close():Void {
  128. NativeSocket.socket_close(__s);
  129. untyped {
  130. var input:SocketInput = cast input;
  131. var output:SocketOutput = cast output;
  132. input.__s = null;
  133. output.__s = null;
  134. }
  135. input.close();
  136. output.close();
  137. }
  138. public function read():String {
  139. var bytes:haxe.io.BytesData = NativeSocket.socket_read(__s);
  140. if (bytes == null)
  141. return "";
  142. var arr:Array<cpp.Char> = cast bytes;
  143. return NativeString.fromPointer(Pointer.ofArray(arr));
  144. }
  145. public function write(content:String):Void {
  146. NativeSocket.socket_write(__s, haxe.io.Bytes.ofString(content).getData());
  147. }
  148. public function connect(host:Host, port:Int):Void {
  149. try {
  150. if (host.ip == 0 && host.host != "0.0.0.0") {
  151. // hack, hack, hack
  152. var ipv6:haxe.io.BytesData = Reflect.field(host, "ipv6");
  153. if (ipv6 != null) {
  154. close();
  155. __s = NativeSocket.socket_new_ip(false, true);
  156. init();
  157. NativeSocket.socket_connect_ipv6(__s, ipv6, port);
  158. } else
  159. throw "Unresolved host";
  160. } else
  161. NativeSocket.socket_connect(__s, host.ip, port);
  162. } catch (s:String) {
  163. if (s == "Invalid socket handle")
  164. throw "Failed to connect on " + host.toString() + ":" + port;
  165. else if (s == "Blocking") {
  166. // Do nothing, this is not a real error, it simply indicates
  167. // that a non-blocking connect is in progress
  168. } else
  169. cpp.Lib.rethrow(s);
  170. }
  171. }
  172. public function listen(connections:Int):Void {
  173. NativeSocket.socket_listen(__s, connections);
  174. }
  175. public function shutdown(read:Bool, write:Bool):Void {
  176. NativeSocket.socket_shutdown(__s, read, write);
  177. }
  178. public function bind(host:Host, port:Int):Void {
  179. if (host.ip == 0 && host.host != "0.0.0.0") {
  180. var ipv6:haxe.io.BytesData = Reflect.field(host, "ipv6");
  181. if (ipv6 != null) {
  182. close();
  183. __s = NativeSocket.socket_new_ip(false, true);
  184. init();
  185. NativeSocket.socket_bind_ipv6(__s, ipv6, port);
  186. } else
  187. throw "Unresolved host";
  188. } else
  189. NativeSocket.socket_bind(__s, host.ip, port);
  190. }
  191. public function accept():Socket {
  192. var c = NativeSocket.socket_accept(__s);
  193. var s = Type.createEmptyInstance(Socket);
  194. s.__s = c;
  195. s.input = new SocketInput(c);
  196. s.output = new SocketOutput(c);
  197. return s;
  198. }
  199. public function peer():{host:Host, port:Int} {
  200. var a:Dynamic = NativeSocket.socket_peer(__s);
  201. if (a == null) {
  202. return null;
  203. }
  204. var h = new Host("127.0.0.1");
  205. untyped h.ip = a[0];
  206. return {host: h, port: a[1]};
  207. }
  208. public function host():{host:Host, port:Int} {
  209. var a:Dynamic = NativeSocket.socket_host(__s);
  210. if (a == null) {
  211. return null;
  212. }
  213. var h = new Host("127.0.0.1");
  214. untyped h.ip = a[0];
  215. return {host: h, port: a[1]};
  216. }
  217. public function setTimeout(timeout:Float):Void {
  218. __timeout = timeout;
  219. NativeSocket.socket_set_timeout(__s, timeout);
  220. }
  221. public function waitForRead():Void {
  222. select([this], null, null, null);
  223. }
  224. public function setBlocking(b:Bool):Void {
  225. __blocking = b;
  226. NativeSocket.socket_set_blocking(__s, b);
  227. }
  228. public function setFastSend(b:Bool):Void {
  229. __fastSend = b;
  230. NativeSocket.socket_set_fast_send(__s, b);
  231. }
  232. public static function select(read:Array<Socket>, write:Array<Socket>, others:Array<Socket>,
  233. ?timeout:Float):{read:Array<Socket>, write:Array<Socket>, others:Array<Socket>} {
  234. var neko_array = NativeSocket.socket_select(read, write, others, timeout);
  235. if (neko_array == null)
  236. throw "Select error";
  237. return @:fixed {
  238. read:neko_array[0], write:neko_array[1], others:neko_array[2]
  239. };
  240. }
  241. }