[sgen] Evacuate from emptier blocks to fuller ones
[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 namespace System.Net
18 {
19         class FtpDataStream : Stream, IDisposable
20         {
21                 FtpWebRequest request;
22                 Stream networkStream;
23                 bool disposed;
24                 bool isRead;
25                 int totalRead;
26
27                 internal FtpDataStream (FtpWebRequest request, Stream stream, bool isRead)
28                 {
29                         if (request == null)
30                                 throw new ArgumentNullException ("request");
31
32                         this.request = request;
33                         this.networkStream = stream;
34                         this.isRead = isRead;
35                 }
36
37                 public override bool CanRead {
38                         get {
39                                 return isRead;
40                         }
41                 }
42
43                 public override bool CanWrite {
44                         get {
45                                 return !isRead;
46                         }
47                 }
48
49                 public override bool CanSeek {
50                         get {
51                                 return false;
52                         }
53                 }
54
55                 public override long Length {
56                         get {
57                                 throw new NotSupportedException ();
58                         }
59                 }
60
61                 public override long Position {
62                         get {
63                                 throw new NotSupportedException ();
64                         }
65                         set {
66                                 throw new NotSupportedException ();
67                         }
68                 }
69
70                 internal Stream NetworkStream {
71                         get {
72                                 CheckDisposed ();
73                                 return networkStream;
74                         }
75                 }
76
77                 public override void Close ()
78                 {
79                         Dispose (true);
80                 }
81
82                 public override void Flush ()
83                 {
84                         // Do nothing.
85                 }
86
87                 public override long Seek (long offset, SeekOrigin origin)
88                 {
89                         throw new NotSupportedException ();
90                 }
91
92                 public override void SetLength (long value)
93                 {
94                         throw new NotSupportedException ();
95                 }
96
97                 int ReadInternal (byte [] buffer, int offset, int size)
98                 {
99                         int nbytes = 0;
100                         request.CheckIfAborted ();
101
102                         try {
103                                 // Probably it would be better to have the socket here
104                                 nbytes = networkStream.Read (buffer, offset, size);
105                         } catch (IOException) {
106                                 throw new ProtocolViolationException ("Server commited a protocol violation");
107                         }
108
109                         totalRead += nbytes;
110                         if (nbytes == 0) {
111                                 networkStream = null;
112                                 request.CloseDataConnection ();
113                                 request.SetTransferCompleted ();
114                         }
115
116                         return nbytes;
117                 }
118
119                 public override IAsyncResult BeginRead (byte [] buffer, int offset, int size, AsyncCallback cb, object state)
120                 {
121                         CheckDisposed ();
122
123                         if (!isRead)
124                                 throw new NotSupportedException ();
125                         if (buffer == null)
126                                 throw new ArgumentNullException ("buffer");
127                         if (offset < 0 || offset > buffer.Length)
128                                 throw new ArgumentOutOfRangeException ("offset");
129                         if (size < 0 || size > buffer.Length - offset)
130                                 throw new ArgumentOutOfRangeException ("offset+size");
131
132                         ReadDelegate del = ReadInternal;
133                         return del.BeginInvoke (buffer, offset, size, cb, state);
134                 }
135
136                 public override int EndRead (IAsyncResult asyncResult)
137                 {
138                         if (asyncResult == null)
139                                 throw new ArgumentNullException ("asyncResult");
140
141                         AsyncResult ar = asyncResult as AsyncResult;
142                         if (ar == null)
143                                 throw new ArgumentException ("Invalid asyncResult", "asyncResult");
144                         
145                         ReadDelegate del = ar.AsyncDelegate as ReadDelegate;
146                         if (del == null)
147                                 throw new ArgumentException ("Invalid asyncResult", "asyncResult");
148
149                         return del.EndInvoke (asyncResult);
150                 }
151
152                 public override int Read (byte [] buffer, int offset, int size)
153                 {
154                         request.CheckIfAborted ();
155                         IAsyncResult ar = BeginRead (buffer, offset, size, null, null);
156                         if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (request.ReadWriteTimeout, false))
157                                 throw new WebException ("Read timed out.", WebExceptionStatus.Timeout);
158                         return EndRead (ar);
159                 }
160
161
162                 delegate void WriteDelegate (byte [] buffer, int offset, int size);
163                 
164                 void WriteInternal (byte [] buffer, int offset, int size)
165                 {
166                         request.CheckIfAborted ();
167                         
168                         try {
169                                 networkStream.Write (buffer, offset, size);
170                         } catch (IOException) {
171                                 throw new ProtocolViolationException ();
172                         }
173                 }
174
175                 public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size, AsyncCallback cb, object state)
176                 {
177                         CheckDisposed ();
178                         if (isRead)
179                                 throw new NotSupportedException ();
180                         if (buffer == null)
181                                 throw new ArgumentNullException ("buffer");
182                         if (offset < 0 || offset > buffer.Length)
183                                 throw new ArgumentOutOfRangeException ("offset");
184                         if (size < 0 || size > buffer.Length - offset)
185                                 throw new ArgumentOutOfRangeException ("offset+size");
186
187                         WriteDelegate del = WriteInternal;
188                         return del.BeginInvoke (buffer, offset, size, cb, state);
189                 }
190
191                 public override void EndWrite (IAsyncResult asyncResult)
192                 {
193                         if (asyncResult == null)
194                                 throw new ArgumentNullException ("asyncResult");
195
196                         AsyncResult ar = asyncResult as AsyncResult;
197                         if (ar == null)
198                                 throw new ArgumentException ("Invalid asyncResult.", "asyncResult");
199
200                         WriteDelegate del = ar.AsyncDelegate as WriteDelegate;
201                         if (del == null)
202                                 throw new ArgumentException ("Invalid asyncResult.", "asyncResult");
203
204                         del.EndInvoke (asyncResult);
205                 }
206
207                 public override void Write (byte [] buffer, int offset, int size)
208                 {
209                         request.CheckIfAborted ();
210                         IAsyncResult ar = BeginWrite (buffer, offset, size, null, null);
211                         if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (request.ReadWriteTimeout, false))
212                                 throw new WebException ("Read timed out.", WebExceptionStatus.Timeout);
213
214                         EndWrite (ar);
215                 }
216
217                 ~FtpDataStream ()
218                 {
219                         Dispose (false);
220                 }
221
222                 void IDisposable.Dispose ()
223                 {
224                         Dispose (true);
225                         GC.SuppressFinalize (this);
226                 }
227
228                 protected override void Dispose (bool disposing)
229                 {
230                         if (disposed)
231                                 return;
232
233                         disposed = true;
234                         if (networkStream != null)  {
235                                 request.CloseDataConnection ();
236                                 request.SetTransferCompleted ();
237                                 request = null;
238                                 networkStream = null;
239                         }
240                 }
241
242                 void CheckDisposed ()
243                 {
244                         if (disposed)
245                                 throw new ObjectDisposedException (GetType ().FullName);
246                 }
247
248                 delegate int ReadDelegate (byte [] buffer, int offset, int size);
249         }
250 }
251
252