Skip to content

Commit a101c32

Browse files
Merge pull request #725 from JackChalmers/test-for-reset-seq-time
Send Reset if the ResetTime elapsed in between checks
2 parents 7863300 + cec0770 commit a101c32

File tree

3 files changed

+298
-9
lines changed

3 files changed

+298
-9
lines changed

session.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ type session struct {
6262
transportDataDictionary *datadictionary.DataDictionary
6363
appDataDictionary *datadictionary.DataDictionary
6464

65-
timestampPrecision TimestampPrecision
65+
timestampPrecision TimestampPrecision
66+
lastCheckedResetSeqTime time.Time
6667
}
6768

6869
func (s *session) logError(err error) {

session_state.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,27 @@ func (sm *stateMachine) CheckSessionTime(session *session, now time.Time) {
156156
}
157157

158158
func (sm *stateMachine) CheckResetTime(session *session, now time.Time) {
159-
if session.EnableResetSeqTime {
160-
if session.ResetSeqTime.Hour() == now.Hour() &&
161-
session.ResetSeqTime.Minute() == now.Minute() &&
162-
session.ResetSeqTime.Second() == now.Second() {
163-
session.sendLogonInReplyTo(true, nil)
164-
}
159+
// If the reset time is not enabled, we do nothing.
160+
if !session.EnableResetSeqTime {
161+
return
162+
}
163+
// If the last checked reset seq time is not set or we are not connected, we do nothing.
164+
if session.lastCheckedResetSeqTime.IsZero() || !session.stateMachine.State.IsConnected() {
165+
session.lastCheckedResetSeqTime = now
166+
return
165167
}
168+
169+
// Get the reset time for today
170+
nowInTimeZone := now.In(session.ResetSeqTime.Location())
171+
resetSeqTimeToday := time.Date(nowInTimeZone.Year(), nowInTimeZone.Month(), nowInTimeZone.Day(), session.ResetSeqTime.Hour(), session.ResetSeqTime.Minute(), session.ResetSeqTime.Second(), session.ResetSeqTime.Nanosecond(), session.ResetSeqTime.Location())
172+
173+
// If we have crossed the reset time boundary in between checks or we are at the reset time, we send the reset
174+
if session.lastCheckedResetSeqTime.Before(resetSeqTimeToday) && !now.Before(resetSeqTimeToday) {
175+
session.sendLogonInReplyTo(true, nil)
176+
}
177+
178+
// Update the last checked reset seq time to now
179+
session.lastCheckedResetSeqTime = now
166180
}
167181

168182
func (sm *stateMachine) setState(session *session, nextState sessionState) {

session_test.go

Lines changed: 276 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,20 +1010,24 @@ func (s *SessionSuite) TestSeqNumResetTime() {
10101010
s.session.ResetSeqTime = now
10111011
s.session.EnableResetSeqTime = true
10121012

1013+
s.NextSenderMsgSeqNum(1)
1014+
s.NextTargetMsgSeqNum(1)
10131015
s.IncrNextSenderMsgSeqNum()
10141016
s.IncrNextTargetMsgSeqNum()
10151017

10161018
s.MockApp.On("ToAdmin")
10171019

1020+
s.NextSenderMsgSeqNum(2)
1021+
s.NextTargetMsgSeqNum(2)
10181022
s.IncrNextSenderMsgSeqNum()
10191023
s.IncrNextTargetMsgSeqNum()
10201024

10211025
s.MockApp.On("ToAdmin")
10221026

10231027
s.session.CheckResetTime(s.session, now)
10241028

1025-
s.NextSenderMsgSeqNum(2)
1026-
s.NextSenderMsgSeqNum(2)
1029+
s.NextSenderMsgSeqNum(3)
1030+
s.NextSenderMsgSeqNum(3)
10271031

10281032
}
10291033

@@ -1052,3 +1056,273 @@ func (s *SessionSuite) TestSeqNumResetTimeDisconnected() {
10521056
s.NextSenderMsgSeqNum(2)
10531057
s.NextTargetMsgSeqNum(2)
10541058
}
1059+
1060+
func (s *SessionSuite) TestSeqNumResetTimeAfterElapse() {
1061+
s.session.State = logonState{}
1062+
before := time.Now().UTC()
1063+
resetTime := time.Now().UTC().Add(time.Second * 2)
1064+
after := resetTime.Add(time.Second * 1)
1065+
s.session.ResetSeqTime = resetTime
1066+
s.session.EnableResetSeqTime = true
1067+
1068+
s.NextSenderMsgSeqNum(1)
1069+
s.NextTargetMsgSeqNum(1)
1070+
s.IncrNextTargetMsgSeqNum()
1071+
s.IncrNextSenderMsgSeqNum()
1072+
s.NextSenderMsgSeqNum(2)
1073+
s.NextTargetMsgSeqNum(2)
1074+
1075+
s.MockApp.On("ToAdmin")
1076+
s.session.CheckResetTime(s.session, before)
1077+
s.NextSenderMsgSeqNum(2)
1078+
s.NextTargetMsgSeqNum(2)
1079+
1080+
s.session.lastCheckedResetSeqTime = before
1081+
s.session.CheckResetTime(s.session, after)
1082+
s.NextSenderMsgSeqNum(2)
1083+
s.NextTargetMsgSeqNum(1)
1084+
}
1085+
1086+
func (s *SessionSuite) TestSeqNumResetTimeNotAfterDisconnect() {
1087+
s.session.State = logonState{}
1088+
before := time.Now().UTC()
1089+
resetTime := before.Add(time.Second * 2)
1090+
after := resetTime.Add(time.Second * 1)
1091+
s.session.ResetSeqTime = resetTime
1092+
s.session.EnableResetSeqTime = true
1093+
1094+
s.NextSenderMsgSeqNum(1)
1095+
s.NextTargetMsgSeqNum(1)
1096+
s.IncrNextTargetMsgSeqNum()
1097+
s.IncrNextSenderMsgSeqNum()
1098+
s.NextSenderMsgSeqNum(2)
1099+
s.NextTargetMsgSeqNum(2)
1100+
1101+
s.MockApp.On("ToAdmin")
1102+
s.session.CheckResetTime(s.session, before)
1103+
s.NextSenderMsgSeqNum(2)
1104+
s.NextTargetMsgSeqNum(2)
1105+
1106+
s.session.onAdmin(stopReq{})
1107+
s.Disconnected()
1108+
s.Stopped()
1109+
1110+
s.session.lastCheckedResetSeqTime = before
1111+
s.session.CheckResetTime(s.session, after)
1112+
s.NextSenderMsgSeqNum(2)
1113+
s.NextTargetMsgSeqNum(2)
1114+
}
1115+
1116+
func (s *SessionSuite) TestSeqNumResetTimeDisconnected_LocalTZ() {
1117+
s.session.State = logonState{}
1118+
tz, err := time.LoadLocation("America/Chicago")
1119+
if err != nil {
1120+
s.T().Fatal(err)
1121+
}
1122+
s.session.TimeZone = tz
1123+
s.session.ResetSeqTime = time.Now().In(tz).Add(time.Second * 2)
1124+
s.session.EnableResetSeqTime = true
1125+
1126+
s.NextSenderMsgSeqNum(1)
1127+
s.NextTargetMsgSeqNum(1)
1128+
s.IncrNextTargetMsgSeqNum()
1129+
s.IncrNextSenderMsgSeqNum()
1130+
s.NextSenderMsgSeqNum(2)
1131+
s.NextTargetMsgSeqNum(2)
1132+
1133+
s.session.onAdmin(stopReq{})
1134+
s.Disconnected()
1135+
s.Stopped()
1136+
1137+
// Wait for reset time to pass.
1138+
time.Sleep(time.Second * 3)
1139+
1140+
s.MockApp.On("ToAdmin")
1141+
// Disconnected so the seq numbers should not be reset.
1142+
s.session.CheckResetTime(s.session, time.Now().UTC())
1143+
s.NextSenderMsgSeqNum(2)
1144+
s.NextTargetMsgSeqNum(2)
1145+
}
1146+
1147+
func (s *SessionSuite) TestSeqNumResetTimeAfterElapse_LocalTZ() {
1148+
s.session.State = logonState{}
1149+
tz, err := time.LoadLocation("America/Chicago")
1150+
if err != nil {
1151+
s.T().Fatal(err)
1152+
}
1153+
s.session.TimeZone = tz
1154+
before := time.Now().In(tz)
1155+
resetTime := before.Add(time.Second * 2)
1156+
after := resetTime.Add(time.Second * 1)
1157+
s.session.ResetSeqTime = resetTime
1158+
s.session.EnableResetSeqTime = true
1159+
1160+
s.NextSenderMsgSeqNum(1)
1161+
s.NextTargetMsgSeqNum(1)
1162+
s.IncrNextTargetMsgSeqNum()
1163+
s.IncrNextSenderMsgSeqNum()
1164+
s.NextSenderMsgSeqNum(2)
1165+
s.NextTargetMsgSeqNum(2)
1166+
1167+
s.MockApp.On("ToAdmin")
1168+
s.session.CheckResetTime(s.session, before)
1169+
s.NextSenderMsgSeqNum(2)
1170+
s.NextTargetMsgSeqNum(2)
1171+
1172+
s.session.lastCheckedResetSeqTime = before
1173+
s.session.CheckResetTime(s.session, after)
1174+
s.NextSenderMsgSeqNum(2)
1175+
s.NextTargetMsgSeqNum(1)
1176+
}
1177+
1178+
func (s *SessionSuite) TestSeqNumResetTimeNotAfterDisconnect_LocalTZ() {
1179+
s.session.State = logonState{}
1180+
tz, err := time.LoadLocation("America/Chicago")
1181+
if err != nil {
1182+
s.T().Fatal(err)
1183+
}
1184+
s.session.TimeZone = tz
1185+
before := time.Now().In(tz)
1186+
resetTime := before.Add(time.Second * 2)
1187+
after := resetTime.Add(time.Second * 1)
1188+
s.session.ResetSeqTime = resetTime
1189+
s.session.EnableResetSeqTime = true
1190+
1191+
s.NextSenderMsgSeqNum(1)
1192+
s.NextTargetMsgSeqNum(1)
1193+
s.IncrNextTargetMsgSeqNum()
1194+
s.IncrNextSenderMsgSeqNum()
1195+
s.NextSenderMsgSeqNum(2)
1196+
s.NextTargetMsgSeqNum(2)
1197+
1198+
s.MockApp.On("ToAdmin")
1199+
s.session.CheckResetTime(s.session, before)
1200+
s.NextSenderMsgSeqNum(2)
1201+
s.NextTargetMsgSeqNum(2)
1202+
1203+
s.session.onAdmin(stopReq{})
1204+
s.Disconnected()
1205+
s.Stopped()
1206+
1207+
s.session.lastCheckedResetSeqTime = before
1208+
s.session.CheckResetTime(s.session, after)
1209+
s.NextSenderMsgSeqNum(2)
1210+
s.NextTargetMsgSeqNum(2)
1211+
}
1212+
1213+
func (s *SessionSuite) TestSeqNumResetTimeAfterElapse_MultipleDaysLater() {
1214+
s.session.State = logonState{}
1215+
1216+
// Example Dates:
1217+
// ResetTime = 2025-06-08 10:15:30
1218+
// Before = 2025-07-10 10:15:29
1219+
// After = 2025-07-10 10:15:32
1220+
resetTime := time.Now()
1221+
before := resetTime.AddDate(0, 1, 2).Add(time.Second * -1)
1222+
after := resetTime.AddDate(0, 1, 2).Add(time.Second * 2)
1223+
1224+
s.session.ResetSeqTime = resetTime
1225+
s.session.EnableResetSeqTime = true
1226+
1227+
s.NextSenderMsgSeqNum(1)
1228+
s.NextTargetMsgSeqNum(1)
1229+
s.IncrNextTargetMsgSeqNum()
1230+
s.IncrNextSenderMsgSeqNum()
1231+
s.NextSenderMsgSeqNum(2)
1232+
s.NextTargetMsgSeqNum(2)
1233+
1234+
s.MockApp.On("ToAdmin")
1235+
s.session.CheckResetTime(s.session, before)
1236+
s.NextSenderMsgSeqNum(2)
1237+
s.NextTargetMsgSeqNum(2)
1238+
1239+
s.session.lastCheckedResetSeqTime = before
1240+
s.session.CheckResetTime(s.session, after)
1241+
s.NextSenderMsgSeqNum(2)
1242+
s.NextTargetMsgSeqNum(1)
1243+
}
1244+
1245+
func (s *SessionSuite) TestSeqNumResetTimeAtExactTime() {
1246+
s.session.State = logonState{}
1247+
resetTime := time.Now()
1248+
before := resetTime.Add(time.Second * -1)
1249+
1250+
s.session.ResetSeqTime = resetTime
1251+
s.session.EnableResetSeqTime = true
1252+
1253+
s.NextSenderMsgSeqNum(1)
1254+
s.NextTargetMsgSeqNum(1)
1255+
s.IncrNextTargetMsgSeqNum()
1256+
s.IncrNextSenderMsgSeqNum()
1257+
s.NextSenderMsgSeqNum(2)
1258+
s.NextTargetMsgSeqNum(2)
1259+
1260+
// We are before the reset time, so we should not reset the seq numbers
1261+
s.MockApp.On("ToAdmin")
1262+
s.session.CheckResetTime(s.session, before)
1263+
s.NextSenderMsgSeqNum(2)
1264+
s.NextTargetMsgSeqNum(2)
1265+
1266+
// We check the reset time exactly at the configured time, so we reset
1267+
s.session.lastCheckedResetSeqTime = before
1268+
s.session.CheckResetTime(s.session, resetTime)
1269+
s.NextSenderMsgSeqNum(2)
1270+
s.NextTargetMsgSeqNum(1)
1271+
}
1272+
1273+
func (s *SessionSuite) TestSeqNumResetTimePreviousCheck() {
1274+
s.session.State = logonState{}
1275+
resetTime := time.Now()
1276+
before := resetTime.Add(time.Second * -1)
1277+
after := resetTime.Add(time.Second * 1)
1278+
1279+
s.session.ResetSeqTime = resetTime
1280+
s.session.EnableResetSeqTime = true
1281+
1282+
s.NextSenderMsgSeqNum(1)
1283+
s.NextTargetMsgSeqNum(1)
1284+
s.IncrNextTargetMsgSeqNum()
1285+
s.IncrNextSenderMsgSeqNum()
1286+
s.NextSenderMsgSeqNum(2)
1287+
s.NextTargetMsgSeqNum(2)
1288+
1289+
// We are before the reset time, so we should not reset the seq numbers
1290+
s.MockApp.On("ToAdmin")
1291+
s.session.CheckResetTime(s.session, before)
1292+
s.NextSenderMsgSeqNum(2)
1293+
s.NextTargetMsgSeqNum(2)
1294+
1295+
// We just checked the reset time at the configured time, so we do not reset the seq num for the next check
1296+
s.session.lastCheckedResetSeqTime = resetTime
1297+
s.session.CheckResetTime(s.session, after)
1298+
s.NextSenderMsgSeqNum(2)
1299+
s.NextTargetMsgSeqNum(2)
1300+
}
1301+
1302+
func (s *SessionSuite) TestSeqNumResetTime_NanoSeconds() {
1303+
s.session.State = logonState{}
1304+
resetTime := time.Now()
1305+
// Nanoseconds are not used in the resetSeqTime, but are referenced in the comparison of before/after
1306+
before := resetTime.Add(time.Nanosecond * -1)
1307+
after := resetTime.Add(time.Nanosecond * 1)
1308+
1309+
s.session.ResetSeqTime = resetTime
1310+
s.session.EnableResetSeqTime = true
1311+
1312+
s.NextSenderMsgSeqNum(1)
1313+
s.NextTargetMsgSeqNum(1)
1314+
s.IncrNextTargetMsgSeqNum()
1315+
s.IncrNextSenderMsgSeqNum()
1316+
s.NextSenderMsgSeqNum(2)
1317+
s.NextTargetMsgSeqNum(2)
1318+
1319+
s.MockApp.On("ToAdmin")
1320+
s.session.CheckResetTime(s.session, before)
1321+
s.NextSenderMsgSeqNum(2)
1322+
s.NextTargetMsgSeqNum(2)
1323+
1324+
s.session.lastCheckedResetSeqTime = before
1325+
s.session.CheckResetTime(s.session, after)
1326+
s.NextSenderMsgSeqNum(2)
1327+
s.NextTargetMsgSeqNum(1)
1328+
}

0 commit comments

Comments
 (0)