Skip to content

Commit 4a5483d

Browse files
committed
session: improve heartbeat interval handling
1 parent 289331e commit 4a5483d

4 files changed

Lines changed: 30 additions & 24 deletions

File tree

easyfix-session/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ pub enum DisconnectReason {
5555
MsgSeqNumTooLow,
5656
/// Invalid logon state
5757
InvalidLogonState,
58+
/// Invalid COMP ID
59+
InvalidCompId,
60+
/// Invalid OrigSendingTime
61+
InvalidOrigSendingTime,
5862
/// Remote side disconnected
5963
Disconnected,
6064
/// I/O Error

easyfix-session/src/session.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::{cell::RefCell, rc::Rc};
1+
use std::{
2+
cell::{Cell, RefCell},
3+
rc::Rc,
4+
};
25

36
use easyfix_messages::{
47
fields::{
@@ -152,6 +155,8 @@ pub(crate) struct Session<S> {
152155
settings: Settings,
153156
session_settings: SessionSettings,
154157
emitter: Emitter,
158+
// Not in SessionState as I/O layer asks for this value often
159+
heartbeat_interval: Cell<u64>,
155160
}
156161

157162
impl<S: MessagesStorage> Session<S> {
@@ -162,12 +167,16 @@ impl<S: MessagesStorage> Session<S> {
162167
sender: Sender,
163168
emitter: Emitter,
164169
) -> Session<S> {
170+
let heartbeat_interval = settings
171+
.heartbeat_interval
172+
.unwrap_or(settings.auto_disconnect_after_no_logout.as_secs());
165173
Session {
166174
state,
167175
settings,
168176
session_settings,
169177
sender,
170178
emitter,
179+
heartbeat_interval: Cell::new(heartbeat_interval),
171180
}
172181
}
173182

@@ -385,7 +394,7 @@ impl<S: MessagesStorage> Session<S> {
385394
self.send(Box::new(Message::Logon(Logon {
386395
// encrypt_method: EncryptMethod::None,
387396
encrypt_method: EncryptMethod::NoneOther,
388-
heart_bt_int: state.heart_bt_int(),
397+
heart_bt_int: self.heartbeat_interval.get().try_into().unwrap_or(Int::MAX),
389398
reset_seq_num_flag: self.should_send_reset(state).then_some(true),
390399
next_expected_msg_seq_num: if self.session_settings.enable_next_expected_msg_seq_num {
391400
let next_expected_msg_seq_num = state.next_sender_msg_seq_num();
@@ -406,8 +415,7 @@ impl<S: MessagesStorage> Session<S> {
406415

407416
self.send(Box::new(Message::Logon(Logon {
408417
encrypt_method: EncryptMethod::NoneOther,
409-
// TODO: option to use predefined OR the value from Logon request
410-
heart_bt_int: state.heart_bt_int(),
418+
heart_bt_int: self.heartbeat_interval.get().try_into().unwrap_or(Int::MAX),
411419
reset_seq_num_flag: self.should_send_reset(state).then_some(true),
412420
next_expected_msg_seq_num,
413421
// TODO: if self.session_settings.session_id().is_fixt()
@@ -965,8 +973,17 @@ impl<S: MessagesStorage> Session<S> {
965973
!Self::is_target_too_high(&state, msg_seq_num) || self.session_settings.reset_on_logon;
966974

967975
if !state.initiate() || (state.reset_received() && !state.reset_sent()) {
968-
state.set_heart_bt_int(heart_bt_int);
969976
info!("Received logon request");
977+
if self.settings.heartbeat_interval.is_none() {
978+
if heart_bt_int <= 0 {
979+
return Err(VerifyError::Reject {
980+
reason: SessionRejectReason::ValueIsIncorrect,
981+
tag: Some(FieldTag::HeartBtInt),
982+
disconnect_reason: None,
983+
});
984+
}
985+
self.heartbeat_interval.set(heart_bt_int as u64);
986+
}
970987

971988
if enable_next_expected_msg_seq_num {
972989
let mut next_expected_target_num = state.next_target_msg_seq_num();
@@ -1375,11 +1392,7 @@ impl<S: MessagesStorage> Session<S> {
13751392
}
13761393

13771394
pub fn heartbeat_interval(&self) -> Duration {
1378-
// TODO: logon.heartbeat_interval, value from settings is for n8 only (implement as Reject
1379-
// on Logon)
1395+
Duration::from_secs(self.heartbeat_interval.get())
13801396

1381-
//let inbound_test_request_timeout_duration =
1382-
// self.settings.heartbeat_interval + NO_INBOUND_TIMEOUT_PADDING;
1383-
self.settings.heartbeat_interval
13841397
}
13851398
}

easyfix-session/src/session_state.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
};
55

66
use easyfix_messages::{
7-
fields::{FixString, Int, SeqNum},
7+
fields::{FixString, SeqNum},
88
messages::FixtMessage,
99
};
1010
use tokio::time::Instant;
@@ -47,7 +47,6 @@ pub(crate) struct State<S> {
4747
reset_received: bool,
4848
initiate: bool,
4949
resend_range: Option<RangeInclusive<SeqNum>>,
50-
heart_bt_int: Int,
5150
last_sent_time: Instant,
5251
last_received_time: Instant,
5352

@@ -78,7 +77,6 @@ impl<S: MessagesStorage> State<S> {
7877
reset_received: false,
7978
initiate: false,
8079
resend_range: None,
81-
heart_bt_int: 10,
8280
last_sent_time: Instant::now(),
8381
last_received_time: Instant::now(),
8482
disconnected: true,
@@ -151,14 +149,6 @@ impl<S: MessagesStorage> State<S> {
151149
self.resend_range.clone()
152150
}
153151

154-
pub fn heart_bt_int(&self) -> Int {
155-
self.heart_bt_int
156-
}
157-
158-
pub fn set_heart_bt_int(&mut self, heart_bt_int: Int) {
159-
self.heart_bt_int = heart_bt_int;
160-
}
161-
162152
pub fn set_last_sent_time(&mut self, last_sent_time: Instant) {
163153
self.last_sent_time = last_sent_time;
164154
}

easyfix-session/src/settings.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ pub struct Settings {
2323
pub sender_sub_id: Option<FixString>,
2424
/// Timeout \[s\] for inbound/outbound messages. When reached, `TestRequest<1>`
2525
/// is sent when inbound message is missing or `Heartbeat<0>` is sent when
26-
/// outbound message is missing.
27-
#[serde(deserialize_with = "duration_from_seconds")]
28-
pub heartbeat_interval: Duration,
26+
/// outbound message is missing. If not set value from Logon<A> will be used.
27+
pub heartbeat_interval: Option<u64>,
2928
/// Timeout \[s\] for `Logon<A>` message, when reached, connection is dropped.
3029
#[serde(deserialize_with = "duration_from_seconds")]
3130
pub auto_disconnect_after_no_logon_received: Duration,

0 commit comments

Comments
 (0)