2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System / System.Net / FtpDataStream.cs
1 //
2 // System.Net.FtpDataStream.cs
3 //
4 // Authors:
5 //      Carlos Alberto Cortez (calberto.cortez@gmail.com)
6 //
7 // (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
8 //
9
10 using System;
11 using System.IO;
12 using System.Net.Sockets;
13 using System.Runtime.Remoting.Messaging;
14 using System.Threading;
15 using System.Net;
16
17 #if NET_2_0
18
19 namespace System.Net
20 {
21         class FtpDataStream : Stream, IDisposable
22         {
23                 FtpWebRequest request;
24                 NetworkStream networkStream;
25                 Socket socket;
26                 bool disposed;
27                 bool isRead;
28                 int totalRead;
29
30                 internal FtpDataStream (FtpWebRequest request, Socket socket, bool isRead)
31                 {
32                         if (request == null)
33                                 throw new ArgumentNullException ("request");
34                         if (socket == null)
35                                 throw new ArgumentNullException ("socket");
36                         if (!socket.Connected)
37                                 throw new ArgumentException ("socket");
38
39                         this.request = request;
40                         this.socket = socket;
41                         this.networkStream = new NetworkStream (socket, true);
42                         this.isRead = isRead;
43
44                         if (request.EnableSsl) {
45                                 FtpWebRequest.ChangeToSSLSocket (ref networkStream);
46                         }
47                 }
48
49                 public override bool CanRead {
50                         get {
51                                 return isRead;
52                         }
53                 }
54
55                 public override bool CanWrite {
56                         get {
57                                 return !isRead;
58                         }
59                 }
60
61                 public override bool CanSeek {
62                         get {
63                                 return false;
64                         }
65                 }
66
67                 public override long Length {
68                         get {
69                                 throw new NotSupportedException ();
70                         }
71                 }
72
73                 public override long Position {
74                         get {
75                                 throw new NotSupportedException ();
76                         }
77                         set {
78                                 throw new NotSupportedException ();
79                         }
80                 }
81
82                 internal NetworkStream NetworkStream {
83                         get {
84                                 CheckDisposed ();
85                                 return networkStream;
86                         }
87                 }
88
89                 public override void Close ()
90                 {
91                         Dispose (true);
92                 }
93
94                 public override void Flush ()
95                 {
96                         // Do nothing.
97                 }
98
99                 public override long Seek (long offset, SeekOrigin origin)
100                 {
101                         throw new NotSupportedException ();
102                 }
103
104                 public override void SetLength (long value)
105                 {
106                         throw new NotSupportedException ();
107                 }
108
109                 int ReadInternal (byte [] buffer, int offset, int size)
110                 {
111                         int nbytes;
112
113                         request.CheckIfAborted ();
114
115                         try {
116                                 // Probably it would be better to have the socket here
117                                 nbytes = networkStream.Read (buffer, offset, size);
118                         } catch (IOException) {
119                                 throw new ProtocolViolationException ("Server commited a protocol violation");
120                         }
121
122                         totalRead += nbytes;
123                         if (nbytes == 0) {
124                                 networkStream.Close ();
125                                 request.SetTransferCompleted ();
126                         }
127
128                         return nbytes;
129                 }
130
131                 public override IAsyncResult BeginRead (byte [] buffer, int offset, int size, AsyncCallback cb, object state)
132                 {
133                         CheckDisposed ();
134
135                         if (!isRead)
136                                 throw new NotSupportedException ();
137                         if (buffer == null)
138                                 throw new ArgumentNullException ("buffer");
139                         if (offset < 0 || offset > buffer.Length)
140                                 throw new ArgumentOutOfRangeException ("offset");
141                         if (size < 0 || size > buffer.Length - offset)
142                                 throw new ArgumentOutOfRangeException ("offset+size");
143
144                         ReadDelegate del = ReadInternal;
145                         return del.BeginInvoke (buffer, offset, size, cb, state);
146                 }
147
148                 public override int EndRead (IAsyncResult asyncResult)
149                 {
150                         if (asyncResult == null)
151                                 throw new ArgumentNullException ("asyncResult");
152
153                         AsyncResult ar = asyncResult as AsyncResult;
154                         if (ar == null)
155                                 throw new ArgumentException ("Invalid asyncResult", "asyncResult");
156                         
157                         ReadDelegate del = ar.AsyncDelegate as ReadDelegate;
158                         if (del == null)
159                                 throw new ArgumentException ("Invalid asyncResult", "asyncResult");
160
161                         return del.EndInvoke (asyncResult);
162                 }
163
164                 public override int Read (byte [] buffer, int offset, int size)
165                 {
166                         request.CheckIfAborted ();
167                         IAsyncResult ar = BeginRead (buffer, offset, size, null, null);
168                         if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (request.ReadWriteTimeout, false))
169                                 throw new WebException ("Read timed out.", WebExceptionStatus.Timeout);
170
171                         return EndRead (ar);
172                 }
173
174
175                 delegate void WriteDelegate (byte [] buffer, int offset, int size);
176                 
177                 void WriteInternal (byte [] buffer, int offset, int size)
178                 {
179                         request.CheckIfAborted ();
180                         
181                         try {
182                                 networkStream.Write (buffer, offset, size);
183                         } catch (IOException) {
184                                 throw new ProtocolViolationException ();
185                         }
186                 }
187
188                 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size, AsyncCallback cb, object state)
189                 {
190                         CheckDisposed ();
191                         if (isRead)
192                                 throw new NotSupportedException ();
193                         if (buffer == null)
194                                 throw new ArgumentNullException ("buffer");
195                         if (offset < 0 || offset > buffer.Length)
196                                 throw new ArgumentOutOfRangeException ("offset");
197                         if (size < 0 || size > buffer.Length - offset)
198                                 throw new ArgumentOutOfRangeException ("offset+size");
199
200                         WriteDelegate del = WriteInternal;
201                         return del.BeginInvoke (buffer, offset, size, cb, state);
202                 }
203
204                 public override void EndWrite (IAsyncResult asyncResult)
205                 {
206                         if (asyncResult == null)
207                                 throw new ArgumentNullException ("asyncResult");
208
209                         AsyncResult ar = asyncResult as AsyncResult;
210                         if (ar == null)
211                                 throw new ArgumentException ("Invalid asyncResult.", "asyncResult");
212
213                         WriteDelegate del = ar.AsyncDelegate as WriteDelegate;
214                         if (del == null)
215                                 throw new ArgumentException ("Invalid asyncResult.", "asyncResult");
216
217                         del.EndInvoke (asyncResult);
218                 }
219
220                 public override void Write (byte [] buffer, int offset, int size)
221                 {
222                         request.CheckIfAborted ();
223                         IAsyncResult ar = BeginWrite (buffer, offset, size, null, null);
224                         if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (request.ReadWriteTimeout, false))
225                                 throw new WebException ("Read timed out.", WebExceptionStatus.Timeout);
226
227                         EndWrite (ar);
228                 }
229
230                 ~FtpDataStream ()
231                 {
232                         Dispose (false);
233                 }
234
235                 void IDisposable.Dispose ()
236                 {
237                         Dispose (true);
238                         GC.SuppressFinalize (this);
239                 }
240
241                 protected override void Dispose (bool disposing)
242                 {
243                         if (disposed)
244                                 return;
245
246                         disposed = true;
247                         if (socket != null) {
248                                 try {
249                                         if (socket.Poll (0, SelectMode.SelectRead)) {
250                                                 byte [] bytes = new byte [2048];
251                                                 int nbytes;
252                                                 do {
253                                                         nbytes = socket.Receive (bytes);
254                                                 } while (nbytes > 0 && socket.Poll (0, SelectMode.SelectRead));
255                                         }
256                                 } catch {
257                                         // Ignore
258                                 }
259
260                                 try {
261                                         networkStream.Close ();
262                                 } catch {
263                                 }
264                                 networkStream = null;
265                                 socket = null;
266                                 request.SetTransferCompleted ();
267                                 request = null;
268                         }
269                 }
270
271                 void CheckDisposed ()
272                 {
273                         if (disposed)
274                                 throw new ObjectDisposedException (GetType ().FullName);
275                 }
276
277                 delegate int ReadDelegate (byte [] buffer, int offset, int size);
278         }
279 }
280
281 #endif
282