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