[sgen] Don't assert in GC.GetTotalMemory.
[mono.git] / mcs / class / System / System.Net.Sockets / SocketAsyncEventArgs.cs
1 // System.Net.Sockets.SocketAsyncEventArgs.cs
2 //
3 // Authors:
4 //      Marek Habersack (mhabersack@novell.com)
5 //      Gonzalo Paniagua Javier (gonzalo@xamarin.com)
6 //
7 // Copyright (c) 2008,2010 Novell, Inc. (http://www.novell.com)
8 // Copyright (c) 2011 Xamarin, Inc. (http://xamarin.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System;
32 using System.Collections.Generic;
33 using System.Reflection;
34 using System.Security;
35 using System.Threading;
36
37 namespace System.Net.Sockets
38 {
39         public class SocketAsyncEventArgs : EventArgs, IDisposable
40         {
41                 bool disposed;
42                 int in_progress;
43                 internal Socket.Worker Worker;
44                 EndPoint remote_ep;
45                 public Exception ConnectByNameError { get; internal set; }
46
47                 public event EventHandler<SocketAsyncEventArgs> Completed;
48
49                 IList <ArraySegment <byte>> _bufferList;
50                 
51                 public Socket AcceptSocket { get; set; }
52                 public byte[] Buffer { get; private set; }
53
54                 public IList<ArraySegment<byte>> BufferList {
55                         get { return _bufferList; }
56                         set {
57                                 if (Buffer != null && value != null)
58                                         throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
59                                 _bufferList = value;
60                         }
61                 }
62
63                 public int BytesTransferred { get; internal set; }
64                 public int Count { get; internal set; }
65                 public bool DisconnectReuseSocket { get; set; }
66                 public SocketAsyncOperation LastOperation { get; private set; }
67                 public int Offset { get; private set; }
68                 public EndPoint RemoteEndPoint {
69                         get { return remote_ep; }
70                         set { remote_ep = value; }
71                 }
72 #if !NET_2_1
73                 public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
74                 public SendPacketsElement[] SendPacketsElements { get; set; }
75                 public TransmitFileOptions SendPacketsFlags { get; set; }
76 #endif
77                 [MonoTODO ("unused property")]
78                 public int SendPacketsSendSize { get; set; }
79                 public SocketError SocketError { get; set; }
80                 public SocketFlags SocketFlags { get; set; }
81                 public object UserToken { get; set; }
82                 internal Socket curSocket;
83                 public Socket ConnectSocket {
84                         get {
85                                 switch (SocketError) {
86                                 case SocketError.AccessDenied:
87                                         return null;
88                                 default:
89                                         return curSocket;
90                                 }
91                         }
92                 }
93
94                 internal bool PolicyRestricted { get; private set; }
95
96                 internal SocketAsyncEventArgs (bool policy) : 
97                         this ()
98                 {
99                         PolicyRestricted = policy;
100                 }
101                 
102                 public SocketAsyncEventArgs ()
103                 {
104                         Worker = new Socket.Worker (this);
105                         AcceptSocket = null;
106                         Buffer = null;
107                         BufferList = null;
108                         BytesTransferred = 0;
109                         Count = 0;
110                         DisconnectReuseSocket = false;
111                         LastOperation = SocketAsyncOperation.None;
112                         Offset = 0;
113                         RemoteEndPoint = null;
114 #if !NET_2_1
115                         SendPacketsElements = null;
116                         SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
117 #endif
118                         SendPacketsSendSize = -1;
119                         SocketError = SocketError.Success;
120                         SocketFlags = SocketFlags.None;
121                         UserToken = null;
122                 }
123
124                 ~SocketAsyncEventArgs ()
125                 {
126                         Dispose (false);
127                 }
128
129                 void Dispose (bool disposing)
130                 {
131                         disposed = true;
132
133                         if (disposing) {
134                                 if (disposed || Interlocked.CompareExchange (ref in_progress, 0, 0) != 0)
135                                         return;
136                                 if (Worker != null) {
137                                         Worker.Dispose ();
138                                         Worker = null;
139                                 }
140                         }
141                         AcceptSocket = null;
142                         Buffer = null;
143                         BufferList = null;
144                         RemoteEndPoint = null;
145                         UserToken = null;
146 #if !NET_2_1
147                         SendPacketsElements = null;
148 #endif
149                 }               
150
151                 public void Dispose ()
152                 {
153                         Dispose (true);
154                         GC.SuppressFinalize (this);
155                 }
156
157                 internal void SetLastOperation (SocketAsyncOperation op)
158                 {
159                         if (disposed)
160                                 throw new ObjectDisposedException ("System.Net.Sockets.SocketAsyncEventArgs");
161                         if (Interlocked.Exchange (ref in_progress, 1) != 0)
162                                 throw new InvalidOperationException ("Operation already in progress");
163                         LastOperation = op;
164                 }
165
166                 protected virtual void OnCompleted (SocketAsyncEventArgs e)
167                 {
168                         if (e == null)
169                                 return;
170                         
171                         EventHandler<SocketAsyncEventArgs> handler = e.Completed;
172                         if (handler != null)
173                                 handler (e.curSocket, e);
174                 }
175
176                 public void SetBuffer (int offset, int count)
177                 {
178                         SetBufferInternal (Buffer, offset, count);
179                 }
180
181                 public void SetBuffer (byte[] buffer, int offset, int count)
182                 {
183                         SetBufferInternal (buffer, offset, count);
184                 }
185
186                 void SetBufferInternal (byte[] buffer, int offset, int count)
187                 {
188                         if (buffer != null) {
189                                 if (BufferList != null)
190                                         throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
191                                 
192                                 int buflen = buffer.Length;
193                                 if (offset < 0 || (offset != 0 && offset >= buflen))
194                                         throw new ArgumentOutOfRangeException ("offset");
195
196                                 if (count < 0 || count > buflen - offset)
197                                         throw new ArgumentOutOfRangeException ("count");
198
199                                 Count = count;
200                                 Offset = offset;
201                         }
202                         Buffer = buffer;
203                 }
204
205 #region Internals
206                 internal static AsyncCallback Dispatcher = new AsyncCallback (DispatcherCB);
207
208                 static void DispatcherCB (IAsyncResult ares)
209                 {
210                         SocketAsyncEventArgs args = (SocketAsyncEventArgs) ares.AsyncState;
211                         if (Interlocked.Exchange (ref args.in_progress, 0) != 1)
212                                 throw new InvalidOperationException ("No operation in progress");
213                         SocketAsyncOperation op = args.LastOperation;
214                         // Notes;
215                         //      -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
216                         //      -SendPackets and ReceiveMessageFrom are not implemented yet
217                         if (op == SocketAsyncOperation.Receive)
218                                 args.ReceiveCallback (ares);
219                         else if (op == SocketAsyncOperation.Send)
220                                 args.SendCallback (ares);
221                         else if (op == SocketAsyncOperation.ReceiveFrom)
222                                 args.ReceiveFromCallback (ares);
223                         else if (op == SocketAsyncOperation.SendTo)
224                                 args.SendToCallback (ares);
225                         else if (op == SocketAsyncOperation.Accept)
226                                 args.AcceptCallback (ares);
227                         else if (op == SocketAsyncOperation.Disconnect)
228                                 args.DisconnectCallback (ares);
229                         else if (op == SocketAsyncOperation.Connect)
230                                 args.ConnectCallback (ares);
231                         /*
232                         else if (op == Socket.SocketOperation.ReceiveMessageFrom)
233                         else if (op == Socket.SocketOperation.SendPackets)
234                         */
235                         else
236                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
237
238                 }
239
240                 internal void ReceiveCallback (IAsyncResult ares)
241                 {
242                         try {
243                                 BytesTransferred = curSocket.EndReceive (ares);
244                         } catch (SocketException se){
245                                 SocketError = se.SocketErrorCode;
246                         } catch (ObjectDisposedException) {
247                                 SocketError = SocketError.OperationAborted;
248                         } finally {
249                                 OnCompleted (this);
250                         }
251                 }
252
253                 void ConnectCallback (IAsyncResult ares)
254                 {
255                         try {
256                                 curSocket.EndConnect (ares);
257                         } catch (SocketException se) {
258                                 SocketError = se.SocketErrorCode;
259                         } catch (ObjectDisposedException) {
260                                 SocketError = SocketError.OperationAborted;
261                         } finally {
262                                 OnCompleted (this);
263                         }
264                 }
265
266                 internal void SendCallback (IAsyncResult ares)
267                 {
268                         try {
269                                 BytesTransferred = curSocket.EndSend (ares);
270                         } catch (SocketException se){
271                                 SocketError = se.SocketErrorCode;
272                         } catch (ObjectDisposedException) {
273                                 SocketError = SocketError.OperationAborted;
274                         } finally {
275                                 OnCompleted (this);
276                         }
277                 }
278
279                 internal void AcceptCallback (IAsyncResult ares)
280                 {
281                         try {
282                                 AcceptSocket = curSocket.EndAccept (ares);
283                         } catch (SocketException ex) {
284                                 SocketError = ex.SocketErrorCode;
285                         } catch (ObjectDisposedException) {
286                                 SocketError = SocketError.OperationAborted;
287                         } finally {
288                                 if (AcceptSocket == null)
289                                         AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, null);
290                                 OnCompleted (this);
291                         }
292                 }
293
294                 internal void DisconnectCallback (IAsyncResult ares)
295                 {
296                         try {
297                                 curSocket.EndDisconnect (ares);
298                         } catch (SocketException ex) {
299                                 SocketError = ex.SocketErrorCode;
300                         } catch (ObjectDisposedException) {
301                                 SocketError = SocketError.OperationAborted;
302                         } finally {
303                                 OnCompleted (this);
304                         }
305                 }
306
307                 internal void ReceiveFromCallback (IAsyncResult ares)
308                 {
309                         try {
310                                 BytesTransferred = curSocket.EndReceiveFrom (ares, ref remote_ep);
311                         } catch (SocketException ex) {
312                                 SocketError = ex.SocketErrorCode;
313                         } catch (ObjectDisposedException) {
314                                 SocketError = SocketError.OperationAborted;
315                         } finally {
316                                 OnCompleted (this);
317                         }
318                 }
319
320                 internal void SendToCallback (IAsyncResult ares)
321                 {
322                         try {
323                                 BytesTransferred = curSocket.EndSendTo (ares);
324                         } catch (SocketException ex) {
325                                 SocketError = ex.SocketErrorCode;
326                         } catch (ObjectDisposedException) {
327                                 SocketError = SocketError.OperationAborted;
328                         } finally {
329                                 OnCompleted (this);
330                         }
331                 }
332 #endregion
333         }
334 }