1 module dast.async.tcpserver; 2 3 import dast.async.core, 4 dast.async.eventloop, 5 dast.async.selector, 6 dast.async.tcpclient, 7 tame.meta; 8 9 version (Windows) import dast.async.iocp; 10 11 @safe: 12 13 alias AcceptHandler = void delegate(Socket socket); 14 15 /// TCP Server 16 class TCPServer : SocketChannel { 17 mixin Forward!"_socket"; 18 19 AcceptHandler onAccept; 20 SimpleHandler onClosed; 21 22 this(EventLoop loop, AddrFamily family = AddrFamily.IPv4) { 23 super(loop, WT.Accept); 24 flags |= WF.Read; 25 socket = tcpSocket(family); 26 } 27 28 override void close() { 29 super.close(); 30 if (onClosed) 31 onClosed(); 32 } 33 34 void start() { 35 _loop.register(this); 36 _isReg = true; 37 version (Windows) 38 accept(); 39 } 40 41 override void onRead() { 42 debug (Log) 43 trace("start listening"); 44 if (!tryAccept((Socket socket) { 45 debug (Log) 46 info("new connection from ", socket.remoteAddress, ", fd=", socket.handle); 47 48 if (onAccept) 49 onAccept(socket); 50 else 51 new TCPClient(_loop, socket).start(); 52 })) { 53 close(); 54 } 55 } 56 57 private: 58 bool tryAccept(scope AcceptHandler handler) { 59 version (Posix) { 60 import core.sys.posix.sys.socket : accept; 61 62 const clientFd = accept(handle, null, null); 63 if (clientFd < 0) 64 return false; 65 66 debug (Log) 67 trace("server fd=", handle, ", client fd=", clientFd); 68 69 handler(Socket(clientFd, _socket.addressFamily)); 70 return true; 71 } 72 73 version (Windows) { 74 import core.sys.windows.mswsock; 75 76 debug (Log) 77 trace("server fd=", handle, ", client fd=", _clientSock.handle); 78 socket_t[1] fd = [handle]; 79 _clientSock.setOption(SocketOptionLevel.SOCKET, 80 cast(SocketOption)SO_UPDATE_ACCEPT_CONTENT, fd); 81 handler(_clientSock); 82 83 debug (Log) 84 trace("accept next connection"); 85 return _isReg && accept(); 86 } 87 } 88 89 version (Windows) : bool accept() @trusted { 90 _clientSock = tcpSocket(_socket.addressFamily); 91 //_clientSock = new Socket(WSASocket(_socket.addressFamily, SocketType.STREAM, 92 //ProtocolType.TCP, null, 0, WSA_FLAG_OVERLAPPED), _socket.addressFamily); 93 uint dwBytesReceived = void; 94 95 debug (Log) 96 trace("client socket=", _clientSock.handle, ", server socket=", handle); 97 return !checkErr(AcceptEx(handle, _clientSock.handle, _buf.ptr, 0, size, size, 98 &dwBytesReceived, &_ctx.overlapped), "accept"); 99 } 100 101 mixin checkErr; 102 enum size = sockaddr_in.sizeof + 16; 103 Socket _clientSock; 104 IocpContext _ctx = {operation: IocpOperation.accept}; 105 ubyte[size * 4] _buf; 106 } 107 108 @property: 109 bool reusePort(Socket socket) { 110 int result = void; 111 socket.getOption(SocketOptionLevel.SOCKET, SocketOption.reuseAddr, result); 112 return result != 0; 113 } 114 115 bool reusePort(Socket socket, bool enabled) { 116 socket.setOption(SocketOptionLevel.SOCKET, SocketOption.reuseAddr, enabled); 117 118 version (Posix) { 119 socket.setOption(SocketOptionLevel.SOCKET, SocketOption.reusePort, enabled); 120 } else version (Windows) { 121 if (!enabled) { 122 socket.setOption(SocketOptionLevel.SOCKET, SocketOption.exclusiveAddr, true); 123 } 124 } 125 126 return enabled; 127 }