/** Main event loop. */
    public void interruptibleRun() {

      m_outputStreamFilterTee.connectionOpened();

      final byte[] buffer = new byte[BUFFER_SIZE];

      try {
        while (true) {
          final int bytesRead = m_in.read(buffer, 0, BUFFER_SIZE);

          if (bytesRead == -1) {
            break;
          }

          m_outputStreamFilterTee.handle(buffer, bytesRead);
        }
      } catch (SocketException e) {
        // Ignore, assume closed.
      } catch (IOException e) {
        UncheckedInterruptedException.ioException(e);
        logIOException(e);
      } finally {
        m_outputStreamFilterTee.connectionClosed();
      }

      // Tidy up.
      Closer.close(m_in);
    }
    /** Close the associated input stream and thus stop the thread. */
    public void stop() {
      Closer.close(m_inputStream);

      // We can interrupt our thread because its executing an
      // InterruptibleRunnable.
      m_thread.interrupt();

      try {
        m_thread.join();
      } catch (InterruptedException e) {
        throw new UncheckedInterruptedException(e);
      }
    }
    /** A connection has been closed. */
    public void connectionClosed() {

      preOutput();

      try {
        m_filter.connectionClosed(m_connectionDetails);
      } catch (GrinderException e) {
        e.printStackTrace(getLogger().getErrorLogWriter());
      } finally {
        postOutput();
      }

      // Close our output stream. This will cause any
      // FilteredStreamThread managing the paired stream to exit.
      Closer.close(m_out);
    }