1 // System.Net.Sockets.SocketAsyncEventArgs.cs
4 // Marek Habersack (mhabersack@novell.com)
5 // Gonzalo Paniagua Javier (gonzalo@novell.com)
7 // Copyright (c) 2008,2010 Novell, Inc. (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
31 using System.Collections.Generic;
32 using System.Reflection;
33 using System.Security;
34 using System.Threading;
35 #if MOONLIGHT && !INSIDE_SYSTEM
36 using System.Net.Policy;
39 namespace System.Net.Sockets
41 public class SocketAsyncEventArgs : EventArgs, IDisposable
43 internal Socket.Worker Worker;
45 #if MOONLIGHT || NET_4_0
46 public Exception ConnectByNameError { get; internal set; }
49 public event EventHandler<SocketAsyncEventArgs> Completed;
51 IList <ArraySegment <byte>> _bufferList;
53 public Socket AcceptSocket { get; set; }
54 public byte[] Buffer { get; private set; }
56 public IList<ArraySegment<byte>> BufferList {
57 get { return _bufferList; }
59 if (Buffer != null && value != null)
60 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
65 public int BytesTransferred { get; private set; }
66 public int Count { get; private 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; }
75 public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
76 public SendPacketsElement[] SendPacketsElements { get; set; }
77 public TransmitFileOptions SendPacketsFlags { get; set; }
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; }
85 #if MOONLIGHT && !INSIDE_SYSTEM
86 private SocketClientAccessPolicyProtocol policy_protocol;
88 public SocketClientAccessPolicyProtocol SocketClientAccessPolicyProtocol {
89 get { return policy_protocol; }
91 if ((value != SocketClientAccessPolicyProtocol.Tcp) && (value != SocketClientAccessPolicyProtocol.Http))
92 throw new ArgumentException ("Invalid value");
93 policy_protocol = value;
98 internal Socket curSocket;
100 public Socket ConnectSocket {
102 switch (SocketError) {
103 case SocketError.AccessDenied:
111 internal bool PolicyRestricted { get; private set; }
113 internal SocketAsyncEventArgs (bool policy) :
116 PolicyRestricted = policy;
120 public SocketAsyncEventArgs ()
122 Worker = new Socket.Worker (this);
126 BytesTransferred = 0;
128 DisconnectReuseSocket = false;
129 LastOperation = SocketAsyncOperation.None;
131 RemoteEndPoint = null;
133 SendPacketsElements = null;
134 SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
136 SendPacketsSendSize = -1;
137 SocketError = SocketError.Success;
138 SocketFlags = SocketFlags.None;
141 #if MOONLIGHT && !INSIDE_SYSTEM
142 policy_protocol = SocketClientAccessPolicyProtocol.Tcp;
146 ~SocketAsyncEventArgs ()
151 void Dispose (bool disposing)
154 if (Worker != null) {
162 RemoteEndPoint = null;
165 SendPacketsElements = null;
169 public void Dispose ()
172 GC.SuppressFinalize (this);
175 internal void SetLastOperation (SocketAsyncOperation op)
180 protected virtual void OnCompleted (SocketAsyncEventArgs e)
185 EventHandler<SocketAsyncEventArgs> handler = e.Completed;
187 handler (e.curSocket, e);
190 public void SetBuffer (int offset, int count)
192 SetBufferInternal (Buffer, offset, count);
195 public void SetBuffer (byte[] buffer, int offset, int count)
197 SetBufferInternal (buffer, offset, count);
200 void SetBufferInternal (byte[] buffer, int offset, int count)
202 if (buffer != null) {
203 if (BufferList != null)
204 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
206 int buflen = buffer.Length;
207 if (offset < 0 || (offset != 0 && offset >= buflen))
208 throw new ArgumentOutOfRangeException ("offset");
210 if (count < 0 || count > buflen - offset)
211 throw new ArgumentOutOfRangeException ("count");
220 internal void ReceiveCallback (IAsyncResult ares)
223 BytesTransferred = curSocket.EndReceive (ares);
224 } catch (SocketException se){
225 SocketError = se.SocketErrorCode;
226 } catch (ObjectDisposedException) {
227 SocketError = SocketError.OperationAborted;
233 void ConnectCallback ()
235 SocketError error = SocketError.AccessDenied;
237 #if MOONLIGHT || NET_4_0
238 // Connect to the first address that match the host name, like:
239 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
240 // while skipping entries that do not match the address family
241 DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
243 IPAddress[] addresses = Dns.GetHostAddresses (dep.Host);
245 #if MOONLIGHT && !INSIDE_SYSTEM
246 if (!PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
247 List<IPAddress> valid = new List<IPAddress> ();
248 foreach (IPAddress a in addresses) {
249 // if we're not downloading a socket policy then check the policy
250 // and if we're not running with elevated permissions (SL4 OoB option)
251 endpoint = new IPEndPoint (a, dep.Port);
252 if (!CrossDomainPolicyManager.CheckEndPoint (endpoint, policy_protocol))
256 addresses = valid.ToArray ();
259 foreach (IPAddress addr in addresses) {
261 if (curSocket.AddressFamily == addr.AddressFamily) {
262 endpoint = new IPEndPoint (addr, dep.Port);
263 error = TryConnect (endpoint);
264 if (error == SocketError.Success) {
265 ConnectByNameError = null;
269 } catch (SocketException se) {
270 ConnectByNameError = se;
271 error = SocketError.AccessDenied;
275 ConnectByNameError = null;
276 #if MOONLIGHT && !INSIDE_SYSTEM
277 if (!PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
278 if (CrossDomainPolicyManager.CheckEndPoint (RemoteEndPoint, policy_protocol))
279 error = TryConnect (RemoteEndPoint);
282 error = TryConnect (RemoteEndPoint);
285 error = TryConnect (RemoteEndPoint);
293 SocketError TryConnect (EndPoint endpoint)
296 curSocket.Connect (endpoint);
297 return (curSocket.Connected ? 0 : SocketError);
298 } catch (SocketException se){
299 return se.SocketErrorCode;
300 } catch (ObjectDisposedException) {
301 return SocketError.OperationAborted;
305 internal void SendCallback (IAsyncResult ares)
308 BytesTransferred = curSocket.EndSend (ares);
309 } catch (SocketException se){
310 SocketError = se.SocketErrorCode;
311 } catch (ObjectDisposedException) {
312 SocketError = SocketError.OperationAborted;
319 internal void AcceptCallback (IAsyncResult ares)
322 AcceptSocket = curSocket.EndAccept (ares);
323 } catch (SocketException ex) {
324 SocketError = ex.SocketErrorCode;
325 } catch (ObjectDisposedException) {
326 SocketError = SocketError.OperationAborted;
328 if (AcceptSocket == null)
329 AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, (IntPtr)(-1));
334 internal void DisconnectCallback (IAsyncResult ares)
337 curSocket.EndDisconnect (ares);
338 } catch (SocketException ex) {
339 SocketError = ex.SocketErrorCode;
340 } catch (ObjectDisposedException) {
341 SocketError = SocketError.OperationAborted;
347 internal void ReceiveFromCallback (IAsyncResult ares)
350 BytesTransferred = curSocket.EndReceiveFrom (ares, ref remote_ep);
351 } catch (SocketException ex) {
352 SocketError = ex.SocketErrorCode;
353 } catch (ObjectDisposedException) {
354 SocketError = SocketError.OperationAborted;
360 internal void SendToCallback (IAsyncResult ares)
363 BytesTransferred = curSocket.EndSendTo (ares);
364 } catch (SocketException ex) {
365 SocketError = ex.SocketErrorCode;
366 } catch (ObjectDisposedException) {
367 SocketError = SocketError.OperationAborted;
374 internal void DoOperation (SocketAsyncOperation operation, Socket socket)
376 ThreadStart callback = null;
380 case SocketAsyncOperation.Connect:
382 socket.seed_endpoint = RemoteEndPoint;
384 callback = new ThreadStart (ConnectCallback);
385 SocketError = SocketError.Success;
386 LastOperation = operation;
390 throw new NotSupportedException ();
393 Thread t = new Thread (callback);
394 t.IsBackground = true;