[Http]: Clear the 'SendChunked' flag when redirecting.
[mono.git] / mcs / class / System / System.Net.Sockets / SocketAsyncEventArgs.cs
index d3bea81b0c071170f6979c89105d76b48b4b8a0d..d8e1c5125e44721237bd87b68263174d8fe21a2d 100644 (file)
@@ -2,9 +2,10 @@
 //
 // 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)
 //
 
 //
@@ -32,17 +33,16 @@ using System.Collections.Generic;
 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
 
@@ -53,7 +53,6 @@ namespace System.Net.Sockets
                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 {
@@ -63,8 +62,8 @@ namespace System.Net.Sockets
                        }
                }
 
-               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; }
@@ -82,21 +81,6 @@ namespace System.Net.Sockets
                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 {
@@ -139,10 +123,6 @@ namespace System.Net.Sockets
                        SocketError = SocketError.Success;
                        SocketFlags = SocketFlags.None;
                        UserToken = null;
-
-#if MOONLIGHT && !INSIDE_SYSTEM
-                       policy_protocol = SocketClientAccessPolicyProtocol.Tcp;
-#endif
                }
 
                ~SocketAsyncEventArgs ()
@@ -152,7 +132,11 @@ namespace System.Net.Sockets
 
                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;
@@ -174,6 +158,15 @@ namespace System.Net.Sockets
                        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)
@@ -214,15 +207,48 @@ namespace System.Net.Sockets
                }
 
 #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);
                        }
@@ -230,119 +256,49 @@ namespace System.Net.Sockets
 
                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);
                        }
@@ -350,13 +306,12 @@ namespace System.Net.Sockets
 
                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);
                        }
@@ -364,37 +319,16 @@ namespace System.Net.Sockets
 
                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
        }
 }