private TcpListener tcpListener;
private readonly IPEndPoint _localEndPoint;
private Thread listenThread;
+ private Socket listenSocket;
private SocketRequestHandler _requestHandler;
- private bool _stopped = true;
+ private int _state = 0;
private readonly object _syncRoot = new object ();
private const int SOCKET_CLOSED = 10004;
+ private const int SOCKET_INVALID_ARGS = 10022;
+
+ private const int STATE_UNINITIALIZED = 0;
+ private const int STATE_RUNNING = 1;
+ private const int STATE_STOPPED = 2;
public SocketResponder (IPEndPoint localEP, SocketRequestHandler requestHandler)
{
get
{
lock (_syncRoot) {
- return _stopped;
+ return _state != STATE_RUNNING;
}
}
}
public void Start ()
{
lock (_syncRoot) {
- if (!_stopped)
- return;
- _stopped = false;
+ if (_state != STATE_UNINITIALIZED)
+ throw new InvalidOperationException ("cannot restart SocketResponder");
+ _state = STATE_RUNNING;
+ tcpListener = new TcpListener (LocalEndPoint);
+ tcpListener.Start ();
listenThread = new Thread (new ThreadStart (Listen));
listenThread.Start ();
- Thread.Sleep (20); // allow listener to start
}
}
public void Stop ()
{
lock (_syncRoot) {
- if (_stopped)
+ if (_state != STATE_RUNNING)
return;
- _stopped = true;
+ _state = STATE_STOPPED;
if (tcpListener != null) {
tcpListener.Stop ();
tcpListener = null;
+ if (listenSocket != null)
+ listenSocket.Close ();
+#if MONO_FEATURE_THREAD_ABORT
+ listenThread.Abort ();
+#else
+ listenThread.Interrupt ();
+#endif
+ listenThread.Join ();
+ listenThread = null;
+ Thread.Sleep (50);
}
}
}
private void Listen ()
{
- tcpListener = new TcpListener (LocalEndPoint);
- tcpListener.Start ();
- while (!_stopped) {
+ while (_state == STATE_RUNNING) {
+ listenSocket = null;
try {
- Socket socket = tcpListener.AcceptSocket ();
- socket.Send (_requestHandler (socket));
+ listenSocket = tcpListener.AcceptSocket ();
+ listenSocket.Send (_requestHandler (listenSocket));
+ try {
+ listenSocket.Shutdown (SocketShutdown.Receive);
+ listenSocket.Shutdown (SocketShutdown.Send);
+ } catch {
+ }
} catch (SocketException ex) {
// ignore interruption of blocking call
- if (ex.ErrorCode != SOCKET_CLOSED)
+ if (ex.ErrorCode != SOCKET_CLOSED && ex.ErrorCode != SOCKET_INVALID_ARGS && _state != STATE_STOPPED)
+ throw;
+ } catch (ObjectDisposedException ex) {
+ Console.WriteLine (ex);
+ if (_state != STATE_STOPPED)
throw;
+#if !MONO_FEATURE_THREAD_ABORT
+ } catch (ThreadInterruptedException) {
+ break;
+#endif
+#if MOBILE
+ } catch (InvalidOperationException ex) {
+ // This breaks some tests running on Android. The problem is that the stack trace
+ // doesn't point to where the exception is actually thrown from but the entire process
+ // is aborted because of unhandled exception.
+ Console.WriteLine ("SocketResponder.Listen failed:");
+ Console.WriteLine (ex);
+#endif
+ } finally {
+#if MONO_FEATURE_THREAD_ABORT
+ Thread.Sleep (500);
+#else
+ try {
+ Thread.Sleep (500);
+ } catch (ThreadInterruptedException) {
+ // nothing to do
+ }
+#endif
+ if (listenSocket != null)
+ listenSocket.Close ();
}
}
}