|
@@ -18,6 +18,7 @@ namespace Renci.SshNet.Tests.Common
|
|
|
private Thread _receiveThread;
|
|
private Thread _receiveThread;
|
|
|
private bool _started;
|
|
private bool _started;
|
|
|
private object _syncLock;
|
|
private object _syncLock;
|
|
|
|
|
+ private string _stackTrace;
|
|
|
|
|
|
|
|
public delegate void BytesReceivedHandler(byte[] bytesReceived, Socket socket);
|
|
public delegate void BytesReceivedHandler(byte[] bytesReceived, Socket socket);
|
|
|
public delegate void ConnectedHandler(Socket socket);
|
|
public delegate void ConnectedHandler(Socket socket);
|
|
@@ -56,6 +57,8 @@ namespace Renci.SshNet.Tests.Common
|
|
|
|
|
|
|
|
_receiveThread = new Thread(StartListener);
|
|
_receiveThread = new Thread(StartListener);
|
|
|
_receiveThread.Start(_listener);
|
|
_receiveThread.Start(_listener);
|
|
|
|
|
+
|
|
|
|
|
+ _stackTrace = Environment.StackTrace;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void Stop()
|
|
public void Stop()
|
|
@@ -78,7 +81,10 @@ namespace Renci.SshNet.Tests.Common
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DrainSocket(connectedClient);
|
|
DrainSocket(connectedClient);
|
|
|
|
|
+ connectedClient.Dispose();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ _connectedClients.Clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (_listener != null)
|
|
if (_listener != null)
|
|
@@ -116,26 +122,62 @@ namespace Renci.SshNet.Tests.Common
|
|
|
_acceptCallbackDone.Set();
|
|
_acceptCallbackDone.Set();
|
|
|
|
|
|
|
|
// Get the socket that listens for inbound connections
|
|
// Get the socket that listens for inbound connections
|
|
|
- var listener = (Socket) ar.AsyncState;
|
|
|
|
|
|
|
+ var listener = (Socket)ar.AsyncState;
|
|
|
|
|
|
|
|
// Get the socket that handles the client request
|
|
// Get the socket that handles the client request
|
|
|
- var handler = listener.EndAccept(ar);
|
|
|
|
|
|
|
+ Socket handler;
|
|
|
|
|
+
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ handler = listener.EndAccept(ar);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (ObjectDisposedException ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ // The listener is stopped through a Dispose() call, which in turn causes
|
|
|
|
|
+ // Socket.EndAccept(IAsyncResult) to throw an ObjectDisposedException
|
|
|
|
|
+ //
|
|
|
|
|
+ // Since we consider this ObjectDisposedException normal when the listener
|
|
|
|
|
+ // is being stopped, we only write a message to stderr if the listener
|
|
|
|
|
+ // is considered to be up and running
|
|
|
|
|
+ if (_started)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.Error.WriteLine("[{0}] Failure accepting new connection: {1}",
|
|
|
|
|
+ typeof(AsyncSocketListener).FullName,
|
|
|
|
|
+ ex);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// Signal new connection
|
|
// Signal new connection
|
|
|
SignalConnected(handler);
|
|
SignalConnected(handler);
|
|
|
|
|
|
|
|
- // Register client socket
|
|
|
|
|
- _connectedClients.Add(handler);
|
|
|
|
|
|
|
+ lock (_syncLock)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Register client socket
|
|
|
|
|
+ _connectedClients.Add(handler);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var state = new SocketStateObject(handler);
|
|
|
|
|
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- var state = new SocketStateObject(handler);
|
|
|
|
|
handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
|
|
handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
|
|
|
}
|
|
}
|
|
|
- catch (ObjectDisposedException)
|
|
|
|
|
|
|
+ catch (ObjectDisposedException ex)
|
|
|
{
|
|
{
|
|
|
- // when the socket is closed, an ObjectDisposedException is thrown
|
|
|
|
|
- // by Socket.EndAccept(IAsyncResult)
|
|
|
|
|
|
|
+ // The listener is stopped through a Dispose() call, which in turn causes
|
|
|
|
|
+ // Socket.BeginReceive(...) to throw an ObjectDisposedException
|
|
|
|
|
+ //
|
|
|
|
|
+ // Since we consider this ObjectDisposedException normal when the listener
|
|
|
|
|
+ // is being stopped, we only write a message to stderr if the listener
|
|
|
|
|
+ // is considered to be up and running
|
|
|
|
|
+ if (_started)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.Error.WriteLine("[{0}] Failure receiving new data: {1}",
|
|
|
|
|
+ typeof(AsyncSocketListener).FullName,
|
|
|
|
|
+ ex);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -143,7 +185,7 @@ namespace Renci.SshNet.Tests.Common
|
|
|
{
|
|
{
|
|
|
// Retrieve the state object and the handler socket
|
|
// Retrieve the state object and the handler socket
|
|
|
// from the asynchronous state object
|
|
// from the asynchronous state object
|
|
|
- var state = (SocketStateObject) ar.AsyncState;
|
|
|
|
|
|
|
+ var state = (SocketStateObject)ar.AsyncState;
|
|
|
var handler = state.Socket;
|
|
var handler = state.Socket;
|
|
|
|
|
|
|
|
int bytesRead;
|
|
int bytesRead;
|
|
@@ -152,11 +194,38 @@ namespace Renci.SshNet.Tests.Common
|
|
|
// Read data from the client socket.
|
|
// Read data from the client socket.
|
|
|
bytesRead = handler.EndReceive(ar);
|
|
bytesRead = handler.EndReceive(ar);
|
|
|
}
|
|
}
|
|
|
- catch (ObjectDisposedException)
|
|
|
|
|
|
|
+ catch (SocketException ex)
|
|
|
{
|
|
{
|
|
|
- // when the socket is closed, the callback will be invoked for any pending BeginReceive
|
|
|
|
|
- // we could use the Socket.Connected property to detect this here, but the proper thing
|
|
|
|
|
- // to do is invoke EndReceive knowing that it will throw an ObjectDisposedException
|
|
|
|
|
|
|
+ // The listener is stopped through a Dispose() call, which in turn causes
|
|
|
|
|
+ // Socket.EndReceive(...) to throw a SocketException or
|
|
|
|
|
+ // ObjectDisposedException
|
|
|
|
|
+ //
|
|
|
|
|
+ // Since we consider such an exception normal when the listener is being
|
|
|
|
|
+ // stopped, we only write a message to stderr if the listener is considered
|
|
|
|
|
+ // to be up and running
|
|
|
|
|
+ if (_started)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.Error.WriteLine("[{0}] Failure receiving new data: {1}",
|
|
|
|
|
+ typeof(AsyncSocketListener).FullName,
|
|
|
|
|
+ ex);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (ObjectDisposedException ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ // The listener is stopped through a Dispose() call, which in turn causes
|
|
|
|
|
+ // Socket.EndReceive(...) to throw a SocketException or
|
|
|
|
|
+ // ObjectDisposedException
|
|
|
|
|
+ //
|
|
|
|
|
+ // Since we consider such an exception normal when the listener is being
|
|
|
|
|
+ // stopped, we only write a message to stderr if the listener is considered
|
|
|
|
|
+ // to be up and running
|
|
|
|
|
+ if (_started)
|
|
|
|
|
+ {
|
|
|
|
|
+ Console.Error.WriteLine("[{0}] Failure receiving new data: {1}",
|
|
|
|
|
+ typeof(AsyncSocketListener).FullName,
|
|
|
|
|
+ ex);
|
|
|
|
|
+ }
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -165,7 +234,21 @@ namespace Renci.SshNet.Tests.Common
|
|
|
var bytesReceived = new byte[bytesRead];
|
|
var bytesReceived = new byte[bytesRead];
|
|
|
Array.Copy(state.Buffer, bytesReceived, bytesRead);
|
|
Array.Copy(state.Buffer, bytesReceived, bytesRead);
|
|
|
SignalBytesReceived(bytesReceived, handler);
|
|
SignalBytesReceived(bytesReceived, handler);
|
|
|
- handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (SocketException ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!_started)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw new Exception("BeginReceive while stopping!", ex);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ throw new Exception("BeginReceive while started!: " + ex.SocketErrorCode + " " + _stackTrace, ex);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -175,8 +258,23 @@ namespace Renci.SshNet.Tests.Common
|
|
|
{
|
|
{
|
|
|
lock (_syncLock)
|
|
lock (_syncLock)
|
|
|
{
|
|
{
|
|
|
- handler.Shutdown(SocketShutdown.Send);
|
|
|
|
|
- handler.Close();
|
|
|
|
|
|
|
+ if (!_started)
|
|
|
|
|
+ {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ handler.Shutdown(SocketShutdown.Send);
|
|
|
|
|
+ handler.Close();
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (SocketException ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw new Exception("Exception in ReadCallback: " + ex.SocketErrorCode + " " + _stackTrace, ex);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw new Exception("Exception in ReadCallback: " + _stackTrace, ex);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
_connectedClients.Remove(handler);
|
|
_connectedClients.Remove(handler);
|
|
|
}
|
|
}
|