Merge pull request #1685 from esdrubal/touint64
[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 SocketAsyncWorker 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 SocketAsyncWorker (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
212                         if (Interlocked.Exchange (ref args.in_progress, 0) != 1)
213                                 throw new InvalidOperationException ("No operation in progress");
214
215                         /* Notes;
216                          *  -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
217                          *  -SendPackets and ReceiveMessageFrom are not implemented yet */
218                         switch (args.LastOperation) {
219                         case SocketAsyncOperation.Receive:
220                                 args.ReceiveCallback (ares);
221                                 break;
222                         case SocketAsyncOperation.Send:
223                                 args.SendCallback (ares);
224                                 break;
225                         case SocketAsyncOperation.ReceiveFrom:
226                                 args.ReceiveFromCallback (ares);
227                                 break;
228                         case SocketAsyncOperation.SendTo:
229                                 args.SendToCallback (ares);
230                                 break;
231                         case SocketAsyncOperation.Accept:
232                                 args.AcceptCallback (ares);
233                                 break;
234                         case SocketAsyncOperation.Disconnect:
235                                 args.DisconnectCallback (ares);
236                                 break;
237                         case SocketAsyncOperation.Connect:
238                                 args.ConnectCallback (ares);
239                                 break;
240                         /*
241                         case SocketOperation.ReceiveMessageFrom:
242                         case SocketOperation.SendPackets:
243                         */
244                         default:
245                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", args.LastOperation));
246                         }
247                 }
248
249                 internal void ReceiveCallback (IAsyncResult ares)
250                 {
251                         try {
252                                 BytesTransferred = curSocket.EndReceive (ares);
253                         } catch (SocketException se){
254                                 SocketError = se.SocketErrorCode;
255                         } catch (ObjectDisposedException) {
256                                 SocketError = SocketError.OperationAborted;
257                         } finally {
258                                 OnCompleted (this);
259                         }
260                 }
261
262                 void ConnectCallback (IAsyncResult ares)
263                 {
264                         try {
265                                 curSocket.EndConnect (ares);
266                         } catch (SocketException se) {
267                                 SocketError = se.SocketErrorCode;
268                         } catch (ObjectDisposedException) {
269                                 SocketError = SocketError.OperationAborted;
270                         } finally {
271                                 OnCompleted (this);
272                         }
273                 }
274
275                 internal void SendCallback (IAsyncResult ares)
276                 {
277                         try {
278                                 BytesTransferred = curSocket.EndSend (ares);
279                         } catch (SocketException se){
280                                 SocketError = se.SocketErrorCode;
281                         } catch (ObjectDisposedException) {
282                                 SocketError = SocketError.OperationAborted;
283                         } finally {
284                                 OnCompleted (this);
285                         }
286                 }
287
288                 internal void AcceptCallback (IAsyncResult ares)
289                 {
290                         try {
291                                 AcceptSocket = curSocket.EndAccept (ares);
292                         } catch (SocketException ex) {
293                                 SocketError = ex.SocketErrorCode;
294                         } catch (ObjectDisposedException) {
295                                 SocketError = SocketError.OperationAborted;
296                         } finally {
297                                 if (AcceptSocket == null)
298                                         AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, null);
299                                 OnCompleted (this);
300                         }
301                 }
302
303                 internal void DisconnectCallback (IAsyncResult ares)
304                 {
305                         try {
306                                 curSocket.EndDisconnect (ares);
307                         } catch (SocketException ex) {
308                                 SocketError = ex.SocketErrorCode;
309                         } catch (ObjectDisposedException) {
310                                 SocketError = SocketError.OperationAborted;
311                         } finally {
312                                 OnCompleted (this);
313                         }
314                 }
315
316                 internal void ReceiveFromCallback (IAsyncResult ares)
317                 {
318                         try {
319                                 BytesTransferred = curSocket.EndReceiveFrom (ares, ref remote_ep);
320                         } catch (SocketException ex) {
321                                 SocketError = ex.SocketErrorCode;
322                         } catch (ObjectDisposedException) {
323                                 SocketError = SocketError.OperationAborted;
324                         } finally {
325                                 OnCompleted (this);
326                         }
327                 }
328
329                 internal void SendToCallback (IAsyncResult ares)
330                 {
331                         try {
332                                 BytesTransferred = curSocket.EndSendTo (ares);
333                         } catch (SocketException ex) {
334                                 SocketError = ex.SocketErrorCode;
335                         } catch (ObjectDisposedException) {
336                                 SocketError = SocketError.OperationAborted;
337                         } finally {
338                                 OnCompleted (this);
339                         }
340                 }
341 #endregion
342         }
343 }