Skip to content

Commit b058e88

Browse files
committed
Individually increment target sequence number in message type specific branches
1 parent 1e540b2 commit b058e88

2 files changed

Lines changed: 38 additions & 22 deletions

File tree

crates/hotfix/src/session.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -243,51 +243,49 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
243243

244244
match message_type {
245245
"0" => {
246-
self.on_heartbeat(&message).await;
246+
self.on_heartbeat(&message).await?;
247247
}
248248
"1" => {
249-
self.on_test_request(&message).await;
249+
self.on_test_request(&message).await?;
250250
}
251251
"2" => {
252-
self.on_resend_request(&message).await;
252+
self.on_resend_request(&message).await?;
253253
}
254254
"3" => {
255-
if !self.on_reject(&message).await {
256-
return Ok(());
257-
}
255+
self.on_reject(&message).await?;
258256
}
259257
"4" => {
260258
self.on_sequence_reset(&message).await;
261-
return Ok(()); // early return as we don't need to increment target seq number
262259
}
263260
"5" => {
264-
self.on_logout().await;
261+
self.on_logout().await?;
265262
}
266263
"A" => {
267264
self.on_logon(&message).await?;
268-
return Ok(());
269265
}
270-
_ => self.process_app_message(&message).await,
266+
_ => self.process_app_message(&message).await?,
271267
}
272268

273-
self.store.increment_target_seq_number().await?;
274269
Ok(())
275270
}
276271

277-
async fn process_app_message(&mut self, message: &Message) {
272+
async fn process_app_message(&mut self, message: &Message) -> Result<()> {
278273
match self.verify_message(message).await {
279274
Ok(_) => {
280275
let parsed_message = M::parse(message);
281276
let app_message = ApplicationMessage::ReceivedMessage(parsed_message);
282277
self.application.send_message(app_message).await;
278+
self.store.increment_target_seq_number().await?;
283279
}
284280
Err(err) => self.handle_verification_error(err).await,
285281
}
282+
283+
Ok(())
286284
}
287285

288286
async fn check_end_of_resend(&mut self) -> Result<()> {
289287
let ended_state = if let SessionState::AwaitingResend(state) = &mut self.state {
290-
if self.store.next_target_seq_number() > state.end_seq_number + 1 {
288+
if self.store.next_target_seq_number() > state.end_seq_number {
291289
let new_state =
292290
SessionState::new_active(state.writer.clone(), self.config.heartbeat_interval);
293291
Some(std::mem::replace(&mut self.state, new_state))
@@ -401,7 +399,7 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
401399
Ok(())
402400
}
403401

404-
async fn on_logout(&mut self) {
402+
async fn on_logout(&mut self) -> Result<()> {
405403
if let SessionState::AwaitingLogout { .. } = &self.state {
406404
self.state.disconnect().await;
407405
self.state = SessionState::new_disconnected(true, "we logged out gracefully");
@@ -413,9 +411,10 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
413411
.send_logout("peer has logged us out".to_string())
414412
.await;
415413
}
414+
self.store.increment_target_seq_number().await
416415
}
417416

418-
async fn on_heartbeat(&mut self, message: &Message) {
417+
async fn on_heartbeat(&mut self, message: &Message) -> Result<()> {
419418
if let (Some(expected_req_id), Ok(message_req_id)) = (
420419
&self.state.expected_test_response_id(),
421420
message.get::<&str>(fix44::TEST_REQ_ID),
@@ -424,19 +423,25 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
424423
debug!("received response for TestRequest, resetting timer");
425424
self.reset_peer_timer(None);
426425
}
426+
427+
self.store.increment_target_seq_number().await
427428
}
428429

429-
async fn on_test_request(&mut self, message: &Message) {
430+
async fn on_test_request(&mut self, message: &Message) -> Result<()> {
430431
let req_id: &str = message.get(fix44::TEST_REQ_ID).unwrap_or_else(|_| {
431432
// TODO: send reject?
432433
todo!()
433434
});
434435

436+
self.store.increment_target_seq_number().await?;
437+
435438
self.send_message(Heartbeat::for_request(req_id.to_string()))
436439
.await;
440+
441+
Ok(())
437442
}
438443

439-
async fn on_resend_request(&mut self, message: &Message) {
444+
async fn on_resend_request(&mut self, message: &Message) -> Result<()> {
440445
// TODO: verify message and send reject as necessary
441446

442447
let begin_seq_number: usize = message.get(fix44::BEGIN_SEQ_NO).unwrap_or_else(|_| {
@@ -459,20 +464,26 @@ impl<M: FixMessage, S: MessageStore> Session<M, S> {
459464
}
460465
};
461466

467+
self.store.increment_target_seq_number().await?;
468+
462469
self.resend_messages(begin_seq_number, end_seq_number, message)
463470
.await;
471+
472+
Ok(())
464473
}
465474

466475
/// Handle Reject messages.
467476
///
468477
/// Returns whether the message should be processed as usual
469478
/// and whether the target sequence number should be incremented.
470-
async fn on_reject(&self, message: &Message) -> bool {
471-
if let Ok(seq_num) = message.get::<u64>(fix44::MSG_SEQ_NUM) {
472-
seq_num == self.store.next_target_seq_number()
473-
} else {
474-
false
479+
async fn on_reject(&mut self, message: &Message) -> Result<()> {
480+
if let Ok(seq_num) = message.get::<u64>(fix44::MSG_SEQ_NUM)
481+
&& seq_num == self.store.next_target_seq_number()
482+
{
483+
self.store.increment_target_seq_number().await?;
475484
}
485+
486+
Ok(())
476487
}
477488

478489
async fn on_sequence_reset(&mut self, message: &Message) {

crates/hotfix/tests/session_test_cases/resend_tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ async fn test_message_sequence_number_too_high() {
2626
.then_receives(|msg| assert_eq!(msg.header().get::<&str>(MSG_TYPE).unwrap(), "2"))
2727
.await;
2828

29+
// the first message is the logon message, which doesn't need to be resent
30+
mock_counterparty.when_message_is_resent(2).await; // the missed message is resent
31+
mock_counterparty.when_message_is_resent(3).await; // the second message is resent
32+
session.then_status_changes_to(Status::Active).await;
33+
2934
session.when_disconnect_is_requested().await;
3035
mock_counterparty.then_gets_disconnected().await;
3136
}

0 commit comments

Comments
 (0)