1 module yu.asyncsocket.tcpclient;
2 
3 import std.socket;
4 import std.exception;
5 
6 import yu.eventloop;
7 import yu.asyncsocket.tcpsocket;
8 import yu.asyncsocket.exception;
9 import yu.exception;
10 
11 alias ConnectCallBack = void delegate(bool connect) nothrow;
12 
13 @trusted final class TCPClient : TCPSocket {
14     this(EventLoop loop, bool isIpV6 = false) {
15         super(loop, isIpV6);
16     }
17 
18     this(EventLoop loop, AddressFamily family) {
19         super(loop, family);
20     }
21 
22     override @property bool isAlive() @trusted nothrow {
23         return super.isAlive() && _isConnect;
24     }
25 
26     pragma(inline) bool connect(Address addr) {
27         if (isAlive())
28             throw new ConnectedException("This Socket is Connected! Please close before connect!");
29         static if (IOMode == IO_MODE.iocp) {
30             Address bindddr;
31             if (addr.addressFamily() == AddressFamily.INET) {
32                 bindddr = new InternetAddress(InternetAddress.PORT_ANY);
33             } else if (addr.addressFamily() == AddressFamily.INET6) {
34                 bindddr = new Internet6Address(Internet6Address.PORT_ANY);
35             } else
36                 throw new ConnectedException("This Address is not a network address!");
37             _socket.bind(bindddr);
38             _loop.addEvent(&_event);
39             _iocpread.event = &_event;
40             _iocpread.operationType = IOCP_OP_TYPE.connect;
41             int b = ConnectEx(cast(SOCKET) _socket.handle,
42                 cast(SOCKADDR*) addr.name(), addr.nameLen(), null, 0, null, &_iocpread.ol);
43             if (b == 0) {
44                 DWORD dwLastError = GetLastError();
45                 if (dwLastError != ERROR_IO_PENDING) {
46                     error("ConnectEx failed with error: ", dwLastError);
47                     return false;
48                 }
49             }
50             return true;
51         } else {
52             if (!start())
53                 return false;
54             _isFrist = true;
55             _socket.connect(addr);
56             return true;
57         }
58     }
59 
60     pragma(inline) void setConnectCallBack(ConnectCallBack cback) {
61         _connectBack = cback;
62     }
63 
64 protected:
65     override void onClose() nothrow {
66         if (_isFrist && !_isConnect && _connectBack) {
67             _isFrist = false;
68             _connectBack(false);
69             return;
70         }
71         _isConnect = false;
72         super.onClose();
73     }
74 
75     override void onWrite() nothrow {
76         if (_isFrist && !_isConnect && _connectBack) {
77             _isFrist = false;
78             _isConnect = true;
79             _connectBack(true);
80         }
81 
82         super.onWrite();
83     }
84 
85 private:
86     bool _isConnect = false;
87     bool _isFrist = true;
88     ConnectCallBack _connectBack;
89 }