1 module geario.net.channel.AbstractSocketChannel;
2 
3 import geario.event.selector.Selector;
4 import geario.net.channel.AbstractChannel;
5 import geario.net.channel.Types;
6 import geario.logging;
7 
8 import core.time;
9 import std.functional;
10 import std.socket;
11 import core.stdc.stdint;
12 
13 /**
14  * 
15  */
16 abstract class AbstractSocketChannel : AbstractChannel {
17 
18     protected shared bool _isWritting = false; // keep a data write operation atomic
19 
20     protected Socket _socket;
21 
22     this(Selector loop, ChannelType type) {
23         super(loop, type);
24     }
25 
26     // Busy with reading or writting
27     protected bool IsBusy() {
28         return false;
29     }
30 
31     protected @property void socket(Socket s) {
32         this.handle = s.handle();
33         version (Posix) {
34             s.blocking = false;
35         }
36         _socket = s;
37         version (GEAR_DEBUG_MORE)
38             log.info("new socket: fd=%d", this.handle);
39     }
40 
41     @property Socket socket() {
42         return _socket;
43     }
44 
45     override void Close()
46     {
47         // if (_isClosing) {
48         //     // debug log.warn("already closed [fd=%d]", this.handle);
49         //     return;
50         // }
51         // _isClosing = true;
52         version (GEAR_IO_MORE) log.trace("socket channel closing [fd=%d]...", this.handle);
53 
54         version (HAVE_IOCP)
55         {
56             super.Close();
57         }
58         else
59         {
60             if (IsBusy()) {
61                 import std.parallelism;
62 
63                 version (GEAR_DEBUG) log.warn("Close operation delayed");
64 
65                 auto theTask = task(() {
66                     super.Close();
67                     while (IsBusy())
68                     {
69                         version (GEAR_DEBUG)
70                             log.info("waitting for idle [fd=%d]...", this.handle);
71                         // Thread.sleep(20.msecs);
72                     }
73                 });
74 
75                 taskPool.put(theTask);
76             } else {
77                 super.Close();
78             }
79         }
80     }
81 
82     /// Get a socket option.
83     /// Returns: The number of bytes written to $(D result).
84     ///    returns the length, in bytes, of the actual result - very different from getsockopt()
85     pragma(inline) final int getOption(SocketOptionLevel level, SocketOption option, void[] result) @trusted {
86         return this._socket.getOption(level, option, result);
87     }
88 
89     /// Common case of getting integer and boolean options.
90     pragma(inline) final int getOption(SocketOptionLevel level,
91             SocketOption option, ref int32_t result) @trusted {
92         return this._socket.getOption(level, option, result);
93     }
94 
95     /// Get the linger option.
96     pragma(inline) final int getOption(SocketOptionLevel level, SocketOption option,
97             ref Linger result) @trusted {
98         return this._socket.getOption(level, option, result);
99     }
100 
101     /// Get a timeout (duration) option.
102     pragma(inline) final void getOption(SocketOptionLevel level,
103             SocketOption option, ref Duration result) @trusted {
104         this._socket.getOption(level, option, result);
105     }
106 
107     /// Set a socket option.
108     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option, void[] value) @trusted {
109         this._socket.setOption(forward!(level, option, value));
110     }
111 
112     /// Common case for setting integer and boolean options.
113     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option, int32_t value) @trusted {
114         this._socket.setOption(forward!(level, option, value));
115     }
116 
117     /// Set the linger option.
118     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option, Linger value) @trusted {
119         this._socket.setOption(forward!(level, option, value));
120     }
121 
122     pragma(inline) final void setOption(SocketOptionLevel level, SocketOption option, Duration value) @trusted {
123         this._socket.setOption(forward!(level, option, value));
124     }
125 
126     final @trusted Address RemoteAddress() {
127         return _remoteAddress;
128     }
129 
130     protected Address _remoteAddress;
131 
132     final @trusted Address LocalAddress() {
133         return _localAddress;
134     }
135 
136     protected Address _localAddress;
137 
138     version (HAVE_IOCP) {
139         void setRead(size_t bytes) {
140             readLen = bytes;
141         }
142 
143         protected size_t readLen;
144     }
145 
146     void Start();
147 
148     void OnWriteDone()
149     {
150         assert(false, "unimplemented");
151     }
152 }