Server.hx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package asys.net;
  2. import haxe.Error;
  3. import haxe.NoData;
  4. import haxe.async.*;
  5. typedef ServerOptions = {
  6. ?allowHalfOpen:Bool,
  7. ?pauseOnConnect:Bool
  8. };
  9. typedef ServerListenTcpOptions = {
  10. ?port:Int,
  11. ?host:String,
  12. ?address:Address,
  13. ?backlog:Int,
  14. ?exclusive:Bool,
  15. ?ipv6only:Bool
  16. };
  17. typedef ServerListenIpcOptions = {
  18. path:String,
  19. ?backlog:Int,
  20. ?exclusive:Bool,
  21. ?readableAll:Bool,
  22. ?writableAll:Bool
  23. };
  24. private typedef NativeStream =
  25. #if doc_gen
  26. Void;
  27. #elseif eval
  28. eval.uv.Stream;
  29. #elseif hl
  30. hl.uv.Stream;
  31. #elseif neko
  32. neko.uv.Stream;
  33. #else
  34. #error "socket not supported on this platform"
  35. #end
  36. private typedef NativeSocket =
  37. #if doc_gen
  38. Void;
  39. #elseif eval
  40. eval.uv.Socket;
  41. #elseif hl
  42. hl.uv.Socket;
  43. #elseif neko
  44. neko.uv.Socket;
  45. #else
  46. #error "socket not supported on this platform"
  47. #end
  48. private typedef NativePipe =
  49. #if doc_gen
  50. Void;
  51. #elseif eval
  52. eval.uv.Pipe;
  53. #elseif hl
  54. hl.uv.Pipe;
  55. #elseif neko
  56. neko.uv.Pipe;
  57. #else
  58. #error "socket not supported on this platform"
  59. #end
  60. class Server {
  61. public final closeSignal:Signal<NoData> = new ArraySignal<NoData>();
  62. public final connectionSignal:Signal<Socket> = new ArraySignal<Socket>();
  63. public final errorSignal:Signal<Error> = new ArraySignal<Error>();
  64. public final listeningSignal:Signal<NoData> = new ArraySignal<NoData>();
  65. public var listening(default, null):Bool;
  66. public var maxConnections:Int; // TODO
  67. function get_localAddress():Null<SocketAddress> {
  68. if (!listening)
  69. return null;
  70. return nativeSocket.getSockName();
  71. }
  72. public var localAddress(get, never):Null<SocketAddress>;
  73. public function new(?options:ServerOptions) {}
  74. // function address():SocketAddress;
  75. public function close(?callback:Callback<NoData>):Void {
  76. native.close(Callback.nonNull(callback));
  77. }
  78. // function getConnections(callback:Callback<Int>):Void;
  79. // function listenSocket(socket:Socket, ?backlog:Int, ?listener:Listener<NoData>):Void;
  80. // function listenServer(server:Server, ?backlog:Int, ?listener:Listener<NoData>):Void;
  81. // function listenFile(file:sys.io.File, ?backlog:Int, ?listener:Listener<NoData>):Void;
  82. public function listenIpc(options:ServerListenIpcOptions, ?listener:Listener<Socket>):Void {
  83. if (listening || listenDefer != null)
  84. throw "already listening";
  85. if (listener != null)
  86. connectionSignal.on(listener);
  87. nativePipe = new NativePipe(false);
  88. native = nativePipe.asStream();
  89. listening = true;
  90. try {
  91. // TODO: probably prepend "\\?\pipe\" to the path on Windows
  92. nativePipe.bindIpc(options.path);
  93. native.listen(options.backlog == null ? 511 : options.backlog, (err) -> {
  94. if (err != null)
  95. return errorSignal.emit(err);
  96. try {
  97. var client = @:privateAccess new Socket();
  98. @:privateAccess client.nativePipe = nativePipe.accept();
  99. @:privateAccess client.native = @:privateAccess client.nativePipe.asStream();
  100. @:privateAccess client.connected = true;
  101. @:privateAccess client.serverSpawn = true;
  102. connectionSignal.emit(client);
  103. } catch (e:haxe.Error) {
  104. errorSignal.emit(e);
  105. }
  106. });
  107. listeningSignal.emit(new NoData());
  108. } catch (e:haxe.Error) {
  109. errorSignal.emit(e);
  110. }
  111. }
  112. public function listenTcp(options:ServerListenTcpOptions, ?listener:Listener<Socket>):Void {
  113. if (listening || listenDefer != null)
  114. throw "already listening";
  115. if (listener != null)
  116. connectionSignal.on(listener);
  117. if (options.host != null && options.address != null)
  118. throw "cannot specify both host and address";
  119. nativeSocket = new NativeSocket();
  120. native = nativeSocket.asStream();
  121. // take a copy since we reuse the object asynchronously
  122. var options = {
  123. port: options.port,
  124. host: options.host,
  125. address: options.address,
  126. backlog: options.backlog,
  127. exclusive: options.exclusive,
  128. ipv6only: options.ipv6only
  129. };
  130. function listen(address:Address):Void {
  131. listenDefer = null;
  132. listening = true;
  133. if (options.ipv6only == null)
  134. options.ipv6only = false;
  135. try {
  136. nativeSocket.bindTcp(address, options.port == null ? 0 : options.port, options.ipv6only);
  137. native.listen(options.backlog == null ? 511 : options.backlog, (err) -> {
  138. if (err != null)
  139. return errorSignal.emit(err);
  140. try {
  141. var client = @:privateAccess new Socket();
  142. @:privateAccess client.nativeSocket = nativeSocket.accept();
  143. @:privateAccess client.native = @:privateAccess client.nativeSocket.asStream();
  144. @:privateAccess client.connected = true;
  145. @:privateAccess client.serverSpawn = true;
  146. connectionSignal.emit(client);
  147. } catch (e:haxe.Error) {
  148. errorSignal.emit(e);
  149. }
  150. });
  151. listeningSignal.emit(new NoData());
  152. } catch (e:haxe.Error) {
  153. errorSignal.emit(e);
  154. }
  155. }
  156. if (options.address != null) {
  157. listenDefer = Defer.nextTick(() -> listen(options.address));
  158. return;
  159. }
  160. if (options.host == null)
  161. options.host = "";
  162. Dns.lookup(options.host, null, (err, entries) -> {
  163. if (err != null)
  164. return errorSignal.emit(err);
  165. if (entries.length == 0)
  166. throw "!";
  167. listen(entries[0]);
  168. });
  169. }
  170. public function ref():Void {
  171. native.ref();
  172. }
  173. public function unref():Void {
  174. native.unref();
  175. }
  176. var native:NativeStream;
  177. var nativeSocket:NativeSocket;
  178. var nativePipe:NativePipe;
  179. var listenDefer:haxe.Timer;
  180. }