diff options
author | Gonzalo Paniagua Javier <gonzalo.mono@gmail.com> | 2004-01-24 16:07:14 +0300 |
---|---|---|
committer | Gonzalo Paniagua Javier <gonzalo.mono@gmail.com> | 2004-01-24 16:07:14 +0300 |
commit | 8fc4e8ba06e1c9cda2b92b08aa59980e5e7563d7 (patch) | |
tree | 1667220f4c76829508420782cf8eb282e2199471 /mcs/class/System/System.Net.Sockets | |
parent | 085a64e6bf88f98bce24b1a6c9b38511e4a44e09 (diff) |
2004-01-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
* Socket.cs: if we have a pending async event, delay socket closing
until EndX is called. Fixes bug #53229. Check parameters and if the
socket has been disposed. Implemented IDisposable explicitly. The
threads created have IsBackground = true now.
svn path=/trunk/mcs/; revision=22464
Diffstat (limited to 'mcs/class/System/System.Net.Sockets')
-rw-r--r-- | mcs/class/System/System.Net.Sockets/ChangeLog | 7 | ||||
-rw-r--r-- | mcs/class/System/System.Net.Sockets/Socket.cs | 212 |
2 files changed, 203 insertions, 16 deletions
diff --git a/mcs/class/System/System.Net.Sockets/ChangeLog b/mcs/class/System/System.Net.Sockets/ChangeLog index 2d01884ac02..4f537c917a1 100644 --- a/mcs/class/System/System.Net.Sockets/ChangeLog +++ b/mcs/class/System/System.Net.Sockets/ChangeLog @@ -1,3 +1,10 @@ +2004-01-24 Gonzalo Paniagua Javier <gonzalo@ximian.com> + + * Socket.cs: if we have a pending async event, delay socket closing + until EndX is called. Fixes bug #53229. Check parameters and if the + socket has been disposed. Implemented IDisposable explicitly. The + threads created have IsBackground = true now. + 2004-01-10 Gonzalo Paniagua Javier <gonzalo@ximian.com> * Socket.cs: patch from Brad Fitzpatrick <brad@danga.com> episode 2. diff --git a/mcs/class/System/System.Net.Sockets/Socket.cs b/mcs/class/System/System.Net.Sockets/Socket.cs index 4e7502aeb87..c5b08928ade 100644 --- a/mcs/class/System/System.Net.Sockets/Socket.cs +++ b/mcs/class/System/System.Net.Sockets/Socket.cs @@ -298,6 +298,8 @@ namespace System.Net.Sockets private SocketType socket_type; private ProtocolType protocol_type; private bool blocking=true; + private int pendingEnds; + private int closeDelayed; /*
* These two fields are looked up by name by the runtime, don't change
@@ -309,6 +311,8 @@ namespace System.Net.Sockets * the last IO operation */ private bool connected=false; + /* true if we called Close_internal */ + private bool closed; /* Used in LocalEndPoint and RemoteEndPoint if the * Mono.Posix assembly is available @@ -468,6 +472,9 @@ namespace System.Net.Sockets public int Available { get { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + return(Available_internal(socket)); } } @@ -505,6 +512,9 @@ namespace System.Net.Sockets [MonoTODO("Support non-IP endpoints")] public EndPoint LocalEndPoint { get { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + SocketAddress sa; sa=LocalEndPoint_internal(socket); @@ -535,6 +545,9 @@ namespace System.Net.Sockets [MonoTODO("Support non-IP endpoints")] public EndPoint RemoteEndPoint { get { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + SocketAddress sa; sa=RemoteEndPoint_internal(socket); @@ -627,6 +640,9 @@ namespace System.Net.Sockets private extern static IntPtr Accept_internal(IntPtr sock); public Socket Accept() { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + IntPtr sock=Accept_internal(socket); return(new Socket(this.AddressFamily, this.SocketType, @@ -635,10 +651,16 @@ namespace System.Net.Sockets public IAsyncResult BeginAccept(AsyncCallback callback, object state) { + + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + Interlocked.Increment (ref pendingEnds); SocketAsyncResult req=new SocketAsyncResult(state); Worker worker=new Worker(this, callback, req); req.Worker=worker; Thread child=new Thread(new ThreadStart(worker.Accept)); + child.IsBackground = true; child.Start(); return(req); } @@ -646,11 +668,20 @@ namespace System.Net.Sockets public IAsyncResult BeginConnect(EndPoint end_point, AsyncCallback callback, object state) { + + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (end_point == null) + throw new ArgumentNullException ("end_point"); + + Interlocked.Increment (ref pendingEnds); SocketAsyncResult req=new SocketAsyncResult(state); Worker worker=new Worker(this, end_point, callback, req); req.Worker=worker; Thread child=new Thread(new ThreadStart(worker.Connect)); + child.IsBackground = true; child.Start(); return(req); } @@ -660,11 +691,29 @@ namespace System.Net.Sockets SocketFlags socket_flags, AsyncCallback callback, object state) { + + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (buffer == null) + throw new ArgumentNullException ("buffer"); + + if (offset < 0) + throw new ArgumentOutOfRangeException ("offset must be >= 0"); + + if (size < 0) + throw new ArgumentOutOfRangeException ("size must be >= 0"); + + if (offset + size > buffer.Length) + throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length"); + + Interlocked.Increment (ref pendingEnds); SocketAsyncResult req=new SocketAsyncResult(state); Worker worker=new Worker(this, buffer, offset, size, socket_flags, callback, req); req.Worker=worker; Thread child=new Thread(new ThreadStart(worker.Receive)); + child.IsBackground = true; child.Start(); return(req); } @@ -675,12 +724,29 @@ namespace System.Net.Sockets ref EndPoint remote_end, AsyncCallback callback, object state) { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (buffer == null) + throw new ArgumentNullException ("buffer"); + + if (offset < 0) + throw new ArgumentOutOfRangeException ("offset must be >= 0"); + + if (size < 0) + throw new ArgumentOutOfRangeException ("size must be >= 0"); + + if (offset + size > buffer.Length) + throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length"); + + Interlocked.Increment (ref pendingEnds); SocketAsyncResult req=new SocketAsyncResult(state); Worker worker=new Worker(this, buffer, offset, size, socket_flags, remote_end, callback, req); req.Worker=worker; Thread child=new Thread(new ThreadStart(worker.ReceiveFrom)); + child.IsBackground = true; child.Start(); return(req); } @@ -690,11 +756,28 @@ namespace System.Net.Sockets SocketFlags socket_flags, AsyncCallback callback, object state) { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (buffer == null) + throw new ArgumentNullException ("buffer"); + + if (offset < 0) + throw new ArgumentOutOfRangeException ("offset must be >= 0"); + + if (size < 0) + throw new ArgumentOutOfRangeException ("size must be >= 0"); + + if (offset + size > buffer.Length) + throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length"); + + Interlocked.Increment (ref pendingEnds); SocketAsyncResult req=new SocketAsyncResult(state); Worker worker=new Worker(this, buffer, offset, size, socket_flags, callback, req); req.Worker=worker; Thread child=new Thread(new ThreadStart(worker.Send)); + child.IsBackground = true; child.Start(); return(req); } @@ -705,12 +788,29 @@ namespace System.Net.Sockets EndPoint remote_end, AsyncCallback callback, object state) { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (buffer == null) + throw new ArgumentNullException ("buffer"); + + if (offset < 0) + throw new ArgumentOutOfRangeException ("offset must be >= 0"); + + if (size < 0) + throw new ArgumentOutOfRangeException ("size must be >= 0"); + + if (offset + size > buffer.Length) + throw new ArgumentOutOfRangeException ("offset + size exceeds the buffer length"); + + Interlocked.Increment (ref pendingEnds); SocketAsyncResult req=new SocketAsyncResult(state); Worker worker=new Worker(this, buffer, offset, size, socket_flags, remote_end, callback, req); req.Worker=worker; Thread child=new Thread(new ThreadStart(worker.SendTo)); + child.IsBackground = true; child.Start(); return(req); } @@ -721,8 +821,11 @@ namespace System.Net.Sockets SocketAddress sa); public void Bind(EndPoint local_end) { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + if(local_end==null) { - throw new ArgumentNullException(); + throw new ArgumentNullException("local_end"); } Bind_internal(socket, local_end.Serialize()); @@ -733,7 +836,7 @@ namespace System.Net.Sockets private extern static void Close_internal(IntPtr socket); public void Close() { - this.Dispose(); + ((IDisposable) this).Dispose (); } // Connects to the remote address @@ -742,8 +845,11 @@ namespace System.Net.Sockets SocketAddress sa); public void Connect(EndPoint remote_end) { + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + if(remote_end==null) { - throw new ArgumentNullException(); + throw new ArgumentNullException("remote_end"); } Connect_internal(socket, remote_end.Serialize()); @@ -751,54 +857,122 @@ namespace System.Net.Sockets } public Socket EndAccept(IAsyncResult result) { - SocketAsyncResult req=(SocketAsyncResult)result; + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (result == null) + throw new ArgumentNullException ("result"); + + SocketAsyncResult req = result as SocketAsyncResult; + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult"); result.AsyncWaitHandle.WaitOne(); + Interlocked.Decrement (ref pendingEnds); + CheckIfClose (); req.CheckIfThrowDelayedException(); return(req.Worker.Socket); } public void EndConnect(IAsyncResult result) { - SocketAsyncResult req=(SocketAsyncResult)result; + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (result == null) + throw new ArgumentNullException ("result"); + + SocketAsyncResult req = result as SocketAsyncResult; + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult"); result.AsyncWaitHandle.WaitOne(); + Interlocked.Decrement (ref pendingEnds); + CheckIfClose (); req.CheckIfThrowDelayedException(); } public int EndReceive(IAsyncResult result) { - SocketAsyncResult req=(SocketAsyncResult)result; + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (result == null) + throw new ArgumentNullException ("result"); + + SocketAsyncResult req = result as SocketAsyncResult; + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult"); result.AsyncWaitHandle.WaitOne(); + Interlocked.Decrement (ref pendingEnds); + CheckIfClose (); req.CheckIfThrowDelayedException(); return(req.Worker.Total); } public int EndReceiveFrom(IAsyncResult result, ref EndPoint end_point) { - SocketAsyncResult req=(SocketAsyncResult)result; + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (result == null) + throw new ArgumentNullException ("result"); + + SocketAsyncResult req = result as SocketAsyncResult; + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult"); result.AsyncWaitHandle.WaitOne(); + Interlocked.Decrement (ref pendingEnds); + CheckIfClose (); req.CheckIfThrowDelayedException(); end_point=req.Worker.EndPoint; return(req.Worker.Total); } public int EndSend(IAsyncResult result) { - SocketAsyncResult req=(SocketAsyncResult)result; + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (result == null) + throw new ArgumentNullException ("result"); + + SocketAsyncResult req = result as SocketAsyncResult; + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult"); result.AsyncWaitHandle.WaitOne(); + Interlocked.Decrement (ref pendingEnds); + CheckIfClose (); req.CheckIfThrowDelayedException(); return(req.Worker.Total); } public int EndSendTo(IAsyncResult result) { - SocketAsyncResult req=(SocketAsyncResult)result; + if (disposed && closed) + throw new ObjectDisposedException (GetType ().ToString ()); + + if (result == null) + throw new ArgumentNullException ("result"); + + SocketAsyncResult req = result as SocketAsyncResult; + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult"); result.AsyncWaitHandle.WaitOne(); + Interlocked.Decrement (ref pendingEnds); + CheckIfClose (); req.CheckIfThrowDelayedException(); return(req.Worker.Total); } + void CheckIfClose () + { + if (Interlocked.CompareExchange (ref closeDelayed, 1, 0) == 1) { + closed = true; + Close_internal(socket); + } + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static void GetSocketOption_obj_internal(IntPtr socket, SocketOptionLevel level, SocketOptionName name, out object obj_val); [MethodImplAttribute(MethodImplOptions.InternalCall)] @@ -1148,7 +1322,7 @@ namespace System.Net.Sockets return (int) socket; } - private bool disposed = false; + private bool disposed; protected virtual void Dispose(bool explicitDisposing) { // Check to see if Dispose has already been called @@ -1163,16 +1337,22 @@ namespace System.Net.Sockets this.disposed=true; connected=false; - Close_internal(socket); + Interlocked.CompareExchange (ref closeDelayed, 0, 1); + if (Interlocked.CompareExchange (ref pendingEnds, 0, 0) == 0) { + if (Interlocked.CompareExchange (ref closeDelayed, 1, 0) == 1) { + closed = true; + Close_internal(socket); + } + } } } - public void Dispose() { - Dispose(true); - // Take yourself off the Finalization queue - GC.SuppressFinalize(this); + void IDisposable.Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); } - + ~Socket () { Dispose(false); } |