docs: function(client, callback) {
      logger.entry('Client.stop.performDisconnect', client.id);
  
      // If this client is still starting, then wait until the state changes
      // before we attempt to stop.
      if (client.state === STATE_STARTING) {
        var stillConnecting = function(client) {
          logger.entry('stillConnecting', client.id);
  
          if (client.state === STATE_STARTING) {
            setImmediate(function() {
              stillConnecting(client);
            });
          } else {
            process.nextTick(function() {
              performDisconnect(client, callback);
            });
          }
  
          logger.exit('stillConnecting', client.id, null);
        };
  
        setImmediate(function() {
          stillConnecting(client);
        });
        logger.exit('Client.stop.performDisconnect', client.id, null);
        return;
      }
  
      client._setState(STATE_STOPPING);
  
      if (client._serviceFunctionTimeout) {
        // if we previously set a timeout to retry the serviceFunction, clear it.
        clearTimeout(client._serviceFunctionTimeout);
      }
      client._serviceFunctionTimeout = null;
  
      // Only disconnect when all outstanding send operations are complete
      if (client._outstandingSends.length === 0) {
        stopMessenger(client, function(client, callback) {
          logger.entry('Client.stop.performDisconnect.stopProcessing',
              client.id);
          // clear queuedSends as we are disconnecting
          var messages = [];
          while (client._queuedSends.length > 0) {
            messages.push(client._queuedSends.shift());
          }
          // call the msg callbacks in error as we have disconnected
          process.nextTick(function() {
            logger.entry('Client.stop.performDisconnect.' +
                'stopProcessing.queuedSendCallback', client.id);
            while (messages.length > 0) {
              var msg = messages.shift();
              if (msg.callback) {
                msg.callback(new StoppedError('send aborted due to client stop'));
              }
            }
            logger.exit('Client.stop.performDisconnect.' +
                'stopProcessing.queuedSendCallback', client.id, null);
          });
          // Clear the active and queued subscriptions lists as we were
          // asked to disconnect.
          logger.log('data', client.id, 'client._subscriptions:',
                     client._subscriptions);
          while (client._subscriptions.length > 0) {
            client._subscriptions.shift();
          }
          while (client._queuedSubscriptions.length > 0) {
            client._queuedSubscriptions.shift();
          }
          // Close our end of the socket
          if (client._stream) {
            client._stream.removeAllListeners('close');
            client._stream.end();
            client._stream = null;
          }
          client._queuedChunks = [];
          client._queuedChunksSize = 0;
  
          // Indicate that we've disconnected
          client._setState(STATE_STOPPED);
          // Remove ourself from the active client list
          var activeClient = activeClientList.get(client.id);
          if (client === activeClient) activeClientList.remove(client.id);
          setImmediate(function() {
            if (!client._firstStart) {
              client._firstStart = true;
              logger.log('emit', client.id, STATE_STOPPED);
              client.emit(STATE_STOPPED);
            }
          });
          if (callback) {
            process.nextTick(function() {
              logger.entry('Client.stop.performDisconnect.stopProcessing.' +
                  'callback', client.id);
              callback.apply(client);
              logger.exit('Client.stop.performDisconnect.stopProcessing.' +
                  'callback', client.id, null);
            });
          }
  
          logger.exit('Client.stop.performDisconnect.stopProcessing',
              client.id, null);
        }, callback);
  
        logger.exit('Client.stop.performDisconnect', client.id, null);
        return;
      }
  
      // try disconnect again
      setImmediate(performDisconnect, client, callback);
  
      logger.exit('Client.stop.performDisconnect', client.id, null);
    }