public void close (final SocketChannel sc, final Callback.TCPClient client) {
    
    if (   !sc.isConnected()      
        || !sc.isOpen()           
        || sc.socket().isClosed()) { return; }

    if (this.isLoopThread()) {
      R r = r(sc);
      assert r != null;
      // try to (more or less) follow close/shutdown conventions:
      // `close` tries to deliver pending data (be it in app or os buffers)
      // while `shutdown` doesn't care.

      if ( sc.socket().isOutputShutdown() || !r.dataPending() ) {
        handleClose(sc); 
      } else {
        r.closePending = true;
      }
      return;
    }

    this.addTimeout(new Callback.Timeout() {
      public void go (TimeoutLoop l) {
        close(sc, client);
      }
    });
  }