Wed Feb 24 15:47:16 CET 2010 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / class / System / System.Net.Sockets / NetworkStream.cs
1 //
2 // System.Net.Sockets.NetworkStream.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Sridhar Kulkarni <sridharkulkarni@gmail.com>
7 //
8 // (C) 2002 Ximian, Inc. http://www.ximian.com
9 // Copyright (C) 2002-2006 Novell, Inc.  http://www.novell.com
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.IO;
34 using System.Runtime.InteropServices;
35 #if NET_2_0 && !NET_2_1
36 using System.Timers;
37 using System.Threading;
38 #endif
39
40 namespace System.Net.Sockets
41 {
42         public class NetworkStream : Stream, IDisposable {
43                 FileAccess access;
44                 Socket socket;
45                 bool owns_socket;
46                 bool readable, writeable;
47                 bool disposed = false;
48                 
49                 public NetworkStream (Socket socket)
50                         : this (socket, FileAccess.ReadWrite, false)
51                 {
52                 }
53
54                 public NetworkStream (Socket socket, bool owns_socket)
55                         : this (socket, FileAccess.ReadWrite, owns_socket)
56                 {
57                 }
58
59                 public NetworkStream (Socket socket, FileAccess access)
60                         : this (socket, access, false)
61                 {
62                 }
63                 
64                 public NetworkStream (Socket socket, FileAccess access, bool owns_socket)
65                 {
66                         if (socket == null)
67                                 throw new ArgumentNullException ("socket is null");
68                         if (socket.SocketType != SocketType.Stream)
69                                 throw new ArgumentException ("Socket is not of type Stream", "socket");
70                         if (!socket.Connected)
71                                 throw new IOException ("Not connected");
72                         if (!socket.Blocking)
73                                 throw new IOException ("Operation not allowed on a non-blocking socket.");
74                         
75                         this.socket = socket;
76                         this.owns_socket = owns_socket;
77                         this.access = access;
78
79                         readable = CanRead;
80                         writeable = CanWrite;
81                 }
82
83                 public override bool CanRead {
84                         get {
85                                 return access == FileAccess.ReadWrite || access == FileAccess.Read;
86                         }
87                 }
88
89                 public override bool CanSeek {
90                         get {
91                                 // network sockets cant seek.
92                                 return false;
93                         }
94                 }
95
96 #if NET_2_0
97                 public override bool CanTimeout
98                 {
99                         get {
100                                 return(true);
101                         }
102                 }
103 #endif
104
105                 public override bool CanWrite {
106                         get {
107                                 return access == FileAccess.ReadWrite || access == FileAccess.Write;
108                         }
109                 }
110
111                 public virtual bool DataAvailable {
112                         get {
113                                 CheckDisposed ();
114                                 return socket.Available > 0;
115                         }
116                 }
117
118                 public override long Length {
119                         get {
120                                 // Network sockets always throw an exception
121                                 throw new NotSupportedException ();
122                         }
123                 }
124
125                 public override long Position {
126                         get {
127                                 // Network sockets always throw an exception
128                                 throw new NotSupportedException ();
129                         }
130                         
131                         set {
132                                 // Network sockets always throw an exception
133                                 throw new NotSupportedException ();
134                         }
135                 }
136
137                 protected bool Readable {
138                         get {
139                                 return readable;
140                         }
141
142                         set {
143                                 readable = value;
144                         }
145                 }
146
147 #if NET_2_0 && !NET_2_1
148 #if TARGET_JVM
149                 [MonoNotSupported ("Not supported since Socket.ReceiveTimeout is not supported")]
150 #endif
151                 public override int ReadTimeout
152                 {
153                         get {
154                                 return(socket.ReceiveTimeout);
155                         }
156                         set {
157                                 if (value <= 0 && value != Timeout.Infinite) {
158                                         throw new ArgumentOutOfRangeException ("value", "The value specified is less than or equal to zero and is not Infinite.");
159                                 }
160                                 
161                                 socket.ReceiveTimeout = value;
162                         }
163                 }
164 #endif
165
166                 protected Socket Socket {
167                         get {
168                                 return socket;
169                         }
170                 }
171
172                 protected bool Writeable {
173                         get {
174                                 return writeable;
175                         }
176
177                         set {
178                                 writeable = value;
179                         }
180                 }
181
182 #if NET_2_0 && !NET_2_1
183 #if TARGET_JVM
184                 [MonoNotSupported ("Not supported since Socket.SendTimeout is not supported")]
185 #endif
186                 public override int WriteTimeout
187                 {
188                         get {
189                                 return(socket.SendTimeout);
190                         }
191                         set {
192                                 if (value <= 0 && value != Timeout.Infinite) {
193                                         throw new ArgumentOutOfRangeException ("value", "The value specified is less than or equal to zero and is not Infinite");
194                                 }
195                                 
196                                 socket.SendTimeout = value;
197                         }
198                 }
199 #endif
200
201                 public override IAsyncResult BeginRead (byte [] buffer, int offset, int size,
202                                                         AsyncCallback callback, object state)
203                 {
204                         CheckDisposed ();                               
205                         IAsyncResult retval;
206
207                         if (buffer == null)
208                                 throw new ArgumentNullException ("buffer is null");
209                         int len = buffer.Length;
210                         if(offset<0 || offset>len) {
211                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
212                         }
213                         if(size<0 || offset+size>len) {
214                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
215                         }
216
217                         try {
218                                 retval = socket.BeginReceive (buffer, offset, size, 0, callback, state);
219                         } catch (Exception e) {
220                                 throw new IOException ("BeginReceive failure", e);
221                         }
222
223                         return retval;
224                 }
225
226                 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size,
227                                                         AsyncCallback callback, object state)
228                 {
229                         CheckDisposed ();
230                         IAsyncResult retval;
231
232                         if (buffer == null)
233                                 throw new ArgumentNullException ("buffer is null");
234
235                         int len = buffer.Length;
236                         if(offset<0 || offset>len) {
237                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
238                         }
239                         if(size<0 || offset+size>len) {
240                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
241                         }
242
243                         try {
244                                 retval = socket.BeginSend (buffer, offset, size, 0, callback, state);
245                         } catch {
246                                 throw new IOException ("BeginWrite failure");
247                         }
248
249                         return retval;
250                 }
251
252                 ~NetworkStream ()
253                 {
254                         Dispose (false);
255                 }
256                 
257 #if !NET_2_0
258                 public override void Close ()
259                 {
260                         ((IDisposable) this).Dispose ();
261                 }
262 #endif
263
264 #if NET_2_0 && !NET_2_1
265                 public void Close (int timeout)
266                 {
267                         if (timeout < -1) {
268                                 throw new ArgumentOutOfRangeException ("timeout", "timeout is less than -1");
269                         }
270                         
271                         System.Timers.Timer close_timer = new System.Timers.Timer ();
272                         close_timer.Elapsed += new ElapsedEventHandler (OnTimeoutClose);
273                         /* NB timeout is in milliseconds here, cf
274                          * seconds in Socket.Close(int)
275                          */
276                         close_timer.Interval = timeout;
277                         close_timer.AutoReset = false;
278                         close_timer.Enabled = true;
279                 }
280                 
281                 private void OnTimeoutClose (object source, ElapsedEventArgs e)
282                 {
283                         this.Close ();
284                 }
285 #endif
286
287                 protected
288 #if NET_2_0
289                 override
290 #else
291                 virtual
292 #endif
293                 void Dispose (bool disposing)
294                 {
295                         if (disposed) 
296                                 return;
297                         disposed = true;
298                         
299                         if (owns_socket) {
300                                 Socket s = socket;
301                                 if (s != null)
302                                         s.Close ();
303                         }
304                         socket = null;
305                         access = 0;
306
307                         if (disposing)
308                                 GC.SuppressFinalize (this);
309                 }
310
311                 public override int EndRead (IAsyncResult ar)
312                 {
313                         CheckDisposed ();
314                         int res;
315
316                         if (ar == null)
317                                 throw new ArgumentNullException ("async result is null");
318
319                         try {
320                                 res = socket.EndReceive (ar);
321                         } catch (Exception e) {
322                                 throw new IOException ("EndRead failure", e);
323                         }
324                         return res;
325                 }
326
327                 public override void EndWrite (IAsyncResult ar)
328                 {
329                         CheckDisposed ();
330                         if (ar == null)
331                                 throw new ArgumentNullException ("async result is null");
332
333                         try {
334                                 socket.EndSend (ar);
335                         } catch (Exception e) {
336                                 throw new IOException ("EndWrite failure", e);
337                         }
338                 }
339
340                 public override void Flush ()
341                 {
342                         // network streams are non-buffered, this is a no-op
343                 }
344
345 #if !NET_2_0
346                 void IDisposable.Dispose ()
347                 {
348                         Dispose (true);
349                 }
350 #endif
351
352                 public override int Read ([In,Out] byte [] buffer, int offset, int size)
353                 {
354                         CheckDisposed ();
355                         int res;
356
357                         if (buffer == null)
358                                 throw new ArgumentNullException ("buffer is null");
359                         if(offset<0 || offset>buffer.Length) {
360                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
361                         }
362                         if(size < 0 || offset+size>buffer.Length) {
363                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
364                         }
365
366                         try {
367                                 res = socket.Receive (buffer, offset, size, 0);
368                         } catch (Exception e) {
369                                 throw new IOException ("Read failure", e);
370                         }
371                         
372                         return res;
373                 }
374
375                 public override long Seek (long offset, SeekOrigin origin)
376                 {
377                         // NetworkStream objects do not support seeking.
378                         
379                         throw new NotSupportedException ();
380                 }
381
382                 public override void SetLength (long value)
383                 {
384                         // NetworkStream objects do not support SetLength
385                         
386                         throw new NotSupportedException ();
387                 }
388
389                 public override void Write (byte [] buffer, int offset, int size)
390                 {
391                         CheckDisposed ();
392                         if (buffer == null)
393                                 throw new ArgumentNullException ("buffer");
394
395                         if (offset < 0 || offset > buffer.Length)
396                                 throw new ArgumentOutOfRangeException("offset exceeds the size of buffer");
397
398                         if (size < 0 || size > buffer.Length - offset)
399                                 throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer");
400
401                         try {
402                                 int count = 0;
403                                 while (size - count > 0) {
404                                         count += socket.Send (buffer, offset + count, size - count, 0);
405                                 }
406                         } catch (Exception e) {
407                                 throw new IOException ("Write failure", e); 
408                         }
409                 }
410                 
411                 private void CheckDisposed ()
412                 {
413                         if (disposed)
414                                 throw new ObjectDisposedException (GetType().FullName);
415                 }
416
417 #if TARGET_JVM
418                 public void ChangeToSSLSocket()
419                 {
420                         socket.ChangeToSSL();
421                 }
422 #endif
423
424         }
425 }