1 module hunt.io.channel.iocp.AbstractListener;
2 
3 // dfmt off
4 version (HAVE_IOCP) : 
5 // dfmt on
6 
7 import hunt.event.selector.Selector;
8 import hunt.io.channel.AbstractSocketChannel;
9 import hunt.io.channel.Common;
10 import hunt.io.channel.iocp.Common;
11 import hunt.logging.ConsoleLogger;
12 import hunt.Functions;
13 
14 import core.sys.windows.windows;
15 import core.sys.windows.winsock2;
16 import core.sys.windows.mswsock;
17 
18 import std.socket;
19 
20 
21 
22 /**
23 TCP Server
24 */
25 abstract class AbstractListener : AbstractSocketChannel {
26     this(Selector loop, AddressFamily family = AddressFamily.INET, size_t bufferSize = 4 * 1024) {
27         super(loop, ChannelType.Accept);
28         setFlag(ChannelFlag.Read, true);
29         _buffer = new ubyte[bufferSize];
30         this.socket = new TcpSocket(family);
31 
32         loadWinsockExtension(this.handle);
33     }
34 
35     mixin CheckIocpError;
36 
37     protected void doAccept() {
38         _iocp.channel = this;
39         _iocp.operation = IocpOperation.accept;
40         _clientSocket = new Socket(this.localAddress.addressFamily,
41                 SocketType.STREAM, ProtocolType.TCP);
42         DWORD dwBytesReceived = 0;
43 
44         version (HUNT_DEBUG) {
45             tracef("client socket: acceptor=%s  inner socket=%s", this.handle,
46                     _clientSocket.handle());
47             // info("AcceptEx@", AcceptEx);
48         }
49         uint sockaddrSize = cast(uint) sockaddr_storage.sizeof;
50         // https://docs.microsoft.com/en-us/windows/desktop/api/mswsock/nf-mswsock-acceptex
51         BOOL ret = AcceptEx(this.handle, cast(SOCKET) _clientSocket.handle, _buffer.ptr,
52                 0, sockaddrSize + 16, sockaddrSize + 16, &dwBytesReceived, &_iocp.overlapped);
53         version (HUNT_DEBUG)
54             trace("AcceptEx return: ", ret);
55         checkErro(ret, FALSE);
56     }
57 
58     protected bool onAccept(scope AcceptHandler handler) {
59         version (HUNT_DEBUG)
60             trace("a new connection coming...");
61         this.clearError();
62         SOCKET slisten = cast(SOCKET) this.handle;
63         SOCKET slink = cast(SOCKET) this._clientSocket.handle;
64         // void[] value = (&slisten)[0..1];
65         // setsockopt(slink, SocketOptionLevel.SOCKET, 0x700B, value.ptr,
66         //                    cast(uint) value.length);
67         version (HUNT_DEBUG)
68             tracef("slisten=%s, slink=%s", slisten, slink);
69         setsockopt(slink, SocketOptionLevel.SOCKET, 0x700B, cast(void*)&slisten, slisten.sizeof);
70         if (handler !is null)
71             handler(this._clientSocket);
72 
73         version (HUNT_DEBUG)
74             trace("accepting next connection...");
75         if (this.isRegistered)
76             this.doAccept();
77         return true;
78     }
79 
80     override void onClose() {
81         
82         // version (HUNT_DEBUG)
83         //     tracef("_isWritting=%s", _isWritting);
84         // _isWritting = false;
85         // assert(false, "");
86         // TODO: created by Administrator @ 2018-3-27 15:51:52
87     }
88 
89     private IocpContext _iocp;
90     private WSABUF _dataWriteBuffer;
91     private ubyte[] _buffer;
92     private Socket _clientSocket;
93 }