Skip to content

Commit 44aff93

Browse files
committed
Move verification flag logic to verification module
1 parent 63d7452 commit 44aff93

8 files changed

Lines changed: 169 additions & 164 deletions

File tree

crates/hotfix/src/message/verification.rs

Lines changed: 120 additions & 40 deletions
Large diffs are not rendered by default.

crates/hotfix/src/session.rs

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::message::reject::Reject;
3434
use crate::message::resend_request::ResendRequest;
3535
use crate::message::sequence_reset::SequenceReset;
3636
use crate::message::test_request::TestRequest;
37+
use crate::message::verification::VerificationFlags;
3738
use crate::session::admin_request::AdminRequest;
3839
use crate::session::ctx::{SessionCtx, TransitionResult, VerificationResult};
3940
use crate::session::error::SessionCreationError;
@@ -53,9 +54,7 @@ use crate::store::MessageStore;
5354
use crate::transport::writer::WriterRef;
5455
use event::SessionEvent;
5556
use hotfix_message::parsed_message::{InvalidReason, ParsedMessage};
56-
use hotfix_message::session_fields::{
57-
GAP_FILL_FLAG, MSG_SEQ_NUM, MSG_TYPE, SessionRejectReason, TEST_REQ_ID,
58-
};
57+
use hotfix_message::session_fields::{MSG_SEQ_NUM, MSG_TYPE, SessionRejectReason, TEST_REQ_ID};
5958

6059
const SCHEDULE_CHECK_INTERVAL: u64 = 1;
6160

@@ -208,38 +207,24 @@ where
208207
}
209208
}
210209

211-
if let SessionState::AwaitingLogon(_) = &mut self.state {
212-
if message_type != Logon::MSG_TYPE {
213-
self.state.disconnect_writer().await;
214-
return Ok(());
215-
}
210+
// TODO: add state-level pre-process check that validates whether the message type
211+
// is acceptable in the current state (e.g. AwaitingLogon rejects non-Logon,
212+
// unexpected Logon in Active should be rejected per FIX spec).
213+
if let SessionState::AwaitingLogon(_) = &mut self.state
214+
&& message_type != Logon::MSG_TYPE
215+
{
216+
self.state.disconnect_writer().await;
217+
return Ok(());
216218
}
217219

218-
// Logon has its own verification inside the AwaitingLogon guard
219-
if message_type != Logon::MSG_TYPE {
220-
let (check_too_high, check_too_low) = match message_type {
221-
// check_too_high=false: QFJ-673 deadlock fix. When both sides send
222-
// ResendRequest simultaneously, each side's ResendRequest will have a seq
223-
// number higher than expected. By not treating that as an error, we allow
224-
// the ResendRequest to be processed.
225-
ResendRequest::MSG_TYPE => (false, true),
226-
Reject::MSG_TYPE => (false, true),
227-
Logout::MSG_TYPE => (false, false),
228-
SequenceReset::MSG_TYPE => {
229-
let is_gap_fill: bool = message.get(GAP_FILL_FLAG).unwrap_or(false);
230-
(is_gap_fill, is_gap_fill)
231-
}
232-
_ => (true, true),
233-
};
234-
235-
if let VerificationResult::Issue(result) = self
236-
.state
237-
.handle_verification_issue(&mut self.ctx, &message, check_too_high, check_too_low)
238-
.await?
239-
{
240-
self.apply_transition(result);
241-
return Ok(());
242-
}
220+
let flags = VerificationFlags::for_message(&message)?;
221+
if let VerificationResult::Issue(result) = self
222+
.state
223+
.handle_verification_issue(&mut self.ctx, &message, flags)
224+
.await?
225+
{
226+
self.apply_transition(result);
227+
return Ok(());
243228
}
244229

245230
match message_type {
@@ -262,7 +247,7 @@ where
262247
self.on_logout().await?;
263248
}
264249
Logon::MSG_TYPE => {
265-
self.on_logon(&message).await?;
250+
self.on_logon().await?;
266251
}
267252
_ => self.process_app_message(&message).await?,
268253
}
@@ -371,25 +356,13 @@ where
371356
}
372357
}
373358

