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;
35 #if MOONLIGHT && !INSIDE_SYSTEM
36 using System.Net.Policy;
39 namespace System.Net.Sockets
41 public class SocketAsyncEventArgs : EventArgs, IDisposable
43 #if MOONLIGHT || NET_4_0
44 public Exception ConnectByNameError { get; internal set; }
47 public event EventHandler<SocketAsyncEventArgs> Completed;
49 IList <ArraySegment <byte>> _bufferList;
51 public Socket AcceptSocket { get; set; }
52 public byte[] Buffer { get; private set; }
54 [MonoTODO ("not supported in all cases")]
55 public IList<ArraySegment<byte>> BufferList {
56 get { return _bufferList; }
58 if (Buffer != null && value != null)
59 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
64 public int BytesTransferred { get; private set; }
65 public int Count { get; private set; }
66 public bool DisconnectReuseSocket { get; set; }
67 public SocketAsyncOperation LastOperation { get; private set; }
68 public int Offset { get; private set; }
69 public EndPoint RemoteEndPoint { get; set; }
71 public IPPacketInformation ReceiveMessageFromPacketInfo { get; private set; }
72 public SendPacketsElement[] SendPacketsElements { get; set; }
73 public TransmitFileOptions SendPacketsFlags { get; set; }
75 [MonoTODO ("unused property")]
76 public int SendPacketsSendSize { get; set; }
77 public SocketError SocketError { get; set; }
78 public SocketFlags SocketFlags { get; set; }
79 public object UserToken { get; set; }
81 #if MOONLIGHT && !INSIDE_SYSTEM
82 private SocketClientAccessPolicyProtocol policy_protocol;
84 [MonoTODO ("Only TCP is currently supported by Moonlight")]
85 public SocketClientAccessPolicyProtocol SocketClientAccessPolicyProtocol {
86 get { return policy_protocol; }
88 if ((value != SocketClientAccessPolicyProtocol.Tcp) && (value != SocketClientAccessPolicyProtocol.Http))
89 throw new ArgumentException ("Invalid value");
90 policy_protocol = value;
97 public Socket ConnectSocket {
99 switch (SocketError) {
100 case SocketError.AccessDenied:
108 internal bool PolicyRestricted { get; private set; }
110 internal SocketAsyncEventArgs (bool policy) :
113 PolicyRestricted = policy;
117 public SocketAsyncEventArgs ()
122 BytesTransferred = 0;
124 DisconnectReuseSocket = false;
125 LastOperation = SocketAsyncOperation.None;
127 RemoteEndPoint = null;
129 SendPacketsElements = null;
130 SendPacketsFlags = TransmitFileOptions.UseDefaultWorkerThread;
132 SendPacketsSendSize = -1;
133 SocketError = SocketError.Success;
134 SocketFlags = SocketFlags.None;
137 #if MOONLIGHT && !INSIDE_SYSTEM
138 policy_protocol = SocketClientAccessPolicyProtocol.Tcp;
142 ~SocketAsyncEventArgs ()
147 void Dispose (bool disposing)
149 Socket acceptSocket = AcceptSocket;
150 if (acceptSocket != null)
151 acceptSocket.Close ();
154 GC.SuppressFinalize (this);
157 public void Dispose ()
162 protected virtual void OnCompleted (SocketAsyncEventArgs e)
167 EventHandler<SocketAsyncEventArgs> handler = e.Completed;
169 handler (e.curSocket, e);
172 public void SetBuffer (int offset, int count)
174 SetBufferInternal (Buffer, offset, count);
177 public void SetBuffer (byte[] buffer, int offset, int count)
179 SetBufferInternal (buffer, offset, count);
182 void SetBufferInternal (byte[] buffer, int offset, int count)
184 if (buffer != null) {
185 if (BufferList != null)
186 throw new ArgumentException ("Buffer and BufferList properties cannot both be non-null.");
188 int buflen = buffer.Length;
189 if (offset < 0 || (offset != 0 && offset >= buflen))
190 throw new ArgumentOutOfRangeException ("offset");
192 if (count < 0 || count > buflen - offset)
193 throw new ArgumentOutOfRangeException ("count");
202 void ReceiveCallback ()
204 SocketError = SocketError.Success;
205 LastOperation = SocketAsyncOperation.Receive;
206 SocketError error = SocketError.Success;
208 if (!curSocket.Connected) {
209 SocketError = SocketError.NotConnected;
214 // FIXME: this does not support using BufferList
215 BytesTransferred = curSocket.Receive_nochecks (Buffer, Offset, Count, SocketFlags, out error);
222 void ConnectCallback ()
224 LastOperation = SocketAsyncOperation.Connect;
225 SocketError error = SocketError.AccessDenied;
227 #if MOONLIGHT || NET_4_0
228 // Connect to the first address that match the host name, like:
229 // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
230 // while skipping entries that do not match the address family
231 DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
233 IPAddress[] addresses = Dns.GetHostAddresses (dep.Host);
234 foreach (IPAddress addr in addresses) {
236 if (curSocket.AddressFamily == addr.AddressFamily) {
237 error = TryConnect (new IPEndPoint (addr, dep.Port));
238 if (error == SocketError.Success) {
239 ConnectByNameError = null;
244 catch (SocketException se) {
245 ConnectByNameError = se;
246 error = SocketError.AccessDenied;
250 ConnectByNameError = null;
251 error = TryConnect (RemoteEndPoint);
254 error = TryConnect (RemoteEndPoint);
262 SocketError TryConnect (EndPoint endpoint)
264 curSocket.Connected = false;
265 SocketError error = SocketError.Success;
266 #if MOONLIGHT && !INSIDE_SYSTEM
267 // if we're not downloading a socket policy then check the policy
268 // and if we're not running with elevated permissions (SL4 OoB option)
269 if (!PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
270 error = SocketError.AccessDenied;
271 if (!CrossDomainPolicyManager.CheckEndPoint (endpoint, policy_protocol)) {
274 error = SocketError.Success;
279 if (!curSocket.Blocking) {
281 curSocket.Poll (-1, SelectMode.SelectWrite, out success);
282 error = (SocketError)success;
284 curSocket.Connected = true;
290 curSocket.seed_endpoint = endpoint;
291 curSocket.Connect (endpoint);
292 curSocket.Connected = true;
294 } catch (SocketException se){
295 error = se.SocketErrorCode;
302 SocketError = SocketError.Success;
303 LastOperation = SocketAsyncOperation.Send;
304 SocketError error = SocketError.Success;
306 if (!curSocket.Connected) {
307 SocketError = SocketError.NotConnected;
312 if (Buffer != null) {
313 BytesTransferred = curSocket.Send_nochecks (Buffer, Offset, Count, SocketFlags.None, out error);
314 } else if (BufferList != null) {
315 BytesTransferred = 0;
316 foreach (ArraySegment<byte> asb in BufferList) {
317 BytesTransferred += curSocket.Send_nochecks (asb.Array, asb.Offset, asb.Count,
318 SocketFlags.None, out error);
319 if (error != SocketError.Success)
329 void AcceptCallback ()
331 SocketError = SocketError.Success;
332 LastOperation = SocketAsyncOperation.Accept;
334 curSocket.Accept (AcceptSocket);
335 } catch (SocketException ex) {
336 SocketError = ex.SocketErrorCode;
343 void DisconnectCallback ()
345 SocketError = SocketError.Success;
346 LastOperation = SocketAsyncOperation.Disconnect;
349 curSocket.Disconnect (DisconnectReuseSocket);
350 } catch (SocketException ex) {
351 SocketError = ex.SocketErrorCode;
358 void ReceiveFromCallback ()
360 SocketError = SocketError.Success;
361 LastOperation = SocketAsyncOperation.ReceiveFrom;
364 EndPoint ep = RemoteEndPoint;
365 if (Buffer != null) {
366 BytesTransferred = curSocket.ReceiveFrom_nochecks (Buffer, Offset, Count, SocketFlags, ref ep);
367 } else if (BufferList != null) {
368 throw new NotImplementedException ();
370 } catch (SocketException ex) {
371 SocketError = ex.SocketErrorCode;
378 void SendToCallback ()
380 SocketError = SocketError.Success;
381 LastOperation = SocketAsyncOperation.SendTo;
387 while (total < count)
388 total += curSocket.SendTo_nochecks (Buffer, Offset, count, SocketFlags, RemoteEndPoint);
389 BytesTransferred = total;
390 } catch (SocketException ex) {
391 SocketError = ex.SocketErrorCode;
398 internal void DoOperation (SocketAsyncOperation operation, Socket socket)
400 ThreadStart callback;
405 case SocketAsyncOperation.Accept:
406 callback = new ThreadStart (AcceptCallback);
409 case SocketAsyncOperation.Disconnect:
410 callback = new ThreadStart (DisconnectCallback);
413 case SocketAsyncOperation.ReceiveFrom:
414 callback = new ThreadStart (ReceiveFromCallback);
417 case SocketAsyncOperation.SendTo:
418 callback = new ThreadStart (SendToCallback);
421 case SocketAsyncOperation.Receive:
422 callback = new ThreadStart (ReceiveCallback);
425 case SocketAsyncOperation.Connect:
426 callback = new ThreadStart (ConnectCallback);
429 case SocketAsyncOperation.Send:
430 callback = new ThreadStart (SendCallback);
434 throw new NotSupportedException ();
437 Thread t = new Thread (callback);
438 t.IsBackground = true;