132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2004 Kris Bell. All rights reserved
|
|
4
|
|
5 license: BSD style: $(LICENSE)
|
|
6
|
|
7 version: Mar 2004 : Initial release
|
|
8 version: Jan 2005 : RedShodan patch for timeout query
|
|
9 version: Dec 2006 : Outback release
|
|
10
|
|
11 author: Kris
|
|
12
|
|
13 *******************************************************************************/
|
|
14
|
|
15 module tango.net.SocketConduit;
|
|
16
|
|
17 private import tango.time.Time;
|
|
18
|
|
19 public import tango.io.Conduit;
|
|
20
|
|
21 private import tango.net.Socket;
|
|
22
|
|
23 /*******************************************************************************
|
|
24
|
|
25 A wrapper around the bare Socket to implement the IConduit abstraction
|
|
26 and add socket-specific functionality.
|
|
27
|
|
28 SocketConduit data-transfer is typically performed in conjunction with
|
|
29 an IBuffer, but can happily be handled directly using void array where
|
|
30 preferred
|
|
31
|
|
32 *******************************************************************************/
|
|
33
|
|
34 class SocketConduit : Conduit
|
|
35 {
|
|
36 private timeval tv;
|
|
37 private SocketSet ss;
|
|
38 package Socket socket_;
|
|
39 private bool timeout;
|
|
40
|
|
41 // freelist support
|
|
42 private SocketConduit next;
|
|
43 private bool fromList;
|
|
44 private static SocketConduit freelist;
|
|
45
|
|
46 /***********************************************************************
|
|
47
|
|
48 Create a streaming Internet Socket
|
|
49
|
|
50 ***********************************************************************/
|
|
51
|
|
52 this ()
|
|
53 {
|
|
54 this (SocketType.STREAM, ProtocolType.TCP);
|
|
55 }
|
|
56
|
|
57 /***********************************************************************
|
|
58
|
|
59 Create an Internet Socket. Used by subclasses and by
|
|
60 ServerSocket; the latter via method allocate() below
|
|
61
|
|
62 ***********************************************************************/
|
|
63
|
|
64 protected this (SocketType type, ProtocolType protocol, bool create=true)
|
|
65 {
|
|
66 socket_ = new Socket (AddressFamily.INET, type, protocol, create);
|
|
67 }
|
|
68
|
|
69 /***********************************************************************
|
|
70
|
|
71 Return the name of this device
|
|
72
|
|
73 ***********************************************************************/
|
|
74
|
|
75 override char[] toString()
|
|
76 {
|
|
77 return socket.toString;
|
|
78 }
|
|
79
|
|
80 /***********************************************************************
|
|
81
|
|
82 Return the socket wrapper
|
|
83
|
|
84 ***********************************************************************/
|
|
85
|
|
86 Socket socket ()
|
|
87 {
|
|
88 return socket_;
|
|
89 }
|
|
90
|
|
91 /***********************************************************************
|
|
92
|
|
93 Return a preferred size for buffering conduit I/O
|
|
94
|
|
95 ***********************************************************************/
|
|
96
|
|
97 override uint bufferSize ()
|
|
98 {
|
|
99 return 1024 * 8;
|
|
100 }
|
|
101
|
|
102 /***********************************************************************
|
|
103
|
|
104 Models a handle-oriented device.
|
|
105
|
|
106 TODO: figure out how to avoid exposing this in the general
|
|
107 case
|
|
108
|
|
109 ***********************************************************************/
|
|
110
|
|
111 override Handle fileHandle ()
|
|
112 {
|
|
113 return cast(Handle) socket_.fileHandle;
|
|
114 }
|
|
115
|
|
116 /***********************************************************************
|
|
117
|
|
118 Set the read timeout to the specified interval. Set a
|
|
119 value of zero to disable timeout support.
|
|
120
|
|
121 ***********************************************************************/
|
|
122
|
|
123 SocketConduit setTimeout (TimeSpan interval)
|
|
124 {
|
|
125 tv = Socket.toTimeval (interval);
|
|
126 return this;
|
|
127 }
|
|
128
|
|
129 /***********************************************************************
|
|
130
|
|
131 Did the last operation result in a timeout?
|
|
132
|
|
133 ***********************************************************************/
|
|
134
|
|
135 bool hadTimeout ()
|
|
136 {
|
|
137 return timeout;
|
|
138 }
|
|
139
|
|
140 /***********************************************************************
|
|
141
|
|
142 Is this socket still alive?
|
|
143
|
|
144 ***********************************************************************/
|
|
145
|
|
146 override bool isAlive ()
|
|
147 {
|
|
148 return socket_.isAlive;
|
|
149 }
|
|
150
|
|
151 /***********************************************************************
|
|
152
|
|
153 Connect to the provided endpoint
|
|
154
|
|
155 ***********************************************************************/
|
|
156
|
|
157 SocketConduit connect (Address addr)
|
|
158 {
|
|
159 socket_.connect (addr);
|
|
160 return this;
|
|
161 }
|
|
162
|
|
163 /***********************************************************************
|
|
164
|
|
165 Bind the socket. This is typically used to configure a
|
|
166 listening socket (such as a server or multicast socket).
|
|
167 The address given should describe a local adapter, or
|
|
168 specify the port alone (ADDR_ANY) to have the OS assign
|
|
169 a local adapter address.
|
|
170
|
|
171 ***********************************************************************/
|
|
172
|
|
173 SocketConduit bind (Address address)
|
|
174 {
|
|
175 socket_.bind (address);
|
|
176 return this;
|
|
177 }
|
|
178
|
|
179 /***********************************************************************
|
|
180
|
|
181 Inform other end of a connected socket that we're no longer
|
|
182 available. In general, this should be invoked before close()
|
|
183 is invoked
|
|
184
|
|
185 The shutdown function shuts down the connection of the socket:
|
|
186
|
|
187 - stops receiving data for this socket. If further data
|
|
188 arrives, it is rejected.
|
|
189
|
|
190 - stops trying to transmit data from this socket. Also
|
|
191 discards any data waiting to be sent. Stop looking for
|
|
192 acknowledgement of data already sent; don't retransmit
|
|
193 if any data is lost.
|
|
194
|
|
195 ***********************************************************************/
|
|
196
|
|
197 SocketConduit shutdown ()
|
|
198 {
|
|
199 socket_.shutdown (SocketShutdown.BOTH);
|
|
200 return this;
|
|
201 }
|
|
202
|
|
203 /***********************************************************************
|
|
204
|
|
205 Read content from socket. This is implemented as a callback
|
|
206 from the reader() method so we can expose the timout support
|
|
207 to subclasses
|
|
208
|
|
209 ***********************************************************************/
|
|
210
|
|
211 protected uint socketReader (void[] dst)
|
|
212 {
|
|
213 return socket_.receive (dst);
|
|
214 }
|
|
215
|
|
216 /***********************************************************************
|
|
217
|
|
218 Release this SocketConduit
|
|
219
|
|
220 Note that one should always disconnect a SocketConduit
|
|
221 under normal conditions, and generally invoke shutdown
|
|
222 on all connected sockets beforehand
|
|
223
|
|
224 ***********************************************************************/
|
|
225
|
|
226 override void detach ()
|
|
227 {
|
|
228 socket_.detach;
|
|
229
|
|
230 // deallocate if this came from the free-list,
|
|
231 // otherwise just wait for the GC to handle it
|
|
232 if (fromList)
|
|
233 deallocate (this);
|
|
234 }
|
|
235
|
|
236 /***********************************************************************
|
|
237
|
|
238 Callback routine to read content from the socket. Note
|
|
239 that the operation may timeout if method setTimeout()
|
|
240 has been invoked with a non-zero value.
|
|
241
|
|
242 Returns the number of bytes read from the socket, or
|
|
243 IConduit.Eof where there's no more content available
|
|
244
|
|
245 Note that a timeout is equivalent to Eof. Isolating
|
|
246 a timeout condition can be achieved via hadTimeout()
|
|
247
|
|
248 Note also that a zero return value is not legitimate;
|
|
249 such a value indicates Eof
|
|
250
|
|
251 ***********************************************************************/
|
|
252
|
|
253 override uint read (void[] dst)
|
|
254 {
|
|
255 // ensure just one read at a time
|
|
256 synchronized (this)
|
|
257 {
|
|
258 // reset timeout; we assume there's no thread contention
|
|
259 timeout = false;
|
|
260
|
|
261 // did user disable timeout checks?
|
|
262 if (tv.tv_usec | tv.tv_sec)
|
|
263 {
|
|
264 // nope: ensure we have a SocketSet
|
|
265 if (ss is null)
|
|
266 ss = new SocketSet (1);
|
|
267
|
|
268 ss.reset ();
|
|
269 ss.add (socket_);
|
|
270
|
|
271 // wait until data is available, or a timeout occurs
|
|
272 auto copy = tv;
|
|
273 int i = socket_.select (ss, null, null, ©);
|
|
274
|
|
275 if (i <= 0)
|
|
276 {
|
|
277 if (i is 0)
|
|
278 timeout = true;
|
|
279 return Eof;
|
|
280 }
|
|
281 }
|
|
282
|
|
283 // invoke the actual read op
|
|
284 int count = socketReader (dst);
|
|
285 if (count <= 0)
|
|
286 count = Eof;
|
|
287 return count;
|
|
288 }
|
|
289 }
|
|
290
|
|
291 /***********************************************************************
|
|
292
|
|
293 Callback routine to write the provided content to the
|
|
294 socket. This will stall until the socket responds in
|
|
295 some manner. Returns the number of bytes sent to the
|
|
296 output, or IConduit.Eof if the socket cannot write.
|
|
297
|
|
298 ***********************************************************************/
|
|
299
|
|
300 override uint write (void[] src)
|
|
301 {
|
|
302 int count = socket_.send (src);
|
|
303 if (count <= 0)
|
|
304 count = Eof;
|
|
305 return count;
|
|
306 }
|
|
307
|
|
308 /***********************************************************************
|
|
309
|
|
310 Allocate a SocketConduit from a list rather than creating
|
|
311 a new one. Note that the socket itself is not opened; only
|
|
312 the wrappers. This is because the socket is often assigned
|
|
313 directly via accept()
|
|
314
|
|
315 ***********************************************************************/
|
|
316
|
|
317 package static synchronized SocketConduit allocate ()
|
|
318 {
|
|
319 SocketConduit s;
|
|
320
|
|
321 if (freelist)
|
|
322 {
|
|
323 s = freelist;
|
|
324 freelist = s.next;
|
|
325 }
|
|
326 else
|
|
327 {
|
|
328 s = new SocketConduit (SocketType.STREAM, ProtocolType.TCP, false);
|
|
329 s.fromList = true;
|
|
330 }
|
|
331 return s;
|
|
332 }
|
|
333
|
|
334 /***********************************************************************
|
|
335
|
|
336 Return this SocketConduit to the free-list
|
|
337
|
|
338 ***********************************************************************/
|
|
339
|
|
340 private static synchronized void deallocate (SocketConduit s)
|
|
341 {
|
|
342 s.next = freelist;
|
|
343 freelist = s;
|
|
344 }
|
|
345 }
|
|
346
|