1 // System.Net.Sockets.SocketAsyncEventArgs.cs
4 // Marek Habersack (mhabersack@novell.com)
6 // Copyright (c) 2008 Novell, Inc. (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections.Generic;
32 using System.Reflection;
33 using System.Security;
34 using System.Threading;
36 namespace System.Net.Sockets
38 public class SocketAsyncEventArgs : EventArgs, IDisposable
40 #if NET_2_1 && !MONOTOUCH
41 static MethodInfo check_socket_policy;
43 static SocketAsyncEventArgs ()
45 Type type = Type.GetType ("System.Windows.Browser.Net.CrossDomainPolicyManager, System.Windows.Browser, Version=2.0.5.0, Culture=Neutral, PublicKeyToken=7cec85d7bea7798e");
46 check_socket_policy = type.GetMethod ("CheckEndPoint");
49 static internal bool CheckEndPoint (EndPoint endpoint)
51 if (check_socket_policy == null)
52 throw new SecurityException ();
53 return ((bool) check_socket_policy.Invoke (null, new object [1] { endpoint }));
56 #if (NET_2_1 || NET_4_0) && !MONOTOUCH
57 public Exception ConnectByNameError { get; internal set; }
60 public event EventHandler<SocketAsyncEventArgs> Completed;
62 IList <ArraySegment <byte>> _bufferList;
64 public Socket AcceptSocket { get; set; }
65 public byte[] Buffer { get; private set; }
67 [MonoTODO ("not supported in all cases")]
68 public IList<ArraySegment<byte>> BufferList {
69 get { return _bufferList; }
71 if (Buffer != null && value != null)
72 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
77 public int BytesTransferred { get; private set; }
78 public int Count { get; private set; }
79 public bool DisconnectReuseSocket { get; set; }
80 public SocketAsyncOperation LastOperation { get; private set; }
81 public int Offset { get; private set; }
82 public EndPoint RemoteEndPoint { get; set; }
84 public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
85 public SendPacketsElement[] SendPacketsElements { get; set; }
86 public TransmitFileOptions SendPacketsFlags { get; set; }
88 [MonoTODO ("unused property")]
89 public int SendPacketsSendSize { get; set; }
90 public SocketError SocketError { get; set; }
91 public SocketFlags SocketFlags { get; set; }
92 public object UserToken { get; set; }
96 public Socket ConnectSocket {
98 switch (SocketError) {
99 case SocketError.AccessDenied:
107 internal bool PolicyRestricted { get; private set; }
109 internal SocketAsyncEventArgs (bool policy) :
112 PolicyRestricted = policy;
116 public SocketAsyncEventArgs ()
121 BytesTransferred = 0;
123 DisconnectReuseSocket = false;
124 LastOperation = SocketAsyncOperation.None;
126 RemoteEndPoint = null;
128 SendPacketsElements = null;
129 SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
131 SendPacketsSendSize = -1;
132 SocketError = SocketError.Success;
133 SocketFlags = SocketFlags.None;
137 ~SocketAsyncEventArgs ()
142 void Dispose (bool disposing)
144 Socket acceptSocket = AcceptSocket;
145 if (acceptSocket != null)
146 acceptSocket.Close ();
149 GC.SuppressFinalize (this);
152 public void Dispose ()
157 protected virtual void OnCompleted (SocketAsyncEventArgs e)
162 EventHandler<SocketAsyncEventArgs> handler = e.Completed;
164 handler (e.curSocket, e);
167 public void SetBuffer (int offset, int count)
169 SetBufferInternal (Buffer, offset, count);
172 public void SetBuffer (byte[] buffer, int offset, int count)
174 SetBufferInternal (buffer, offset, count);
177 void SetBufferInternal (byte[] buffer, int offset, int count)
179 if (buffer != null) {
180 if (BufferList != null)
181 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
183 int buflen = buffer.Length;
184 if (offset < 0 || (offset != 0 && offset >= buflen))
185 throw new ArgumentOutOfRangeException ("offset");
187 if (count < 0 || count > buflen - offset)
188 throw new ArgumentOutOfRangeException ("count");
197 void ReceiveCallback ()
199 SocketError = SocketError.Success;
200 LastOperation = SocketAsyncOperation.Receive;
201 SocketError error = SocketError.Success;
203 if (!curSocket.Connected) {
204 SocketError = SocketError.NotConnected;
209 // FIXME: this does not support using BufferList
210 BytesTransferred = curSocket.Receive_nochecks (Buffer, Offset, Count, SocketFlags, out error);
217 void ConnectCallback ()
219 LastOperation = SocketAsyncOperation.Connect;
220 SocketError error = SocketError.AccessDenied;
222 #if (NET_2_1 || NET_4_0) && !MONOTOUCH
223 // Connect to the first address that match the host name, like:
224 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
225 // while skipping entries that do not match the address family
226 DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
228 IPAddress[] addresses = Dns.GetHostAddresses (dep.Host);
229 foreach (IPAddress addr in addresses) {
231 if (curSocket.AddressFamily == addr.AddressFamily) {
232 error = TryConnect (new IPEndPoint (addr, dep.Port));
233 if (error == SocketError.Success) {
234 ConnectByNameError = null;
239 catch (SocketException se) {
240 ConnectByNameError = se;
241 error = SocketError.AccessDenied;
245 ConnectByNameError = null;
246 error = TryConnect (RemoteEndPoint);
249 error = TryConnect (RemoteEndPoint);
257 SocketError TryConnect (EndPoint endpoint)
259 curSocket.Connected = false;
260 SocketError error = SocketError.Success;
261 #if NET_2_1 && !MONOTOUCH
262 // if we're not downloading a socket policy then check the policy
263 if (!PolicyRestricted) {
264 error = SocketError.AccessDenied;
265 if (!CheckEndPoint (endpoint)) {
268 error = SocketError.Success;
273 if (!curSocket.Blocking) {
275 curSocket.Poll (-1, SelectMode.SelectWrite, out success);
276 error = (SocketError)success;
278 curSocket.Connected = true;
284 curSocket.seed_endpoint = endpoint;
285 curSocket.Connect (endpoint);
286 curSocket.Connected = true;
288 } catch (SocketException se){
289 error = se.SocketErrorCode;
296 SocketError = SocketError.Success;
297 LastOperation = SocketAsyncOperation.Send;
298 SocketError error = SocketError.Success;
300 if (!curSocket.Connected) {
301 SocketError = SocketError.NotConnected;
306 if (Buffer != null) {
307 BytesTransferred = curSocket.Send_nochecks (Buffer, Offset, Count, SocketFlags.None, out error);
308 } else if (BufferList != null) {
309 BytesTransferred = 0;
310 foreach (ArraySegment<byte> asb in BufferList) {
311 BytesTransferred += curSocket.Send_nochecks (asb.Array, asb.Offset, asb.Count,
312 SocketFlags.None, out error);
313 if (error != SocketError.Success)
323 void AcceptCallback ()
325 SocketError = SocketError.Success;
326 LastOperation = SocketAsyncOperation.Accept;
328 curSocket.Accept (AcceptSocket);
329 } catch (SocketException ex) {
330 SocketError = ex.SocketErrorCode;
337 void DisconnectCallback ()
339 SocketError = SocketError.Success;
340 LastOperation = SocketAsyncOperation.Disconnect;
343 curSocket.Disconnect (DisconnectReuseSocket);
344 } catch (SocketException ex) {
345 SocketError = ex.SocketErrorCode;
352 void ReceiveFromCallback ()
354 SocketError = SocketError.Success;
355 LastOperation = SocketAsyncOperation.ReceiveFrom;
358 EndPoint ep = RemoteEndPoint;
359 if (Buffer != null) {
360 BytesTransferred = curSocket.ReceiveFrom_nochecks (Buffer, Offset, Count, SocketFlags, ref ep);
361 } else if (BufferList != null) {
362 throw new NotImplementedException ();
364 } catch (SocketException ex) {
365 SocketError = ex.SocketErrorCode;
372 void SendToCallback ()
374 SocketError = SocketError.Success;
375 LastOperation = SocketAsyncOperation.SendTo;
381 while (total < count)
382 total += curSocket.SendTo_nochecks (Buffer, Offset, count, SocketFlags, RemoteEndPoint);
383 BytesTransferred = total;
384 } catch (SocketException ex) {
385 SocketError = ex.SocketErrorCode;
392 internal void DoOperation (SocketAsyncOperation operation, Socket socket)
394 ThreadStart callback;
399 case SocketAsyncOperation.Accept:
400 callback = new ThreadStart (AcceptCallback);
403 case SocketAsyncOperation.Disconnect:
404 callback = new ThreadStart (DisconnectCallback);
407 case SocketAsyncOperation.ReceiveFrom:
408 callback = new ThreadStart (ReceiveFromCallback);
411 case SocketAsyncOperation.SendTo:
412 callback = new ThreadStart (SendToCallback);
415 case SocketAsyncOperation.Receive:
416 callback = new ThreadStart (ReceiveCallback);
419 case SocketAsyncOperation.Connect:
420 callback = new ThreadStart (ConnectCallback);
423 case SocketAsyncOperation.Send:
424 callback = new ThreadStart (SendCallback);
428 throw new NotSupportedException ();
431 Thread t = new Thread (callback);
432 t.IsBackground = true;