diff --git a/logon_state.go b/logon_state.go index 351fa629c..d254b92b3 100644 --- a/logon_state.go +++ b/logon_state.go @@ -24,23 +24,15 @@ func (s logonState) FixMsgIn(session *session, msg *Message) (nextState sessionS if err := session.handleLogon(msg); err != nil { switch err := err.(type) { case RejectLogon: - session.log.OnEvent(err.Text) - logout := session.buildLogout(err.Text) + return shutdownWithReason(session, msg, true, err.Error()) - if err := session.dropAndSendInReplyTo(logout, msg); err != nil { - session.logError(err) - } - - if err := session.store.IncrNextTargetMsgSeqNum(); err != nil { - session.logError(err) - } - - return latentState{} + case targetTooLow: + return shutdownWithReason(session, msg, false, err.Error()) case targetTooHigh: var tooHighErr error if nextState, tooHighErr = session.doTargetTooHigh(err); tooHighErr != nil { - return handleStateError(session, tooHighErr) + return shutdownWithReason(session, msg, false, tooHighErr.Error()) } return @@ -64,3 +56,20 @@ func (s logonState) Timeout(session *session, e internal.Event) (nextState sessi func (s logonState) Stop(session *session) (nextState sessionState) { return latentState{} } + +func shutdownWithReason(session *session, msg *Message, incrNextTargetMsgSeqNum bool, reason string) (nextState sessionState) { + session.log.OnEvent(reason) + logout := session.buildLogout(reason) + + if err := session.dropAndSendInReplyTo(logout, msg); err != nil { + session.logError(err) + } + + if incrNextTargetMsgSeqNum { + if err := session.store.IncrNextTargetMsgSeqNum(); err != nil { + session.logError(err) + } + } + + return latentState{} +} diff --git a/logon_state_test.go b/logon_state_test.go index 08da2e710..3ba29af1d 100644 --- a/logon_state_test.go +++ b/logon_state_test.go @@ -302,3 +302,31 @@ func (s *LogonStateTestSuite) TestFixMsgInLogonSeqNumTooHigh() { s.State(inSession{}) s.NextTargetMsgSeqNum(7) } + +func (s *LogonStateTestSuite) TestFixMsgInLogonSeqNumTooLow() { + s.IncrNextSenderMsgSeqNum() + s.IncrNextTargetMsgSeqNum() + + logon := s.Logon() + logon.Body.SetField(tagHeartBtInt, FIXInt(32)) + logon.Header.SetInt(tagMsgSeqNum, 1) + + s.MockApp.On("ToAdmin") + s.NextTargetMsgSeqNum(2) + s.fixMsgIn(s.session, logon) + + s.State(latentState{}) + s.NextTargetMsgSeqNum(2) + + s.MockApp.AssertNumberOfCalls(s.T(), "ToAdmin", 1) + msgBytesSent, ok := s.Receiver.LastMessage() + s.Require().True(ok) + sentMessage := NewMessage() + err := ParseMessage(sentMessage, bytes.NewBuffer(msgBytesSent)) + s.Require().Nil(err) + s.MessageType(string(msgTypeLogout), sentMessage) + + s.session.sendQueued() + s.MessageType(string(msgTypeLogout), s.MockApp.lastToAdmin) + s.FieldEquals(tagText, "MsgSeqNum too low, expecting 2 but received 1", s.MockApp.lastToAdmin.Body) +}