0
|
1 /*******************************************************************************
|
|
2
|
2
|
3 copyright: Copyright (c) 2004 Kris Bell. All rights reserved
|
0
|
4
|
2
|
5 license: BSD style: $(LICENSE)
|
0
|
6
|
2
|
7 version: Mar 2004 : Initial release
|
|
8 version: Jan 2005 : RedShodan patch for timeout query
|
|
9 version: Dec 2006 : Outback release
|
0
|
10
|
2
|
11 author: Kris, modified by Rick Richardson (May 2008)
|
|
12
|
|
13 *******************************************************************************/
|
0
|
14
|
|
15 module dreactor.transport.AsyncSocketConduit;
|
|
16
|
|
17 private import tango.time.Time;
|
|
18
|
|
19 public import tango.io.Conduit;
|
|
20
|
|
21 private import tango.net.Socket;
|
|
22
|
2
|
23 import tango.net.Socket.Address;
|
|
24
|
0
|
25 /*******************************************************************************
|
|
26
|
2
|
27 A wrapper around the bare Socket to implement the IConduit abstraction
|
|
28 and add socket-specific functionality specifically for multiplexing via
|
|
29 poll and the ilk.
|
0
|
30
|
2
|
31 AsyncSocketConduit data-transfer is typically performed in conjunction with
|
|
32 an IBuffer, but can happily be handled directly using void array where
|
|
33 preferred
|
|
34
|
|
35 *******************************************************************************/
|
|
36 alias IPv4Address Address;
|
0
|
37
|
|
38 class AsyncSocketConduit : Conduit
|
|
39 {
|
2
|
40 package Socket socket_;
|
0
|
41
|
2
|
42 /***********************************************************************
|
|
43
|
|
44 Create a streaming Internet Socket
|
0
|
45
|
2
|
46 ***********************************************************************/
|
|
47 /* overriding the enum from the IConduit interface */
|
|
48 enum : uint
|
|
49 {
|
|
50 Eof = uint.max, /// the End-of-Flow identifer
|
|
51 Err = uint.max -1 // some error ocurred, Should disconnect
|
|
52 }
|
0
|
53
|
2
|
54 this ()
|
|
55 {
|
|
56 this (SocketType.STREAM, ProtocolType.TCP);
|
|
57 }
|
0
|
58
|
2
|
59 /***********************************************************************
|
0
|
60
|
2
|
61 Create an Internet Socket. Used by subclasses and by
|
|
62 ServerSocket; the latter via method allocate() below
|
|
63
|
|
64 ***********************************************************************/
|
0
|
65
|
2
|
66 protected this (SocketType type, ProtocolType protocol, bool create=true)
|
|
67 {
|
|
68 socket_ = new Socket (AddressFamily.INET, type, protocol, create);
|
|
69 }
|
0
|
70
|
2
|
71 /***********************************************************************
|
0
|
72
|
2
|
73 Return the name of this device
|
0
|
74
|
2
|
75 ***********************************************************************/
|
0
|
76
|
2
|
77 override char[] toString()
|
|
78 {
|
|
79 return socket.toString;
|
|
80 }
|
0
|
81
|
2
|
82 /***********************************************************************
|
|
83
|
|
84 Return the socket wrapper
|
0
|
85
|
2
|
86 ***********************************************************************/
|
0
|
87
|
2
|
88 Socket socket ()
|
|
89 {
|
|
90 return socket_;
|
|
91 }
|
0
|
92
|
2
|
93 /***********************************************************************
|
|
94
|
|
95 Return a preferred size for buffering conduit I/O
|
0
|
96
|
2
|
97 ***********************************************************************/
|
0
|
98
|
2
|
99 override uint bufferSize ()
|
|
100 {
|
|
101 return 1024 * 8;
|
|
102 }
|
0
|
103
|
2
|
104 /***********************************************************************
|
0
|
105
|
2
|
106 Models a handle-oriented device.
|
0
|
107
|
2
|
108 TODO: figure out how to avoid exposing this in the general
|
|
109 case
|
0
|
110
|
2
|
111 ***********************************************************************/
|
0
|
112
|
2
|
113 override Handle fileHandle ()
|
|
114 {
|
|
115 return cast(Handle) socket_.fileHandle;
|
|
116 }
|
0
|
117
|
2
|
118 /***********************************************************************
|
0
|
119
|
2
|
120 Is this socket still alive?
|
|
121
|
|
122 ***********************************************************************/
|
0
|
123
|
2
|
124 override bool isAlive ()
|
|
125 {
|
|
126 return socket_.isAlive;
|
|
127 }
|
0
|
128
|
2
|
129 /***********************************************************************
|
0
|
130
|
2
|
131 Connect to the provided endpoint
|
0
|
132
|
2
|
133 ***********************************************************************/
|
0
|
134
|
2
|
135 AsyncSocketConduit connect (Address addr)
|
|
136 {
|
|
137 socket_.connect (addr);
|
|
138 return this;
|
|
139 }
|
0
|
140
|
2
|
141 /***********************************************************************
|
0
|
142
|
2
|
143 Bind the socket. This is typically used to configure a
|
|
144 listening socket (such as a server or multicast socket).
|
|
145 The address given should describe a local adapter, or
|
|
146 specify the port alone (ADDR_ANY) to have the OS assign
|
|
147 a local adapter address.
|
|
148
|
|
149 ***********************************************************************/
|
|
150
|
|
151 AsyncSocketConduit bind (Address address)
|
|
152 {
|
|
153 socket_.bind (address);
|
|
154 return this;
|
|
155 }
|
0
|
156
|
2
|
157 /**************************************************************************
|
|
158
|
|
159 Enable the socket for listening
|
0
|
160
|
2
|
161 **************************************************************************/
|
|
162 AsyncSocketConduit listen()
|
|
163 {
|
|
164 socket_.listen();
|
|
165 return this;
|
|
166 }
|
|
167
|
|
168 /***********************************************************************
|
0
|
169
|
2
|
170 Inform other end of a connected socket that we're no longer
|
|
171 available. In general, this should be invoked before close()
|
|
172 is invoked
|
|
173
|
|
174 The shutdown function shuts down the connection of the socket:
|
0
|
175
|
2
|
176 - stops receiving data for this socket. If further data
|
|
177 arrives, it is rejected.
|
0
|
178
|
2
|
179 - stops trying to transmit data from this socket. Also
|
|
180 discards any data waiting to be sent. Stop looking for
|
|
181 acknowledgement of data already sent; don't retransmit
|
|
182 if any data is lost.
|
0
|
183
|
2
|
184 ***********************************************************************/
|
0
|
185
|
2
|
186 AsyncSocketConduit shutdown ()
|
|
187 {
|
|
188 socket_.shutdown (SocketShutdown.BOTH);
|
|
189 return this;
|
|
190 }
|
0
|
191
|
2
|
192 /***********************************************************************
|
|
193
|
|
194 Release this AsyncSocketConduit
|
0
|
195
|
2
|
196 Note that one should always disconnect a AsyncSocketConduit
|
|
197 under normal conditions, and generally invoke shutdown
|
|
198 on all connected sockets beforehand
|
0
|
199
|
2
|
200 ***********************************************************************/
|
0
|
201
|
2
|
202 override void detach ()
|
|
203 {
|
|
204 socket_.detach;
|
0
|
205
|
2
|
206 // deallocate if this came from the free-list,
|
|
207 // otherwise just wait for the GC to handle it
|
|
208 if (fromList)
|
|
209 deallocate (this);
|
|
210 }
|
|
211
|
|
212 /***********************************************************************
|
0
|
213
|
2
|
214 Read content from the socket.
|
|
215
|
|
216 Returns the number of bytes read from the socket, or
|
|
217 IConduit.Eof where there's no more content available
|
0
|
218
|
2
|
219 Note that a timeout is equivalent to Eof. Isolating
|
|
220 a timeout condition can be achieved via hadTimeout()
|
0
|
221
|
2
|
222 Note also that a zero return value is not legitimate;
|
|
223 such a value indicates Eof
|
0
|
224
|
2
|
225 ***********************************************************************/
|
0
|
226
|
2
|
227 override uint read (void[] dst)
|
|
228 {
|
|
229 return read (dst, (void[] dst){return socket_.receive(dst);});
|
|
230 }
|
|
231
|
|
232 /***********************************************************************
|
0
|
233
|
2
|
234 Callback routine to write the provided content to the
|
|
235 socket. This will stall until the socket responds in
|
|
236 some manner. Returns the number of bytes sent to the
|
|
237 output, or IConduit.Eof if the socket cannot write.
|
0
|
238
|
2
|
239 ***********************************************************************/
|
0
|
240
|
2
|
241 override uint write (void[] src)
|
|
242 {
|
|
243 int count = socket_.send (src);
|
|
244 if (count == 0)
|
|
245 count = Eof;
|
|
246 else if (count < 0)
|
|
247 count = Err;
|
|
248 return count;
|
|
249 }
|
0
|
250
|
2
|
251 /***********************************************************************
|
|
252
|
|
253 Internal routine to handle socket read under a timeout.
|
|
254 Note that this is synchronized, in order to serialize
|
|
255 socket access
|
0
|
256
|
2
|
257 ***********************************************************************/
|
0
|
258
|
2
|
259 package final uint read (void[] dst, int delegate(void[]) dg)
|
|
260 {
|
|
261 // invoke the actual read op
|
|
262 int count = dg (dst);
|
|
263 if (count == 0)
|
|
264 return Eof;
|
|
265 else if (count < 0)
|
|
266 return Err;
|
0
|
267
|
2
|
268 return count;
|
|
269 }
|
|
270
|
|
271 }
|
|
272
|