Remove excessive shortcut key matching in ToolStrip
[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 #if NET_4_0
46                 public Exception ConnectByNameError { get; internal set; }
47 #endif
48
49                 public event EventHandler<SocketAsyncEventArgs> Completed;
50
51                 IList <ArraySegment <byte>> _bufferList;
52                 
53                 public Socket AcceptSocket { get; set; }
54                 public byte[] Buffer { get; private set; }
55
56                 public IList<ArraySegment<byte>> BufferList {
57                         get { return _bufferList; }
58                         set {
59                                 if (Buffer != null && value != null)
60                                         throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
61                                 _bufferList = value;
62                         }
63                 }
64
65                 public int BytesTransferred { get; internal set; }
66                 public int Count { get; internal set; }
67                 public bool DisconnectReuseSocket { get; set; }
68                 public SocketAsyncOperation LastOperation { get; private set; }
69                 public int Offset { get; private set; }
70                 public EndPoint RemoteEndPoint {
71                         get { return remote_ep; }
72                         set { remote_ep = value; }
73                 }
74 #if !NET_2_1
75                 public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
76                 public SendPacketsElement[] SendPacketsElements { get; set; }
77                 public TransmitFileOptions SendPacketsFlags { get; set; }
78 #endif
79                 [MonoTODO ("unused property")]
80                 public int SendPacketsSendSize { get; set; }
81                 public SocketError SocketError { get; set; }
82                 public SocketFlags SocketFlags { get; set; }
83                 public object UserToken { get; set; }
84                 internal Socket curSocket;
85 #if (NET_2_1 || NET_4_0)
86                 public Socket ConnectSocket {
87                         get {
88                                 switch (SocketError) {
89                                 case SocketError.AccessDenied:
90                                         return null;
91                                 default:
92                                         return curSocket;
93                                 }
94                         }
95                 }
96
97                 internal bool PolicyRestricted { get; private set; }
98
99                 internal SocketAsyncEventArgs (bool policy) : 
100                         this ()
101                 {
102                         PolicyRestricted = policy;
103                 }
104 #endif
105                 
106                 public SocketAsyncEventArgs ()
107                 {
108                         Worker = new Socket.Worker (this);
109                         AcceptSocket = null;
110                         Buffer = null;
111                         BufferList = null;
112                         BytesTransferred = 0;
113                         Count = 0;
114                         DisconnectReuseSocket = false;
115                         LastOperation = SocketAsyncOperation.None;
116                         Offset = 0;
117                         RemoteEndPoint = null;
118 #if !NET_2_1
119                         SendPacketsElements = null;
120                         SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
121 #endif
122                         SendPacketsSendSize = -1;
123                         SocketError = SocketError.Success;
124                         SocketFlags = SocketFlags.None;
125                         UserToken = null;
126                 }
127
128                 ~SocketAsyncEventArgs ()
129                 {
130                         Dispose (false);
131                 }
132
133                 void Dispose (bool disposing)
134                 {
135                         disposed = true;
136
137                         if (disposing) {
138                                 if (disposed || Interlocked.CompareExchange (ref in_progress, 0, 0) != 0)
139                                         return;
140                                 if (Worker != null) {
141                                         Worker.Dispose ();
142                                         Worker = null;
143                                 }
144                         }
145                         AcceptSocket = null;
146                         Buffer = null;
147                         BufferList = null;
148                         RemoteEndPoint = null;
149                         UserToken = null;
150 #if !NET_2_1
151                         SendPacketsElements = null;
152 #endif
153                 }               
154
155                 public void Dispose ()
156                 {
157                         Dispose (true);
158                         GC.SuppressFinalize (this);
159                 }
160
161                 internal void SetLastOperation (SocketAsyncOperation op)
162                 {
163                         if (disposed)
164                                 throw new ObjectDisposedException ("System.Net.Sockets.SocketAsyncEventArgs");
165                         if (Interlocked.Exchange (ref in_progress, 1) != 0)
166                                 throw new InvalidOperationException ("Operation already in progress");
167                         LastOperation = op;
168                 }
169
170                 protected virtual void OnCompleted (SocketAsyncEventArgs e)
171                 {
172                         if (e == null)
173                                 return;
174                         
175                         EventHandler<SocketAsyncEventArgs> handler = e.Completed;
176                         if (handler != null)
177                                 handler (e.curSocket, e);
178                 }
179
180                 public void SetBuffer (int offset, int count)
181                 {
182                         SetBufferInternal (Buffer, offset, count);
183                 }
184
185                 public void SetBuffer (byte[] buffer, int offset, int count)
186                 {
187                         SetBufferInternal (buffer, offset, count);
188                 }
189
190                 void SetBufferInternal (byte[] buffer, int offset, int count)
191                 {
192                         if (buffer != null) {
193                                 if (BufferList != null)
194                                         throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
195                                 
196                                 int buflen = buffer.Length;
197                                 if (offset < 0 || (offset != 0 && offset >= buflen))
198                                         throw new ArgumentOutOfRangeException ("offset");
199
200                                 if (count < 0 || count > buflen - offset)
201                                         throw new ArgumentOutOfRangeException ("count");
202
203                                 Count = count;
204                                 Offset = offset;
205                         }
206                         Buffer = buffer;
207                 }
208
209 #region Internals
210                 internal static AsyncCallback Dispatcher = new AsyncCallback (DispatcherCB);
211
212                 static void DispatcherCB (IAsyncResult ares)
213                 {
214                         SocketAsyncEventArgs args = (SocketAsyncEventArgs) ares.AsyncState;
215                         if (Interlocked.Exchange (ref args.in_progress, 0) != 1)
216                                 throw new InvalidOperationException ("No operation in progress");
217                         SocketAsyncOperation op = args.LastOperation;
218                         // Notes;
219                         //      -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
220                         //      -SendPackets and ReceiveMessageFrom are not implemented yet
221                         if (op == SocketAsyncOperation.Receive)
222                                 args.ReceiveCallback (ares);
223                         else if (op == SocketAsyncOperation.Send)
224                                 args.SendCallback (ares);
225                         else if (op == SocketAsyncOperation.ReceiveFrom)
226                                 args.ReceiveFromCallback (ares);
227                         else if (op == SocketAsyncOperation.SendTo)
228                                 args.SendToCallback (ares);
229                         else if (op == SocketAsyncOperation.Accept)
230                                 args.AcceptCallback (ares);
231                         else if (op == SocketAsyncOperation.Disconnect)
232                                 args.DisconnectCallback (ares);
233                         else if (op == SocketAsyncOperation.Connect)
234                                 args.ConnectCallback (ares);
235                         /*
236                         else if (op == Socket.SocketOperation.ReceiveMessageFrom)
237                         else if (op == Socket.SocketOperation.SendPackets)
238                         */
239                         else
240                                 throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
241
242                 }
243
244                 internal void ReceiveCallback (IAsyncResult ares)
245                 {
246                         try {
247                                 BytesTransferred = curSocket.EndReceive (ares);
248                         } catch (SocketException se){
249                                 SocketError = se.SocketErrorCode;
250                         } catch (ObjectDisposedException) {
251                                 SocketError = SocketError.OperationAborted;
252                         } finally {
253                                 OnCompleted (this);
254                         }
255                 }
256
257                 void ConnectCallback (IAsyncResult ares)
258                 {
259                         try {
260                                 curSocket.EndConnect (ares);
261                         } catch (SocketException se) {
262                                 SocketError = se.SocketErrorCode;
263                         } finally {
264                                 OnCompleted (this);
265                         }
266                 }
267
268                 internal void SendCallback (IAsyncResult ares)
269                 {
270                         try {
271                                 BytesTransferred = curSocket.EndSend (ares);
272                         } catch (SocketException se){
273                                 SocketError = se.SocketErrorCode;
274                         } catch (ObjectDisposedException) {
275                                 SocketError = SocketError.OperationAborted;
276                         } finally {
277                                 OnCompleted (this);
278                         }
279                 }
280
281                 internal void AcceptCallback (IAsyncResult ares)
282                 {
283                         try {
284                                 AcceptSocket = curSocket.EndAccept (ares);
285                         } catch (SocketException ex) {
286                                 SocketError = ex.SocketErrorCode;
287                         } catch (ObjectDisposedException) {
288                                 SocketError = SocketError.OperationAborted;
289                         } finally {
290                                 if (AcceptSocket == null)
291                                         AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, (IntPtr)(-1));
292                                 OnCompleted (this);
293                         }
294                 }
295
296                 internal void DisconnectCallback (IAsyncResult ares)
297                 {
298                         try {
299                                 curSocket.EndDisconnect (ares);
300                         } catch (SocketException ex) {
301                                 SocketError = ex.SocketErrorCode;
302                         } catch (ObjectDisposedException) {
303                                 SocketError = SocketError.OperationAborted;
304                         } finally {
305                                 OnCompleted (this);
306                         }
307                 }
308
309                 internal void ReceiveFromCallback (IAsyncResult ares)
310                 {
311                         try {
312                                 BytesTransferred = curSocket.EndReceiveFrom (ares, ref remote_ep);
313                         } catch (SocketException ex) {
314                                 SocketError = ex.SocketErrorCode;
315                         } catch (ObjectDisposedException) {
316                                 SocketError = SocketError.OperationAborted;
317                         } finally {
318                                 OnCompleted (this);
319                         }
320                 }
321
322                 internal void SendToCallback (IAsyncResult ares)
323                 {
324                         try {
325                                 BytesTransferred = curSocket.EndSendTo (ares);
326                         } catch (SocketException ex) {
327                                 SocketError = ex.SocketErrorCode;
328                         } catch (ObjectDisposedException) {
329                                 SocketError = SocketError.OperationAborted;
330                         } finally {
331                                 OnCompleted (this);
332                         }
333                 }
334 #endregion
335         }
336 }