1 module async.net.tcpstream;
2 
3 import std.socket;
4 import std.datetime;
5 
6 abstract class TcpStream
7 {
8     this(Socket socket)
9     {
10         _socket          = socket;
11         _socket.blocking = false;
12     }
13 
14     @property bool reusePort()
15     {
16         return _reusePort;
17     }
18 
19     @property bool reusePort(bool enabled)
20     {
21         _reusePort = enabled;
22 
23         _socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, _reusePort);
24 
25         version (Posix)
26         {
27             import core.sys.posix.sys.socket;
28             _socket.setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_REUSEPORT, _reusePort);
29         }
30 
31         version (Windows)
32         {
33             if (!_reusePort)
34             {
35                 import core.sys.windows.winsock2;
36                 _socket.setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_EXCLUSIVEADDRUSE, true);
37             }
38         }
39 
40         return _reusePort;
41     }
42 
43     @property bool blocking()
44     {
45         return _blocking;
46     }
47 
48     @property bool blocking(bool enabled)
49     {
50         _blocking        = enabled;
51         _socket.blocking = _blocking;
52 
53         return _blocking;
54     }
55 
56     @property int fd()
57     {
58         return _socket.handle();
59     }
60 
61     @property Address remoteAddress()
62     {
63         return _socket.remoteAddress();
64     }
65 
66     @property Address localAddress()
67     {
68         return _socket.localAddress();
69     }
70 
71     @property bool isAlive()
72     {
73         return _socket.isAlive();
74     }
75 
76     int getOption(SocketOptionLevel level, SocketOption option, void[] result) @trusted
77     {
78         return _socket.getOption(level, option, result);
79     }
80 
81     int getOption(SocketOptionLevel level, SocketOption option, out int result) @trusted
82     {
83         return _socket.getOption(level, option, result);
84     }
85 
86     int getOption(SocketOptionLevel level, SocketOption option, out Linger result) @trusted
87     {
88         return _socket.getOption(level, option, result);
89     }
90 
91     void getOption(SocketOptionLevel level, SocketOption option, out Duration result) @trusted
92     {
93         return _socket.getOption(level, option, result);
94     }
95 
96     void setOption(SocketOptionLevel level, SocketOption option, void[] value) @trusted
97     {
98         _socket.setOption(level, option, value);
99     }
100 
101     void setOption(SocketOptionLevel level, SocketOption option, int value) @trusted
102     {
103         _socket.setOption(level, option, value);
104     }
105 
106     void setOption(SocketOptionLevel level, SocketOption option, Linger value) @trusted
107     {
108         _socket.setOption(level, option, value);
109     }
110 
111     void setOption(SocketOptionLevel level, SocketOption option, Duration value) @trusted
112     {
113         _socket.setOption(level, option, value);
114     }
115 
116     void setKeepAlive(int time, int interval) @trusted
117     {
118         version (Windows)
119         {
120             tcp_keepalive options;
121             options.onoff             = 1;
122             options.keepalivetime     = time * 1000;
123             options.keepaliveinterval = interval * 1000;
124             uint cbBytesReturned;
125             if (WSAIoctl(_socket.handle(), SIO_KEEPALIVE_VALS, &options, options.sizeof, null, 0, &cbBytesReturned, null, null) != 0)
126             {
127                 //throw new SocketOSException("Error setting keep-alive.");
128             }
129         }
130         else
131         static if (is(typeof(TCP_KEEPIDLE)) && is(typeof(TCP_KEEPINTVL)))
132         {
133             setOption(SocketOptionLevel.TCP, cast(SocketOption) TCP_KEEPIDLE,  time);
134             setOption(SocketOptionLevel.TCP, cast(SocketOption) TCP_KEEPINTVL, interval);
135             setOption(SocketOptionLevel.SOCKET, SocketOption.KEEPALIVE, true);
136         }
137         else
138         {
139             //throw new SocketFeatureException("Setting keep-alive options is not supported on this platform.");
140         }
141     }
142 
143 protected:
144 
145     Socket _socket;
146 
147     bool _reusePort = false;
148     bool _blocking  = false;
149 }