// public methods
        /// <summary>
        /// Authenticates the connection against the given database.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="credential">The credential.</param>
        public void Authenticate(MongoConnection connection, MongoCredential credential)
        {
            var nonceCommand = new CommandDocument("getnonce", 1);
            var commandResult = connection.RunCommandAs<CommandResult>(credential.Source, QueryFlags.None, nonceCommand, false);
            if (!commandResult.Ok)
            {
                throw new MongoAuthenticationException(
                    "Error getting nonce for authentication.",
                    new MongoCommandException(commandResult));
            }

            var nonce = commandResult.Response["nonce"].AsString;
            var passwordDigest = ((PasswordEvidence)credential.Evidence).ComputeMongoCRPasswordDigest(credential.Username);
            var digest = MongoUtils.Hash(nonce + credential.Username + passwordDigest);
            var authenticateCommand = new CommandDocument
                {
                    { "authenticate", 1 },
                    { "user", credential.Username },
                    { "nonce", nonce },
                    { "key", digest }
                };

            commandResult = connection.RunCommandAs<CommandResult>(credential.Source, QueryFlags.None, authenticateCommand, false);
            if (!commandResult.Ok)
            {
                var message = string.Format("Invalid credential for database '{0}'.", credential.Source);
                throw new MongoAuthenticationException(
                    message,
                    new MongoCommandException(commandResult));
            }
        }
        // public methods
        /// <summary>
        /// Authenticates the connection against the given database.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="credential">The credential.</param>
        public void Authenticate(MongoConnection connection, MongoCredential credential)
        {
            using (var conversation = new SaslConversation())
            {
                var currentStep = _mechanism.Initialize(connection, credential);

                var command = new CommandDocument
                {
                    { "saslStart", 1 },
                    { "mechanism", _mechanism.Name },
                    { "payload", currentStep.BytesToSendToServer }
                };

                while (true)
                {
                    CommandResult result;
                    try
                    {
                        result = connection.RunCommandAs<CommandResult>(credential.Source, QueryFlags.SlaveOk, command, true);
                    }
                    catch (MongoCommandException ex)
                    {
                        var message = "Unknown error occured during authentication.";
                        var code = ex.CommandResult.Code;
                        var errmsg = ex.CommandResult.ErrorMessage;
                        if(code.HasValue && errmsg != null)
                        {
                            message = string.Format("Error: {0} - {1}", code, errmsg);
                        }

                        throw new MongoSecurityException(message, ex);
                    }

                    if (result.Response["done"].AsBoolean)
                    {
                        break;
                    }

                    currentStep = currentStep.Transition(conversation, result.Response["payload"].AsByteArray);

                    command = new CommandDocument
                    {
                        { "saslContinue", 1 },
                        { "conversationId", result.Response["conversationId"].AsInt32 },
                        { "payload", currentStep.BytesToSendToServer }
                    };
                }
            }
        }
 private void Ping(MongoConnection connection)
 {
     try
     {
         var pingCommand = new CommandDocument("ping", 1);
         Stopwatch stopwatch = Stopwatch.StartNew();
         connection.RunCommandAs<CommandResult>("admin", QueryFlags.SlaveOk, pingCommand, true);
         stopwatch.Stop();
         var currentAverage = _pingTimeAggregator.Average;
         _pingTimeAggregator.Include(stopwatch.Elapsed);
         var newAverage = _pingTimeAggregator.Average;
         if (currentAverage != newAverage)
         {
             OnAveragePingTimeChanged();
         }
     }
     catch
     {
         _pingTimeAggregator.Clear();
         SetState(MongoServerState.Disconnected);
         throw;
     }
 }
        // private methods
        private void LookupServerInformation(MongoConnection connection)
        {
            IsMasterResult isMasterResult = null;
            bool ok = false;
            try
            {
                var isMasterCommand = new CommandDocument("ismaster", 1);
                isMasterResult = connection.RunCommandAs<IsMasterResult>("admin", QueryFlags.SlaveOk, isMasterCommand, false);
                isMasterResult.Command = isMasterCommand;
                if (!isMasterResult.Ok)
                {
                    throw new MongoCommandException(isMasterResult);
                }

                MongoServerBuildInfo buildInfo;
                var buildInfoCommand = new CommandDocument("buildinfo", 1);
                var buildInfoResult = connection.RunCommandAs<CommandResult>("admin", QueryFlags.SlaveOk, buildInfoCommand, false);
                if (buildInfoResult.Ok)
                {
                    buildInfo = MongoServerBuildInfo.FromCommandResult(buildInfoResult);
                }
                else
                {
                    // short term fix: if buildInfo fails due to auth we don't know the server version; see CSHARP-324
                    if (buildInfoResult.ErrorMessage != "need to login")
                    {
                        throw new MongoCommandException(buildInfoResult);
                    }
                    buildInfo = null;
                }

                ReplicaSetInformation replicaSetInformation = null;
                MongoServerInstanceType instanceType = MongoServerInstanceType.StandAlone;
                if (isMasterResult.IsReplicaSet)
                {
                    var peers = isMasterResult.Hosts.Concat(isMasterResult.Passives).Concat(isMasterResult.Arbiters).ToList();
                    replicaSetInformation = new ReplicaSetInformation(isMasterResult.ReplicaSetName, isMasterResult.Primary, peers, isMasterResult.Tags);
                    instanceType = MongoServerInstanceType.ReplicaSetMember;
                }
                else if (isMasterResult.Message != null && isMasterResult.Message == "isdbgrid")
                {
                    instanceType = MongoServerInstanceType.ShardRouter;
                }

                var newServerInfo = new ServerInformation
                {
                    BuildInfo = buildInfo,
                    InstanceType = instanceType,
                    IsArbiter = isMasterResult.IsArbiterOnly,
                    IsMasterResult = isMasterResult,
                    IsPassive = isMasterResult.IsPassive,
                    IsPrimary = isMasterResult.IsPrimary,
                    IsSecondary = isMasterResult.IsSecondary,
                    MaxDocumentSize = isMasterResult.MaxBsonObjectSize,
                    MaxMessageLength = isMasterResult.MaxMessageLength,
                    ReplicaSetInformation = replicaSetInformation
                };
                MongoServerState currentState;
                lock (_serverInstanceLock)
                {
                    currentState = _state;
                }
                SetState(currentState, newServerInfo);
                ok = true;
            }
            finally
            {
                if (!ok)
                {
                    ServerInformation currentServerInfo;
                    lock (_serverInstanceLock)
                    {
                        currentServerInfo = _serverInfo;
                    }

                    // keep the current instance type, build info, and replica set info
                    // as these aren't relevent to state and are likely still correct.
                    var newServerInfo = new ServerInformation
                    {
                        BuildInfo = currentServerInfo.BuildInfo,
                        InstanceType = currentServerInfo.InstanceType,
                        IsArbiter = false,
                        IsMasterResult = isMasterResult,
                        IsPassive = false,
                        IsPrimary = false,
                        IsSecondary = false,
                        MaxDocumentSize = currentServerInfo.MaxDocumentSize,
                        MaxMessageLength = currentServerInfo.MaxMessageLength,
                        ReplicaSetInformation = currentServerInfo.ReplicaSetInformation
                    };

                    SetState(MongoServerState.Disconnected, newServerInfo);
                }
            }
        }