Mercurial > projects > ldc
comparison tango/tango/net/SocketConduit.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:5825d48b27d1 | 132:1700239cab2e |
---|---|
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 |