//
// Authors:
// Marek Habersack (mhabersack@novell.com)
-// Gonzalo Paniagua Javier (gonzalo@novell.com)
+// Gonzalo Paniagua Javier (gonzalo@xamarin.com)
//
// Copyright (c) 2008,2010 Novell, Inc. (http://www.novell.com)
+// Copyright (c) 2011 Xamarin, Inc. (http://xamarin.com)
//
//
using System.Reflection;
using System.Security;
using System.Threading;
-#if MOONLIGHT && !INSIDE_SYSTEM
-using System.Net.Policy;
-#endif
namespace System.Net.Sockets
{
public class SocketAsyncEventArgs : EventArgs, IDisposable
{
+ bool disposed;
+ int in_progress;
internal Socket.Worker Worker;
EndPoint remote_ep;
-#if MOONLIGHT || NET_4_0
+#if NET_4_0
public Exception ConnectByNameError { get; internal set; }
#endif
public Socket AcceptSocket { get; set; }
public byte[] Buffer { get; private set; }
- [MonoTODO ("not supported in all cases")]
public IList<ArraySegment<byte>> BufferList {
get { return _bufferList; }
set {
}
}
- public int BytesTransferred { get; private set; }
- public int Count { get; private set; }
+ public int BytesTransferred { get; internal set; }
+ public int Count { get; internal set; }
public bool DisconnectReuseSocket { get; set; }
public SocketAsyncOperation LastOperation { get; private set; }
public int Offset { get; private set; }
public SocketError SocketError { get; set; }
public SocketFlags SocketFlags { get; set; }
public object UserToken { get; set; }
-
-#if MOONLIGHT && !INSIDE_SYSTEM
- private SocketClientAccessPolicyProtocol policy_protocol;
-
- [MonoTODO ("Only TCP is currently supported by Moonlight")]
- public SocketClientAccessPolicyProtocol SocketClientAccessPolicyProtocol {
- get { return policy_protocol; }
- set {
- if ((value != SocketClientAccessPolicyProtocol.Tcp) && (value != SocketClientAccessPolicyProtocol.Http))
- throw new ArgumentException ("Invalid value");
- policy_protocol = value;
- }
- }
-#endif
-
internal Socket curSocket;
#if NET_2_1
public Socket ConnectSocket {
SocketError = SocketError.Success;
SocketFlags = SocketFlags.None;
UserToken = null;
-
-#if MOONLIGHT && !INSIDE_SYSTEM
- policy_protocol = SocketClientAccessPolicyProtocol.Tcp;
-#endif
}
~SocketAsyncEventArgs ()
void Dispose (bool disposing)
{
+ disposed = true;
+
if (disposing) {
+ if (disposed || Interlocked.CompareExchange (ref in_progress, 0, 0) != 0)
+ return;
if (Worker != null) {
Worker.Dispose ();
Worker = null;
GC.SuppressFinalize (this);
}
+ internal void SetLastOperation (SocketAsyncOperation op)
+ {
+ if (disposed)
+ throw new ObjectDisposedException ("System.Net.Sockets.SocketAsyncEventArgs");
+ if (Interlocked.Exchange (ref in_progress, 1) != 0)
+ throw new InvalidOperationException ("Operation already in progress");
+ LastOperation = op;
+ }
+
protected virtual void OnCompleted (SocketAsyncEventArgs e)
{
if (e == null)
}
#region Internals
- internal void ReceiveCallback (IAsyncResult ares)
+ internal static AsyncCallback Dispatcher = new AsyncCallback (DispatcherCB);
+
+ static void DispatcherCB (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Receive;
+ SocketAsyncEventArgs args = (SocketAsyncEventArgs) ares.AsyncState;
+ if (Interlocked.Exchange (ref args.in_progress, 0) != 1)
+ throw new InvalidOperationException ("No operation in progress");
+ SocketAsyncOperation op = args.LastOperation;
+ // Notes;
+ // -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
+ // -SendPackets and ReceiveMessageFrom are not implemented yet
+ if (op == SocketAsyncOperation.Receive)
+ args.ReceiveCallback (ares);
+ else if (op == SocketAsyncOperation.Send)
+ args.SendCallback (ares);
+ else if (op == SocketAsyncOperation.ReceiveFrom)
+ args.ReceiveFromCallback (ares);
+ else if (op == SocketAsyncOperation.SendTo)
+ args.SendToCallback (ares);
+ else if (op == SocketAsyncOperation.Accept)
+ args.AcceptCallback (ares);
+ else if (op == SocketAsyncOperation.Disconnect)
+ args.DisconnectCallback (ares);
+ else if (op == SocketAsyncOperation.Connect)
+ args.ConnectCallback ();
+ /*
+ else if (op == Socket.SocketOperation.ReceiveMessageFrom)
+ else if (op == Socket.SocketOperation.SendPackets)
+ */
+ else
+ throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
+ }
+
+ internal void ReceiveCallback (IAsyncResult ares)
+ {
try {
BytesTransferred = curSocket.EndReceive (ares);
} catch (SocketException se){
SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
void ConnectCallback ()
{
- LastOperation = SocketAsyncOperation.Connect;
- SocketError error = SocketError.AccessDenied;
try {
-#if MOONLIGHT || NET_4_0
- // Connect to the first address that match the host name, like:
- // http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx
- // while skipping entries that do not match the address family
- DnsEndPoint dep = (RemoteEndPoint as DnsEndPoint);
- if (dep != null) {
- IPAddress[] addresses = Dns.GetHostAddresses (dep.Host);
- foreach (IPAddress addr in addresses) {
- try {
- if (curSocket.AddressFamily == addr.AddressFamily) {
- error = TryConnect (new IPEndPoint (addr, dep.Port));
- if (error == SocketError.Success) {
- ConnectByNameError = null;
- break;
- }
- }
- }
- catch (SocketException se) {
- ConnectByNameError = se;
- error = SocketError.AccessDenied;
- }
- }
- } else {
- ConnectByNameError = null;
- error = TryConnect (RemoteEndPoint);
- }
-#else
- error = TryConnect (RemoteEndPoint);
-#endif
+ SocketError = (SocketError) Worker.result.error;
} finally {
- SocketError = error;
OnCompleted (this);
}
}
- SocketError TryConnect (EndPoint endpoint)
- {
- curSocket.Connected = false;
- SocketError error = SocketError.Success;
-#if MOONLIGHT && !INSIDE_SYSTEM
- // if we're not downloading a socket policy then check the policy
- // and if we're not running with elevated permissions (SL4 OoB option)
- if (!PolicyRestricted && !SecurityManager.HasElevatedPermissions) {
- error = SocketError.AccessDenied;
- if (!CrossDomainPolicyManager.CheckEndPoint (endpoint, policy_protocol)) {
- return error;
- }
- error = SocketError.Success;
- }
-#endif
- try {
-#if !NET_2_1
- if (!curSocket.Blocking) {
- int success;
- curSocket.Poll (-1, SelectMode.SelectWrite, out success);
- error = (SocketError)success;
- if (success == 0)
- curSocket.Connected = true;
- else
- return error;
- } else
-#endif
- {
- curSocket.seed_endpoint = endpoint;
- curSocket.Connect (endpoint);
- curSocket.Connected = true;
- }
- } catch (SocketException se){
- error = se.SocketErrorCode;
- }
- return error;
- }
-
internal void SendCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Send;
-
try {
BytesTransferred = curSocket.EndSend (ares);
} catch (SocketException se){
SocketError = se.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
}
-#if !MOONLIGHT
internal void AcceptCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Accept;
try {
AcceptSocket = curSocket.EndAccept (ares);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
+ if (AcceptSocket == null)
+ AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, (IntPtr)(-1));
OnCompleted (this);
}
}
internal void DisconnectCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.Disconnect;
-
try {
curSocket.EndDisconnect (ares);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
internal void ReceiveFromCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.ReceiveFrom;
-
try {
BytesTransferred = curSocket.EndReceiveFrom (ares, ref remote_ep);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
internal void SendToCallback (IAsyncResult ares)
{
- SocketError = SocketError.Success;
- LastOperation = SocketAsyncOperation.SendTo;
-
try {
BytesTransferred = curSocket.EndSendTo (ares);
} catch (SocketException ex) {
SocketError = ex.SocketErrorCode;
+ } catch (ObjectDisposedException) {
+ SocketError = SocketError.OperationAborted;
} finally {
OnCompleted (this);
}
}
-
-#endif
- internal void DoOperation (SocketAsyncOperation operation, Socket socket)
- {
- ThreadStart callback = null;
- curSocket = socket;
-
- switch (operation) {
- case SocketAsyncOperation.Connect:
- callback = new ThreadStart (ConnectCallback);
- break;
-
- default:
- throw new NotSupportedException ();
- }
-
- Thread t = new Thread (callback);
- t.IsBackground = true;
- t.Start ();
- }
#endregion
}
}