374-
async fn on_logon(&mut self, message: &Message) -> Result<(), SessionOperationError> {
359+
async fn on_logon(&mut self) -> Result<(), SessionOperationError> {
375360
if let SessionState::AwaitingLogon(AwaitingLogonState { writer, .. }) = &self.state {
376361
let writer = writer.clone();
377-
match self
378-
.state
379-
.handle_verification_issue(&mut self.ctx, message, true, true)
380-
.await?
381-
{
382-
VerificationResult::Issue(result) => {
383-
self.apply_transition(result);
384-
}
385-
VerificationResult::Passed => {
386-
// happy logon flow, the session is now active
387-
self.state =
388-
SessionState::new_active(writer, self.ctx.config.heartbeat_interval);
389-
self.ctx.application.on_logon().await;
390-
self.ctx.store.increment_target_seq_number().await?;
391-
}
392-
}
362+
// happy logon flow, the session is now active
363+
self.state = SessionState::new_active(writer, self.ctx.config.heartbeat_interval);
364+
self.ctx.application.on_logon().await;
365+
self.ctx.store.increment_target_seq_number().await?;
393366
} else {
394367
error!("received unexpected logon message");
395368
}

crates/hotfix/src/session/inbound.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::message::heartbeat::Heartbeat;
22
use crate::message::logout::Logout;
33
use crate::message::reject::Reject;
4-
use crate::message::verification::verify_message;
4+
use crate::message::verification::{VerificationFlags, verify_message};
55
use crate::message::verification_issue::{CompIdType, MessageError, VerificationIssue};
66
use crate::session::ctx::{SessionCtx, TransitionResult};
77
use crate::session::error::{InternalSendResultExt, SessionOperationError};
@@ -21,21 +21,14 @@ use tracing::warn;
2121
fn verify_message_with_ctx<A, S: MessageStore>(
2222
ctx: &SessionCtx<A, S>,
2323
message: &Message,
24-
check_too_high: bool,
25-
check_too_low: bool,
24+
flags: VerificationFlags,
2625
) -> Result<(), VerificationIssue> {
27-
let expected_seq_number = if check_too_high || check_too_low {
26+
let expected_seq_number = if flags.requires_sequence_number() {
2827
Some(ctx.store.next_target_seq_number())
2928
} else {
3029
None
3130
};
32-
verify_message(
33-
message,
34-
&ctx.config,
35-
expected_seq_number,
36-
check_too_high,
37-
check_too_low,
38-
)
31+
verify_message(message, &ctx.config, expected_seq_number, flags)
3932
}
4033

4134
/// The result of verifying an inbound message after handling message errors.
@@ -62,11 +55,10 @@ pub(crate) async fn verify_and_handle_errors<A, S: MessageStore>(
6255
ctx: &mut SessionCtx<A, S>,
6356
writer: &WriterRef,
6457
message: &Message,
65-
check_too_high: bool,
66-
check_too_low: bool,
58+
flags: VerificationFlags,
6759
) -> VerificationOutcome {
68-
match verify_message_with_ctx(ctx, message, check_too_high, check_too_low) {
69-
Result::Ok(()) => VerificationOutcome::Ok,
60+
match verify_message_with_ctx(ctx, message, flags) {
61+
Ok(()) => VerificationOutcome::Ok,
7062
Err(VerificationIssue::SequenceGap { expected, actual }) => {
7163
VerificationOutcome::SequenceGap { expected, actual }
7264
}

crates/hotfix/src/session/state.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::Application;
1414
use crate::message::OutboundMessage;
1515
use crate::message::logon::Logon;
1616
use crate::message::logout::Logout;
17+
use crate::message::verification::VerificationFlags;
1718
use crate::session::ctx::{SessionCtx, VerificationResult};
1819
use crate::session::error::{InternalSendError, InternalSendResultExt, SessionOperationError};
1920
use crate::session::event::ScheduleResponse;
@@ -169,29 +170,20 @@ impl SessionState {
169170
&mut self,
170171
ctx: &mut SessionCtx<A, S>,
171172
message: &Message,
172-
check_too_high: bool,
173-
check_too_low: bool,
173+
flags: VerificationFlags,
174174
) -> Result<VerificationResult, SessionOperationError> {
175175
match self {
176176
SessionState::Active(state) => {
177-
state
178-
.handle_verification_issue(ctx, message, check_too_high, check_too_low)
179-
.await
177+
state.handle_verification_issue(ctx, message, flags).await
180178
}
181179
SessionState::AwaitingResend(state) => {
182-
state
183-
.handle_verification_issue(ctx, message, check_too_high, check_too_low)
184-
.await
180+
state.handle_verification_issue(ctx, message, flags).await
185181
}
186182
SessionState::AwaitingLogon(state) => {
187-
state
188-
.handle_verification_issue(ctx, message, check_too_high, check_too_low)
189-
.await
183+
state.handle_verification_issue(ctx, message, flags).await
190184
}
191185
SessionState::AwaitingLogout(state) => {
192-
state
193-
.handle_verification_issue(ctx, message, check_too_high, check_too_low)
194-
.await
186+
state.handle_verification_issue(ctx, message, flags).await
195187
}
196188
SessionState::Disconnected(_) => {
197189
error!("handle_verification_issue called while disconnected");

crates/hotfix/src/session/state/active.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::Application;
22
use crate::message::resend_request::ResendRequest;
3+
use crate::message::verification::VerificationFlags;
34
use crate::session::ctx::{SessionCtx, TransitionResult, VerificationResult};
45
use crate::session::error::{InternalSendResultExt, SessionOperationError};
56
use crate::session::inbound::{self, VerificationOutcome};
@@ -27,18 +28,9 @@ impl ActiveState {
2728
&self,
2829
ctx: &mut SessionCtx<A, S>,
2930
message: &Message,
30-
check_too_high: bool,
31-
check_too_low: bool,
31+
flags: VerificationFlags,
3232
) -> Result<VerificationResult, SessionOperationError> {
33-
match inbound::verify_and_handle_errors(
34-
ctx,
35-
&self.writer,
36-
message,
37-
check_too_high,
38-
check_too_low,
39-
)
40-
.await
41-
{
33+
match inbound::verify_and_handle_errors(ctx, &self.writer, message, flags).await {
4234
VerificationOutcome::Ok => Ok(VerificationResult::Passed),
4335
VerificationOutcome::Handled(result) => Ok(VerificationResult::Issue(result)),
4436
VerificationOutcome::SequenceGap { expected, actual } => {

crates/hotfix/src/session/state/awaiting_logon.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::Application;
22
use crate::message::resend_request::ResendRequest;
3+
use crate::message::verification::VerificationFlags;
34
use crate::session::ctx::{SessionCtx, TransitionResult, VerificationResult};
45
use crate::session::error::{InternalSendResultExt, SessionOperationError};
56
use crate::session::inbound::{self, VerificationOutcome};
@@ -25,18 +26,9 @@ impl AwaitingLogonState {
2526
&self,
2627
ctx: &mut SessionCtx<A, S>,
2728
message: &Message,
28-
check_too_high: bool,
29-
check_too_low: bool,
29+
flags: VerificationFlags,
3030
) -> Result<VerificationResult, SessionOperationError> {
31-
match inbound::verify_and_handle_errors(
32-
ctx,
33-
&self.writer,
34-
message,
35-
check_too_high,
36-
check_too_low,
37-
)
38-
.await
39-
{
31+
match inbound::verify_and_handle_errors(ctx, &self.writer, message, flags).await {
4032
VerificationOutcome::Ok => Ok(VerificationResult::Passed),
4133
VerificationOutcome::Handled(result) => Ok(VerificationResult::Issue(result)),
4234
VerificationOutcome::SequenceGap { expected, actual } => {

crates/hotfix/src/session/state/awaiting_logout.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::Application;
2+
use crate::message::verification::VerificationFlags;
23
use crate::session::ctx::{SessionCtx, TransitionResult, VerificationResult};
34
use crate::session::error::SessionOperationError;
45
use crate::session::inbound::{self, VerificationOutcome};
@@ -22,18 +23,9 @@ impl AwaitingLogoutState {
2223
&self,
2324
ctx: &mut SessionCtx<A, S>,
2425
message: &Message,
25-
check_too_high: bool,
26-
check_too_low: bool,
26+
flags: VerificationFlags,
2727
) -> Result<VerificationResult, SessionOperationError> {
28-
match inbound::verify_and_handle_errors(
29-
ctx,
30-
&self.writer,
31-
message,
32-
check_too_high,
33-
check_too_low,
34-
)
35-
.await
36-
{
28+
match inbound::verify_and_handle_errors(ctx, &self.writer, message, flags).await {
3729
VerificationOutcome::Ok => Ok(VerificationResult::Passed),
3830
VerificationOutcome::Handled(result) => Ok(VerificationResult::Issue(result)),
3931
VerificationOutcome::SequenceGap { expected, actual } => {

crates/hotfix/src/session/state/awaiting_resend.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::Application;
22
use crate::message::resend_request::ResendRequest;
3+
use crate::message::verification::VerificationFlags;
34
use crate::session::ctx::{SessionCtx, TransitionResult, VerificationResult};
45
use crate::session::error::{InternalSendResultExt, SessionOperationError};
56
use crate::session::inbound::{self, VerificationOutcome};
@@ -42,18 +43,9 @@ impl AwaitingResendState {
4243
&mut self,
4344
ctx: &mut SessionCtx<A, S>,
4445
message: &Message,
45-
check_too_high: bool,
46-
check_too_low: bool,
46+
flags: VerificationFlags,
4747
) -> Result<VerificationResult, SessionOperationError> {
48-
match inbound::verify_and_handle_errors(
49-
ctx,
50-
&self.writer,
51-
message,
52-
check_too_high,
53-
check_too_low,
54-
)
55-
.await
56-
{
48+
match inbound::verify_and_handle_errors(ctx, &self.writer, message, flags).await {
5749
VerificationOutcome::Ok => Ok(VerificationResult::Passed),
5850
VerificationOutcome::Handled(result) => Ok(VerificationResult::Issue(result)),
5951
VerificationOutcome::SequenceGap { expected, actual } => {

0 commit comments

Comments
 (0)