30 #include <string_view>
32 #include <type_traits>
38 #include <unordered_map>
40 #include "core/compiler/hints_hot_code.h"
41 #include "core/compiler/hints_branch_predictor.h"
43 #include "core/os/vdso.h"
45 #include "core/utilities/logger.h"
46 #include "core/utilities/object_cache.h"
47 #include "core/utilities/spsc_bounded_queue.h"
48 #include "core/utilities/std_string_utilities.h"
49 #include "core/utilities/configuration.h"
50 #include "core/utilities/userspace_spinlock.h"
52 #include "electronic_trading/common/message_serialiser.h"
54 #include "electronic_trading/session/session_state.h"
55 #include "electronic_trading/session/sequence_store.h"
56 #include "electronic_trading/session/session_schedule_validator.h"
57 #include "electronic_trading/session/throttler.h"
59 #include "electronic_trading/managed_instance/managed_instance_session.h"
60 #include "electronic_trading/managed_instance/modifying_admin_command.h"
62 #include "fix_constants.h"
63 #include "fix_string.h"
64 #include "fix_string_view.h"
65 #include "fix_utilities.h"
66 #include "fix_session_settings.h"
67 #include "fix_parser_error_codes.h"
68 #include "incoming_fix_repeating_group_specs.h"
69 #include "incoming_fix_message.h"
70 #include "outgoing_fix_message.h"
72 #ifdef LLFIX_ENABLE_DICTIONARY // VOLTRON_EXCLUDE
73 #include "fix_dictionary.h"
74 #include "fix_dictionary_loader.h"
75 #include "fix_dictionary_validator.h"
76 #endif // VOLTRON_EXCLUDE
78 #ifdef LLFIX_ENABLE_BINARY_FIELDS // VOLTRON_EXCLUDE
79 #include "incoming_fix_binary_field_specs.h"
80 #endif // VOLTRON_EXCLUDE
85 using MessageSerialiserType = MessageSerialiser<FixMessageSequenceNumberExtractor>;
103 m_sequence_store.save_to_disc();
105 if (m_tx_encode_buffer)
107 Allocator::deallocate(m_tx_encode_buffer, m_settings.tx_encode_buffer_capacity);
108 m_tx_encode_buffer =
nullptr;
112 bool initialise(
const std::string& name,
const FixSessionSettings& settings)
117 if(m_name.length()==0)
119 LLFIX_LOG_ERROR(
"Session names can't be empty");
123 if(m_name.length()>32)
125 LLFIX_LOG_ERROR(
"Session names can have max 32 characters. Failed name : " + m_name);
129 if (settings.validate() ==
false)
131 LLFIX_LOG_ERROR(
"FixSessionSettings for session " + m_name +
" validation failed : " + settings.validation_error);
137 m_settings = settings;
139 m_incoming_throttler_exceed_count = 0;
141 set_state(SessionState::DISCONNECTED);
143 if (m_settings.schedule_week_days.length() > 0) m_schedule_validator.add_allowed_weekdays_from_dash_separated_string(m_settings.schedule_week_days);
144 m_schedule_validator.set_start_and_end_times(m_settings.start_hour_utc, m_settings.start_minute_utc, m_settings.end_hour_utc, m_settings.end_minute_utc);
146 if (m_admin_commands.create(128) ==
false)
148 LLFIX_LOG_ERROR(
"Failed to create admin commands queue for session " + m_name);
152 if(m_settings.throttle_limit>0)
154 if (m_throttler.initialise(m_settings.throttle_window_in_milliseconds * 1
'000'000, m_settings.throttle_limit) ==
false)
156 LLFIX_LOG_ERROR(
"Session " + m_name +
" : failed to initialise throttler. Check the throttle_limit config.");
161 if (open_or_create_sequence_store(m_settings.sequence_store_file_path) ==
false)
163 LLFIX_LOG_ERROR(
"Session " + m_name +
" : failed to initialise sequence store. Check the sequence_store_file_path config.");
167 if(m_settings.max_serialised_file_size > 0)
169 if (m_incoming_messages_serialiser.initialise(m_settings.incoming_message_serialisation_path, m_settings.max_serialised_file_size,
false) ==
false)
171 LLFIX_LOG_ERROR(
"Session " + m_name +
" : failed to initialise incoming message serialiser. Check serialisation path and serialised file max size configs.");
175 if (m_outgoing_messages_serialiser.initialise(m_settings.outgoing_message_serialisation_path, m_settings.max_serialised_file_size, m_settings.replay_messages_on_incoming_resend_request, m_settings.replay_message_cache_initial_size) ==
false)
177 LLFIX_LOG_ERROR(
"Session " + m_name +
" : failed to initialise incoming message serialiser. Check serialisation path and serialised file max size configs.");
184 LLFIX_LOG_ERROR(
"Session " + m_name +
" : OutgoingFixMessage creation failed.");
188 if (m_incoming_fix_message.initialise() ==
false)
190 LLFIX_LOG_ERROR(
"Session " + m_name +
" : IncomingFixMessage creation failed.");
194 if (m_fix_string_view_cache.create(1024) ==
false)
196 LLFIX_LOG_ERROR(
"Session " + m_name +
" : FixStringView cache creation failed.");
200 m_tx_encode_buffer =
reinterpret_cast<char*
>(Allocator::allocate(m_settings.tx_encode_buffer_capacity));
202 if (m_tx_encode_buffer ==
nullptr)
204 LLFIX_LOG_ERROR(
"Session " + m_name +
" : TX encode buffer allocation failed");
208 catch (
const std::bad_alloc&)
210 LLFIX_LOG_FATAL(
"Session " + m_name +
" : Insufficient memory.");
216 if (m_settings.additional_static_header_tags.length() > 0)
218 auto tag_value_pairs = StringUtilities::split(m_settings.additional_static_header_tags,
',');
220 for (
auto pair : tag_value_pairs)
222 auto tokens = StringUtilities::split(pair,
'=');
224 if (tokens.size() != 2)
226 LLFIX_LOG_ERROR(
"Invalid FixSession config value for 'additional_static_header_tags' : " + m_settings.additional_static_header_tags);
230 int tag = std::stoi(tokens[0]);
234 LLFIX_LOG_ERROR(
"Invalid FixSession config value for 'additional_static_header_tags' : " + m_settings.additional_static_header_tags +
" , tag numbers must be positive integers.");
238 m_outgoing_fix_message.set_additional_static_header_tag(
static_cast<uint32_t
>(tag), tokens[1]);
244 LLFIX_LOG_ERROR(
"Session " + m_name +
" : failed to initialise, check config value for 'additional_static_header_tags'.");
248 #ifdef LLFIX_ENABLE_DICTIONARY
249 bool dictionary_load_success =
false;
253 dictionary_load_success = initialise_dictionary_validator();
258 if(dictionary_load_success==
false)
260 LLFIX_LOG_ERROR(
"Session " + m_name +
" : dictionary loading failed.");
265 LLFIX_LOG_INFO(
"Session " + m_name +
" : session config loaded =>\n" + m_settings.to_string());
278 std::string
get_name()
const override {
return m_name; }
280 FixSessionSettings* settings() {
return &m_settings; }
282 std::string get_display_text()
const
284 std::stringstream ret;
286 ret <<
"Session state : " << convert_session_state_to_string(
static_cast<SessionState
>(m_state.load())) <<
'\n';
296 void set_state(SessionState state)
298 m_state =
static_cast<int>(state);
345 return static_cast<SessionState
>(m_state.load());
350 bool open_or_create_sequence_store(
const std::string_view& path)
352 return m_sequence_store.open(path);
365 return &m_sequence_store;
368 uint32_t get_last_processed_sequence_number()
const {
return m_sequence_store.
get_incoming_seq_no(); }
372 Throttler* throttler() {
return &m_throttler; }
374 uint32_t get_incoming_throttler_exceed_count()
const {
return m_incoming_throttler_exceed_count; }
375 void increment_incoming_throttler_exceed_count() { m_incoming_throttler_exceed_count++; }
379 MessageSerialiserType* get_incoming_message_serialiser() {
return &m_incoming_messages_serialiser; }
380 MessageSerialiserType* get_outgoing_message_serialiser() {
return &m_outgoing_messages_serialiser; }
381 bool serialisation_enabled()
const {
return m_settings.max_serialised_file_size>0; }
383 void reinitialise_outgoing_serialiser()
385 LLFIX_LOG_INFO(
"Session " + m_name +
" , record count before reinitialisation : " + std::to_string(m_outgoing_messages_serialiser.get_message_record_count()));
386 m_outgoing_messages_serialiser.initialise(m_settings.outgoing_message_serialisation_path, m_settings.max_serialised_file_size, m_settings.replay_messages_on_incoming_resend_request, m_settings.replay_message_cache_initial_size);
387 LLFIX_LOG_INFO(
"Session " + m_name +
" , record count after reinitialisation : " + std::to_string(m_outgoing_messages_serialiser.get_message_record_count()));
392 bool expecting_response_for_outgoing_test_request()
const {
return m_expecting_response_for_outgoing_test_request; }
393 void set_expecting_response_for_outgoing_test_request(
bool b) { m_expecting_response_for_outgoing_test_request =b; }
395 uint64_t outgoing_test_request_timestamp_nanoseconds()
const {
return m_outgoing_test_request_timestamp_nanoseconds; }
396 void set_outgoing_test_request_timestamp_nanoseconds(uint64_t val) { m_outgoing_test_request_timestamp_nanoseconds = val; }
400 bool needs_to_send_resend_request()
const {
return m_needs_to_send_resend_request; }
401 void set_needs_to_send_resend_request(
bool b) { m_needs_to_send_resend_request = b; }
403 uint32_t get_outgoing_resend_request_begin_no()
const {
return m_outgoing_resend_request_begin_no; }
404 uint32_t get_outgoing_resend_request_end_no()
const {
return m_outgoing_resend_request_end_no; }
406 void queue_outgoing_resend_request(uint32_t sequence_store_incoming_seq_no, uint32_t live_incoming_seq_no)
408 m_needs_to_send_resend_request =
true;
410 m_outgoing_resend_request_begin_no = sequence_store_incoming_seq_no;
411 m_outgoing_resend_request_end_no = live_incoming_seq_no;
414 uint64_t outgoing_resend_request_timestamp_nanoseconds()
const {
return m_outgoing_resend_request_timestamp_nanoseconds; }
415 void set_outgoing_resend_request_timestamp_nanoseconds(uint64_t val) { m_outgoing_resend_request_timestamp_nanoseconds = val; }
419 bool needs_responding_to_incoming_resend_request()
const {
return m_needs_responding_to_incoming_resend_request; }
420 void set_needs_responding_to_incoming_resend_request(
bool b) { m_needs_responding_to_incoming_resend_request = b; }
422 uint32_t get_incoming_resend_request_begin_no()
const {
return m_incoming_resend_request_begin_no; }
423 uint32_t get_incoming_resend_request_end_no()
const {
return m_incoming_resend_request_end_no; }
427 bool needs_responding_to_incoming_test_request()
const {
return m_needs_responding_to_incoming_test_request; }
428 void set_needs_responding_to_incoming_test_request(
bool b) { m_needs_responding_to_incoming_test_request = b; }
430 FixString* get_incoming_test_request_id() {
return &m_incoming_test_request_id; }
434 bool received_logout_response()
const {
return m_received_logout_response; }
435 void set_received_logout_response(
bool b) { m_received_logout_response = b; }
439 uint64_t last_received_message_timestamp_nanoseconds()
const {
return m_last_received_message_timestamp_nanoseconds; }
440 void set_last_received_message_timestamp_nanoseconds(uint64_t val) { m_last_received_message_timestamp_nanoseconds = val; }
442 uint64_t last_sent_message_timestamp_nanoseconds()
const {
return m_last_sent_message_timestamp_nanoseconds; }
443 void set_last_sent_message_timestamp_nanoseconds(uint64_t val) { m_last_sent_message_timestamp_nanoseconds = val; }
464 template <
typename T>
471 if constexpr (std::is_same_v<T, std::string>)
473 m_attributes.add_attribute(attribute, value);
475 else if constexpr (std::is_arithmetic_v<T>)
477 m_attributes.add_attribute(attribute, std::to_string(value));
481 std::ostringstream oss;
483 m_attributes.add_attribute(attribute, oss.str());
506 if(m_attributes.does_attribute_exist(attribute))
508 value = m_attributes.get_string_value(attribute);
517 uint64_t get_heartbeart_interval_in_nanoseconds()
const {
return m_settings.heartbeat_interval_in_nanoseconds; }
519 uint64_t get_outgoing_test_request_interval_in_nanoseconds()
const
521 return m_settings.outgoing_test_request_interval_in_nanoseconds;
524 bool enable_simd_avx2()
const {
return m_settings.enable_simd_avx2; }
525 VDSO::SubsecondPrecision get_timestamp_subsecond_precision()
const {
return m_settings.timestamp_subseconds_precision; }
527 void set_heartbeart_interval_in_nanoseconds(uint64_t value)
529 m_settings.heartbeat_interval_in_nanoseconds = value;
532 void set_outgoing_test_request_interval_in_nanoseconds(uint64_t value)
534 m_settings.outgoing_test_request_interval_in_nanoseconds = value;
537 void set_enable_simd_avx2(
bool b) { m_settings.enable_simd_avx2 = b; }
539 int get_protocol_version()
const {
return m_settings.protocol_version; }
543 const std::string& get_begin_string()
const {
return m_settings.begin_string; }
544 const std::string& get_compid()
const {
return m_settings.sender_comp_id; }
545 const std::string& get_target_compid()
const {
return m_settings.target_comp_id; }
546 bool include_last_processed_seqnum_in_header()
const {
return m_settings.include_last_processed_seqnum_in_header; }
548 void set_begin_string(
const std::string& str) { m_settings.begin_string = str; }
549 void set_compid(
const std::string_view& identifier) { m_settings.sender_comp_id = identifier; }
550 void set_target_compid(
const std::string_view& identifier) { m_settings.target_comp_id = identifier; }
554 const std::string& get_default_app_ver_id()
const {
return m_settings.default_app_ver_id; }
555 const std::string& get_username()
const {
return m_settings.logon_username; }
556 const std::string& get_password()
const {
return m_settings.logon_password; }
557 std::string logon_message_new_password()
const {
return m_settings.logon_message_new_password; }
558 bool logon_reset_sequence_numbers_flag()
const {
return m_settings.logon_reset_sequence_numbers; }
559 bool logon_include_next_expected_seq_no()
const {
return m_settings.logon_include_next_expected_seq_no; }
563 bool validations_enabled()
const {
return m_settings.validations_enabled; }
564 void set_validations_enabled(
bool b) { m_settings.validations_enabled = b; }
566 bool validate_repeating_groups_enabled()
const {
return m_settings.validate_repeating_groups; }
567 void set_validate_repeating_groups_enabled(
bool b) { m_settings.validate_repeating_groups = b; }
571 bool replay_messages_on_incoming_resend_request()
const {
return m_settings.replay_messages_on_incoming_resend_request; }
572 bool include_t97_during_resends()
const {
return m_settings.include_t97_during_resends; }
573 std::size_t max_resend_range()
const {
return m_settings.max_resend_range; }
574 void set_replay_messages_on_incoming_resend_request (
bool b) { m_settings.replay_messages_on_incoming_resend_request=b; }
578 int outgoing_resend_request_expire_secs()
const {
return m_settings.outgoing_resend_request_expire_in_secs; }
582 void build_heartbeat_message(OutgoingFixMessage* message, FixString* test_request_id)
584 message->set_msg_type(FixConstants::MSG_TYPE_HEARTBEAT);
586 if (test_request_id !=
nullptr)
588 message->set_tag(FixConstants::TAG_TEST_REQ_ID, test_request_id);
592 void build_test_request_message(OutgoingFixMessage* message)
594 message->set_msg_type(FixConstants::MSG_TYPE_TEST_REQUEST);
595 m_outgoing_test_request_id++;
596 message->set_tag(FixConstants::TAG_TEST_REQ_ID, m_outgoing_test_request_id);
599 void build_resend_request_message(OutgoingFixMessage* message,
const std::string& end_no)
601 message->set_msg_type(FixConstants::MSG_TYPE_RESEND_REQUEST);
602 message->set_tag(FixConstants::TAG_BEGIN_SEQ_NO, m_outgoing_resend_request_begin_no);
603 message->set_tag(FixConstants::TAG_END_SEQ_NO, end_no);
606 void build_logout_message(OutgoingFixMessage* message,
const std::string& reason_text =
"")
608 message->set_msg_type(FixConstants::MSG_TYPE_LOGOUT);
610 if (reason_text.length() > 0)
612 message->set_tag(FixConstants::TAG_TEXT, reason_text);
616 void build_session_level_reject_message(OutgoingFixMessage* message, uint32_t reject_reason_code,
const char* reject_reason_text, uint32_t error_tag=0)
618 message->set_msg_type(FixConstants::MSG_TYPE_REJECT);
620 if (m_incoming_fix_message.
has_tag(FixConstants::TAG_MSG_SEQ_NUM))
622 message->set_tag(FixConstants::TAG_REF_SEQ_NUM, m_incoming_fix_message.
get_tag_value_as<uint32_t>(FixConstants::TAG_MSG_SEQ_NUM));
627 message->set_tag(FixConstants::TAG_REF_TAG, error_tag);
630 if (m_incoming_fix_message.
has_tag(FixConstants::TAG_MSG_TYPE))
632 message->set_tag(FixConstants::TAG_REF_MSG_TYPE, m_incoming_fix_message.
get_tag_value_as<std::string>(FixConstants::TAG_MSG_TYPE));
635 message->set_tag(FixConstants::TAG_SESSION_REJECT_REASON, reject_reason_code);
636 message->set_tag(FixConstants::TAG_TEXT, reject_reason_text);
639 void build_gap_fill_message(OutgoingFixMessage* message)
641 message->set_msg_type(FixConstants::MSG_TYPE_SEQUENCE_RESET);
648 message->set_tag(FixConstants::TAG_NEW_SEQ_NO, next_outgoing_sequence_no);
651 message->set_tag(FixConstants::TAG_GAP_FILL_FLAG, FixConstants::FIX_BOOLEAN_TRUE);
654 void build_sequence_reset_message(OutgoingFixMessage* message, uint32_t desired_sequence_no)
659 message->set_msg_type(FixConstants::MSG_TYPE_SEQUENCE_RESET);
662 message->set_tag(FixConstants::TAG_NEW_SEQ_NO, desired_sequence_no + 1);
667 bool process_incoming_sequence_reset_message(
const IncomingFixMessage& message)
671 if (message.has_tag(FixConstants::TAG_NEW_SEQ_NO))
673 if (message.is_tag_value_numeric(FixConstants::TAG_NEW_SEQ_NO))
675 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming sequence reset message tag36(new seq no) : " + message.get_tag_value_as<std::string>(FixConstants::TAG_NEW_SEQ_NO));
677 auto new_incoming_seq_no = message.get_tag_value_as<uint32_t>(FixConstants::TAG_NEW_SEQ_NO);
679 if(new_incoming_seq_no==0)
681 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : received invalid new tag sequence number(0) for sequence reset.");
687 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : the sequence reset can only increase the sequence number.");
692 set_state(SessionState::LOGGED_ON);
696 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming sequence reset message has invalid tag36(new seq no).");
701 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming sequence reset message does not have tag36(new seq no).");
707 void process_resend_request(
const IncomingFixMessage& message)
709 if (message.has_tag(FixConstants::TAG_BEGIN_SEQ_NO) && message.has_tag(FixConstants::TAG_END_SEQ_NO))
711 bool is_tag_7_numeric = message.is_tag_value_numeric(FixConstants::TAG_BEGIN_SEQ_NO);
712 bool is_tag_16_numeric = message.is_tag_value_numeric(FixConstants::TAG_END_SEQ_NO);
714 if (is_tag_7_numeric && is_tag_16_numeric)
716 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming resend request tag7(begin seq no) : " + message.get_tag_value_as<std::string>(FixConstants::TAG_BEGIN_SEQ_NO) +
" tag16(end seq no) : " + message.get_tag_value_as<std::string>(FixConstants::TAG_END_SEQ_NO));
718 set_state(llfix::SessionState::IN_RETRANSMISSION_INITIATED_BY_PEER);
720 m_incoming_resend_request_begin_no = message.get_tag_value_as<uint32_t>(FixConstants::TAG_BEGIN_SEQ_NO);
722 m_incoming_resend_request_end_no = message.get_tag_value_as<uint32_t>(FixConstants::TAG_END_SEQ_NO);
724 m_needs_responding_to_incoming_resend_request =
true;
728 if (is_tag_7_numeric ==
false)
730 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming resend request message has invalid tag7(begin seq no).");
733 if (is_tag_16_numeric ==
false)
735 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming resend request message has invalid tag16(end seq no).");
741 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming resend request message does not have one or both of tag7(begin seq no) and tag16(end seq no).");
745 void process_test_request_message(
const IncomingFixMessage& message)
747 LLFIX_LOG_DEBUG(
"Session " + m_name +
" : incoming test request");
749 if (m_expecting_response_for_outgoing_test_request ==
false)
751 m_needs_responding_to_incoming_test_request =
true;
753 if (message.has_tag(FixConstants::TAG_TEST_REQ_ID))
755 auto test_request_id = message.get_tag_value(FixConstants::TAG_TEST_REQ_ID);
756 m_incoming_test_request_id.copy_from(test_request_id->data(), test_request_id->length());
763 bool is_now_valid_session_datetime()
const
765 return m_schedule_validator.is_now_valid_datetime();
768 static void validate_header_tags_order(uint32_t tag, uint32_t tag_index, uint32_t& parser_reject_code)
774 if (llfix_unlikely(tag != FixConstants::TAG_BEGIN_STRING))
776 parser_reject_code = FixParserErrorCodes::OUT_OF_ORDER_HEADER_FIELDS;
779 else if (tag_index == 2)
781 if (llfix_unlikely(tag != FixConstants::TAG_BODY_LENGTH))
783 parser_reject_code = FixParserErrorCodes::OUT_OF_ORDER_HEADER_FIELDS;
786 else if (tag_index == 3)
788 if (llfix_unlikely(tag != FixConstants::TAG_MSG_TYPE))
790 parser_reject_code = FixParserErrorCodes::OUT_OF_ORDER_HEADER_FIELDS;
796 static void validate_tag_format(
const char* buffer, std::size_t buffer_len,
bool& is_numeric, uint32_t& parser_reject_code)
798 if (llfix_unlikely(buffer_len == 0 || buffer_len>10))
800 parser_reject_code = FixConstants::FIX_ERROR_CODE_INVALID_TAG_NUMBER;
805 for (std::size_t i = 0; i < buffer_len; i++)
809 if (llfix_unlikely(c < '0' || c >
'9'))
811 parser_reject_code = FixConstants::FIX_ERROR_CODE_INVALID_TAG_NUMBER;
818 static void validate_tag9_and_tag35(IncomingFixMessage* incoming_message,
int tag_10_start_index,
int tag_35_tag_start_index, uint32_t& parser_reject_code)
820 if (llfix_likely(tag_35_tag_start_index != -1))
822 if (llfix_likely(incoming_message->has_tag(FixConstants::TAG_BODY_LENGTH)))
824 if (llfix_likely(incoming_message->is_tag_value_numeric(FixConstants::TAG_BODY_LENGTH)))
826 auto msg_body_len_val = incoming_message->get_tag_value_as<uint32_t>(FixConstants::TAG_BODY_LENGTH);
828 if (llfix_unlikely(
static_cast<int>(msg_body_len_val) != (tag_10_start_index - tag_35_tag_start_index)))
830 parser_reject_code = FixParserErrorCodes::WRONG_BODY_LENGTH;
835 parser_reject_code = FixParserErrorCodes::INVALID_TAG_9;
840 parser_reject_code = FixParserErrorCodes::NO_TAG_9;
845 parser_reject_code = FixParserErrorCodes::NO_TAG_35;
849 bool validate_fix_message(
const IncomingFixMessage& incoming_message,
const char* buffer_message, std::size_t buffer_message_length, uint32_t reject_reason_code, uint32_t& out_reject_message_code)
852 if (incoming_message.has_tag(FixConstants::TAG_MSG_SEQ_NUM) ==
false)
854 set_last_error_tag(0);
855 LLFIX_LOG_DEBUG(
"Session " + m_name +
" received a message with no tag34(sequence number) : " +
FixUtilities::fix_to_human_readible(buffer_message, buffer_message_length));
860 if (incoming_message.is_tag_value_numeric(FixConstants::TAG_MSG_SEQ_NUM) ==
false)
862 set_last_error_tag(0);
863 LLFIX_LOG_DEBUG(
"Session " + m_name +
" received a message with invalid tag34(sequence number) : " +
FixUtilities::fix_to_human_readible(buffer_message, buffer_message_length));
868 if (llfix_unlikely(reject_reason_code !=
static_cast<uint32_t
>(-1)))
870 set_last_error_tag(0);
872 if (reject_reason_code > FixConstants::FIX_MAX_ERROR_CODE)
874 std::string log_message =
"Session " + m_name +
" " + FixParserErrorCodes::get_internal_parser_error_description(reject_reason_code) +
" : " +
FixUtilities::fix_to_human_readible(buffer_message, buffer_message_length);
875 LLFIX_LOG_DEBUG(log_message);
879 out_reject_message_code = reject_reason_code;
886 if (incoming_message.has_tag(FixConstants::TAG_BEGIN_STRING) ==
false)
888 set_last_error_tag(0);
894 if (!incoming_message.get_tag_value(FixConstants::TAG_BEGIN_STRING)->equals(m_settings.begin_string.c_str()))
896 set_last_error_tag(0);
902 if (incoming_message.has_tag(FixConstants::TAG_SENDER_COMP_ID) ==
false)
904 set_last_error_tag(0);
910 if (!incoming_message.get_tag_value(FixConstants::TAG_SENDER_COMP_ID)->equals(m_settings.target_comp_id.c_str()))
912 set_last_error_tag(0);
913 out_reject_message_code = FixConstants::FIX_ERROR_CODE_COMPID_PROBLEM;
918 if (incoming_message.has_tag(FixConstants::TAG_TARGET_COMP_ID) ==
false)
920 set_last_error_tag(0);
926 if (!incoming_message.get_tag_value(FixConstants::TAG_TARGET_COMP_ID)->equals(m_settings.sender_comp_id.c_str()))
928 set_last_error_tag(0);
929 out_reject_message_code = FixConstants::FIX_ERROR_CODE_COMPID_PROBLEM;
934 if (incoming_message.is_tag_value_numeric(FixConstants::TAG_CHECKSUM) ==
false)
936 set_last_error_tag(0);
942 const uint32_t actual_checksum = incoming_message.get_tag_value_as<uint32_t>(FixConstants::TAG_CHECKSUM);
944 if (m_settings.enable_simd_avx2)
946 if (FixUtilities::validate_checksum_simd_avx2(buffer_message, buffer_message_length - 7, actual_checksum) ==
false)
948 set_last_error_tag(0);
955 if (FixUtilities::validate_checksum_no_simd(buffer_message, buffer_message_length - 7, actual_checksum) ==
false)
957 set_last_error_tag(0);
964 if (incoming_message.has_tag(FixConstants::TAG_SENDING_TIME) ==
false)
966 set_last_error_tag(0);
972 if(m_settings.max_allowed_message_age_seconds > 0)
974 auto sending_time = incoming_message.get_tag_value(FixConstants::TAG_SENDING_TIME);
976 if(sending_time->is_timestamp() ==
false)
978 set_last_error_tag(FixConstants::TAG_SENDING_TIME);
979 out_reject_message_code = FixConstants::FIX_ERROR_CODE_FORMAT_INCORRECT_FOR_TAG;
984 if(FixUtilities::is_utc_timestamp_stale(sending_time->to_string_view(),
static_cast<int>(m_settings.max_allowed_message_age_seconds)))
986 set_last_error_tag(0);
987 out_reject_message_code = FixConstants::FIX_ERROR_CODE_SENDING_TIME_ACCURACY_PROBLEM;
993 #ifdef LLFIX_ENABLE_DICTIONARY
995 if (m_settings.dictionary_validations_enabled ==
true)
997 if (m_validator_id >= 0)
999 if (get_validator(m_validator_id).validate(m_incoming_fix_message, out_reject_message_code) ==
false)
1001 set_last_error_tag(get_validator(m_validator_id).get_last_error_tag());
1006 if (validate_repeating_groups_enabled())
1008 if (get_validator(m_validator_id).validate_repeating_groups(m_incoming_fix_message, out_reject_message_code) ==
false)
1010 set_last_error_tag(get_validator(m_validator_id).get_last_error_tag());
1021 uint32_t get_last_error_tag()
const {
return m_last_error_tag; }
1025 IncomingFixMessage* get_incoming_fix_message() {
return &m_incoming_fix_message; }
1026 OutgoingFixMessage* get_outgoing_fix_message() {
return &m_outgoing_fix_message; }
1028 ObjectCache<FixStringView>* get_fix_string_view_cache() {
return &m_fix_string_view_cache; }
1029 char* get_tx_encode_buffer() {
return m_tx_encode_buffer; }
1030 SPSCBoundedQueue<ModifyingAdminCommand*>* get_admin_commands() {
return &m_admin_commands; }
1034 m_needs_responding_to_incoming_test_request =
false;
1035 m_expecting_response_for_outgoing_test_request =
false;
1036 m_needs_responding_to_incoming_resend_request =
false;
1037 m_needs_to_send_resend_request =
false;
1038 m_received_logout_response =
false;
1040 m_incoming_throttler_exceed_count = 0;
1043 static bool is_a_hard_sequence_reset_message(
const IncomingFixMessage& message)
1045 if (message.has_tag(FixConstants::TAG_MSG_TYPE) ==
false)
1050 if (message.get_tag_value_as<
char>(FixConstants::TAG_MSG_TYPE) != FixConstants::MSG_TYPE_SEQUENCE_RESET)
1055 if (message.has_tag(FixConstants::TAG_GAP_FILL_FLAG))
1057 if (message.get_tag_value_as<
char>(FixConstants::TAG_GAP_FILL_FLAG) == FixConstants::FIX_BOOLEAN_TRUE)
1082 static IncomingFixRepeatingGroupSpecs& get_repeating_group_specs()
1084 return m_repeating_group_specs;
1087 #ifdef LLFIX_ENABLE_DICTIONARY
1088 LLFIX_FORCE_INLINE
static FixDictionaryValidator::Validator& get_validator(uint32_t validator_id)
1090 assert(m_validators.find(validator_id) != m_validators.end());
1091 return m_validators[validator_id];
1095 #ifdef LLFIX_ENABLE_BINARY_FIELDS
1096 static IncomingFixBinaryFieldSpecs& get_binary_field_specs()
1098 return m_binary_field_specs;
1103 std::atomic<int> m_state =
static_cast<int>(SessionState::NONE);
1105 SequenceStore m_sequence_store;
1106 Throttler m_throttler;
1107 MessageSerialiserType m_outgoing_messages_serialiser;
1108 MessageSerialiserType m_incoming_messages_serialiser;
1109 Configuration m_attributes;
1111 FixSessionSettings m_settings;
1113 uint64_t m_last_sent_message_timestamp_nanoseconds = 0;
1114 uint64_t m_last_received_message_timestamp_nanoseconds = 0;
1115 uint32_t m_incoming_throttler_exceed_count = 0;
1117 char* m_tx_encode_buffer =
nullptr;
1119 OutgoingFixMessage m_outgoing_fix_message;
1121 IncomingFixMessage m_incoming_fix_message;
1122 ObjectCache<FixStringView> m_fix_string_view_cache;
1124 UserspaceSpinlock<> m_lock;
1127 FixString m_incoming_test_request_id;
1128 bool m_needs_responding_to_incoming_test_request =
false;
1131 uint32_t m_outgoing_test_request_id = 0;
1132 uint64_t m_outgoing_test_request_timestamp_nanoseconds = 0;
1133 bool m_expecting_response_for_outgoing_test_request =
false;
1136 bool m_needs_responding_to_incoming_resend_request =
false;
1137 uint32_t m_incoming_resend_request_begin_no = 0;
1138 uint32_t m_incoming_resend_request_end_no = 0;
1141 bool m_needs_to_send_resend_request =
false;
1142 uint32_t m_outgoing_resend_request_begin_no = 0;
1143 uint32_t m_outgoing_resend_request_end_no = 0;
1145 uint64_t m_outgoing_resend_request_timestamp_nanoseconds = 0;
1148 bool m_received_logout_response =
false;
1151 SPSCBoundedQueue<ModifyingAdminCommand*> m_admin_commands;
1154 SessionScheduleValidator m_schedule_validator;
1155 uint32_t m_last_error_tag=0;
1157 static inline IncomingFixRepeatingGroupSpecs m_repeating_group_specs;
1159 #ifdef LLFIX_ENABLE_BINARY_FIELDS
1160 static inline IncomingFixBinaryFieldSpecs m_binary_field_specs;
1163 #ifdef LLFIX_ENABLE_DICTIONARY
1164 static inline UserspaceSpinlock<> m_validators_initialisation_lock;
1165 static inline std::unordered_map<std::string, int> m_path_validator_id_table;
1166 static inline int m_latest_validator_id = 0;
1167 static inline std::unordered_map<int, FixDictionaryValidator::Validator> m_validators;
1169 int m_validator_id = -1;
1170 std::unique_ptr<std::vector<std::string>> m_dictionary_load_errors;
1172 void on_dictionary_load_error(
const std::string& message)
1174 m_dictionary_load_errors->push_back(message);
1177 bool initialise_dictionary_validator()
1179 const std::lock_guard<UserspaceSpinlock<>> lock(m_validators_initialisation_lock);
1181 if (m_settings.application_dictionary_path.length() == 0)
1186 bool already_loaded_dictionary =
false;
1188 if (m_path_validator_id_table.find(m_settings.application_dictionary_path) != m_path_validator_id_table.end())
1190 m_validator_id = m_path_validator_id_table[m_settings.application_dictionary_path];
1191 already_loaded_dictionary =
true;
1195 m_latest_validator_id++;
1196 m_validator_id = m_latest_validator_id;
1200 m_dictionary_load_errors.reset(
new std::vector<std::string>);
1201 std::unique_ptr<FixDictionaryLoader> dictionary_loader(
new FixDictionaryLoader);
1203 auto get_dictionary_load_errors = [&]()
1207 auto dictionary_load_errors = *dictionary_loader->errors();
1209 for (
const auto& error : dictionary_load_errors)
1211 ret += error +
"\n";
1217 if (m_settings.transport_dictionary_path.length() > 0)
1219 if (dictionary_loader->load_from(m_settings.transport_dictionary_path,
true) ==
false)
1221 LLFIX_LOG_ERROR(
"Session " + m_name +
" transport dictionary loading errors :" + get_dictionary_load_errors());
1226 if (m_settings.application_dictionary_path.length() > 0)
1228 if (dictionary_loader->load_from(m_settings.application_dictionary_path,
false) ==
false)
1230 LLFIX_LOG_ERROR(
"Session " + m_name +
" application dictionary loading errors :" + get_dictionary_load_errors());
1236 std::string dictionary_begin_string;
1238 if (dictionary_loader->get_dictionary()->get_begin_string(dictionary_begin_string))
1240 if (m_settings.begin_string != dictionary_begin_string)
1242 LLFIX_LOG_ERROR(
"Session " + m_name +
" : begin string specified in config file (" + m_settings.begin_string +
") does not match the dictionary (" + dictionary_begin_string +
")");
1248 LLFIX_LOG_ERROR(
"Session " + m_name +
" failed to retrieve begin string from dictionary.");
1253 FixDictionaryValidator::Validator validator;
1255 if (already_loaded_dictionary ==
false)
1257 auto fields = *dictionary_loader->get_dictionary()->fields();
1260 for (
const auto& field : fields)
1262 FixDictionaryValidator::FieldDefinition field_definition;
1263 field_definition.m_type = get_validator_field_type(field.second.type);
1265 if (field_definition.m_type != FixDictionaryValidator::FieldType::NONE)
1267 for (
const auto& allowed_value : field.second.values)
1269 field_definition.add_allowed_value(allowed_value);
1272 validator.specify_field_definition(field.second.tag, field_definition);
1277 load_validator_message_definitions(validator, dictionary_loader->get_dictionary(), fields);
1280 load_validator_repeating_group_definitions(validator, dictionary_loader->get_dictionary(), fields);
1282 #ifdef LLFIX_ENABLE_BINARY_FIELDS
1284 load_binary_fields(dictionary_loader->get_dictionary(), fields);
1289 for (
const auto& dict_error : *m_dictionary_load_errors)
1291 LLFIX_LOG_ERROR(
"Session " + m_name +
" dictionary error : " + dict_error);
1294 if (m_dictionary_load_errors->size() > 0)
1300 if (already_loaded_dictionary ==
false)
1302 m_validators[m_validator_id] = validator;
1303 m_path_validator_id_table[m_settings.application_dictionary_path] = m_validator_id;
1309 void get_all_non_repeating_group_fields_of_component_recursively(std::unordered_map<std::string, Component>& components,
const std::string& component_name,
bool is_parent_required, std::vector<MessageField>& target,
int& depth)
1313 if (components.find(component_name) != components.end())
1315 Component& component = components[component_name];
1317 for (
const auto& field : component.fields)
1320 cp.name = field.name;
1324 cp.required = field.required && is_parent_required;
1326 target.push_back(cp);
1329 for (
const auto& component_field : component.components)
1331 get_all_non_repeating_group_fields_of_component_recursively(components, component_field.name, component_field.required && is_parent_required, target, depth);
1337 on_dictionary_load_error(
"Could not find component " + component_name);
1341 void load_validator_message_definitions(FixDictionaryValidator::Validator& target_validator, FixDictionary* dictionary, std::unordered_map<std::string, Field>& fields)
1343 auto messages = dictionary->messages();
1344 auto components = *dictionary->components();
1345 auto header = dictionary->header();
1346 auto trailer = dictionary->trailer();
1348 auto add_field_to_message_definition = [&](
const std::string& field_name,
bool required, FixDictionaryValidator::MessageDefinition& target)
1350 if (fields.find(field_name) != fields.end())
1354 auto current_tag = fields[field_name].tag;
1355 if(current_tag != FixConstants::TAG_BEGIN_STRING && current_tag != FixConstants::TAG_BODY_LENGTH && current_tag != FixConstants::TAG_MSG_SEQ_NUM && current_tag != FixConstants::TAG_MSG_TYPE && current_tag != FixConstants::TAG_SENDER_COMP_ID && current_tag != FixConstants::TAG_SENDING_TIME && current_tag != FixConstants::TAG_TARGET_COMP_ID)
1356 target.add_required_field({ current_tag });
1358 target.add_non_required_field({ current_tag });
1362 target.add_non_required_field({ fields[field_name].tag });
1367 on_dictionary_load_error(
"Could not find field " + field_name);
1371 std::vector<MessageField> header_component_fields;
1372 for (
const auto& component : header->components)
1375 get_all_non_repeating_group_fields_of_component_recursively(components, component.name, component.required, header_component_fields, depth);
1378 std::vector<MessageField> trailer_component_fields;
1379 for (
const auto& component : trailer->components)
1382 get_all_non_repeating_group_fields_of_component_recursively(components, component.name, component.required, trailer_component_fields, depth);
1385 for (
const auto& message : *messages)
1387 auto message_type = message.second.msg_type;
1388 FixDictionaryValidator::MessageDefinition message_definition;
1391 for (
auto& field : message.second.fields)
1393 add_field_to_message_definition(field.name, field.required, message_definition);
1397 for (
const auto& component : message.second.components)
1399 std::vector<MessageField> component_fields;
1401 get_all_non_repeating_group_fields_of_component_recursively(components, component.name, component.required, component_fields, depth);
1403 for (
const auto& field : component_fields)
1405 add_field_to_message_definition(field.name, (component.required && field.required), message_definition);
1410 for (
const auto& field : header->fields)
1412 if (fields.find(field.name) != fields.end())
1414 add_field_to_message_definition(field.name, field.required, message_definition);
1418 on_dictionary_load_error(
"Could not find field " + field.name);
1423 for (
const auto& field : header_component_fields)
1425 if (fields.find(field.name) != fields.end())
1427 add_field_to_message_definition(field.name, field.required, message_definition);
1431 on_dictionary_load_error(
"Could not find field " + field.name);
1436 for (
const auto& field : trailer->fields)
1438 if (fields.find(field.name) != fields.end())
1440 add_field_to_message_definition(field.name, field.required, message_definition);
1444 on_dictionary_load_error(
"Could not find field " + field.name);
1449 for (
const auto& field : trailer_component_fields)
1451 if (fields.find(field.name) != fields.end())
1453 add_field_to_message_definition(field.name, field.required, message_definition);
1457 on_dictionary_load_error(
"Could not find field " + field.name);
1461 target_validator.specify_message_definition(message_type, message_definition);
1465 #ifdef LLFIX_ENABLE_BINARY_FIELDS
1466 void load_binary_fields(FixDictionary* dictionary, std::unordered_map<std::string, Field>& fields)
1468 auto messages = *dictionary->messages();
1469 auto header = *dictionary->header();
1470 auto trailer = *dictionary->trailer();
1471 auto components = *dictionary->components();
1473 for (
auto& message : messages)
1476 process_field_vector(message.second.fields, message.first, fields);
1479 for (
auto component : message.second.components)
1481 process_component_binary_fields_recursively(component, components, fields, message.first);
1485 for (
auto group_field : message.second.groups)
1487 process_group_binary_fields_recursively(group_field, components, fields, message.first);
1491 process_field_vector(header.fields, message.first, fields);
1494 for (
auto component : header.components)
1496 process_component_binary_fields_recursively(component, components, fields, message.first);
1500 for (
auto group : header.groups)
1502 process_group_binary_fields_recursively(group, components, fields, message.first);
1506 process_field_vector(trailer.fields, message.first, fields);
1509 for (
auto component : trailer.components)
1511 process_component_binary_fields_recursively(component, components, fields, message.first);
1515 for (
auto group : trailer.groups)
1517 process_group_binary_fields_recursively(group, components, fields, message.first);
1522 void process_component_binary_fields_recursively(ComponentField& component, std::unordered_map<std::string, Component>& components, std::unordered_map<std::string, Field>& fields,
const std::string& message_type)
1524 if (components.find(component.name) != components.end())
1526 process_field_vector(components[component.name].fields, message_type, fields);
1528 for (
auto& nested_component : components[component.name].components)
1530 process_component_binary_fields_recursively(nested_component, components, fields, message_type);
1533 for (
auto& nested_group_field : components[component.name].groups)
1535 process_group_binary_fields_recursively(nested_group_field, components, fields, message_type);
1541 on_dictionary_load_error(
"Could not find component " + component.name);
1545 void process_group_binary_fields_recursively(GroupField& group_field, std::unordered_map<std::string, Component>& components, std::unordered_map<std::string, Field>& fields,
const std::string& message_type)
1547 process_field_vector(group_field.fields, message_type, fields);
1549 for (
auto& nested_component : group_field.component_fields)
1551 process_component_binary_fields_recursively(nested_component, components, fields, message_type);
1554 for (
auto& nested_group_field : group_field.group_fields)
1556 process_group_binary_fields_recursively(nested_group_field, components, fields, message_type);
1560 void process_field_vector(std::vector<MessageField>& field_vector,
const std::string& message_type, std::unordered_map<std::string, Field>& fields)
1563 uint32_t current_length_tag = 0;
1564 int current_length_index = 0;
1566 for (
auto& field : field_vector)
1570 if (fields.find(field.name) != fields.end())
1572 auto current_field_type = fields[field.name].type;
1574 if (current_field_type == FieldType::LENGTH)
1576 current_length_tag = fields[field.name].tag;
1577 current_length_index = index;
1579 else if (current_field_type == FieldType::DATA)
1581 if (index == current_length_index + 1)
1583 m_binary_field_specs.specify_binary_field(message_type, current_length_tag, fields[field.name].tag);
1589 on_dictionary_load_error(
"Could not find field " + field.name);
1595 void load_validator_repeating_group_definitions(FixDictionaryValidator::Validator& target_validator, FixDictionary* dictionary, std::unordered_map<std::string, Field>& fields)
1597 auto messages = *dictionary->messages();
1598 auto header = *dictionary->header();
1599 auto trailer = *dictionary->trailer();
1600 auto components = *dictionary->components();
1602 std::vector<uint32_t> count_tags_stack;
1603 count_tags_stack.reserve(4);
1605 for (
const auto& message : messages)
1608 for (
const auto& component : message.second.components)
1610 if (components.find(component.name) != components.end())
1613 process_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message.first, components[component.name], component.required, depth);
1617 on_dictionary_load_error(
"Could not find component " + component.name);
1622 for (
const auto& component : header.components)
1624 if (components.find(component.name) != components.end())
1627 process_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message.first, components[component.name], component.required, depth);
1631 on_dictionary_load_error(
"Could not find component " + component.name);
1636 for (
const auto& component : trailer.components)
1638 if (components.find(component.name) != components.end())
1641 process_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message.first, components[component.name], component.required, depth);
1645 on_dictionary_load_error(
"Could not find component " + component.name);
1650 for (
const auto& group_field : message.second.groups)
1653 process_group_field_rg_tags_recursively(target_validator, components, fields, count_tags_stack, message.first, group_field, group_field.required, depth);
1657 for (
const auto& group_field : header.groups)
1660 process_group_field_rg_tags_recursively(target_validator, components, fields, count_tags_stack, message.first, group_field, group_field.required, depth);
1664 for (
const auto& group_field : trailer.groups)
1667 process_group_field_rg_tags_recursively(target_validator, components, fields, count_tags_stack, message.first, group_field, group_field.required, depth);
1673 void process_rg_component_tags_recursively(FixDictionaryValidator::Validator& target_validator, std::unordered_map<std::string, Component>& components, std::unordered_map<std::string, Field>& fields, std::vector<uint32_t>& count_tags_stack,
const std::string& message_type,
const Component& component,
bool is_parent_required,
int& depth)
1677 for (
const auto& group : component.groups)
1679 int group_traversal_depth{ 0 };
1680 process_group_field_rg_tags_recursively(target_validator, components, fields, count_tags_stack, message_type, group, group.required && is_parent_required, group_traversal_depth);
1683 for (
const auto& nested_component_field : component.components)
1685 if (components.find(nested_component_field.name) != components.end())
1687 process_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message_type, components[nested_component_field.name], nested_component_field.required && is_parent_required, depth);
1692 on_dictionary_load_error(
"Could not find component " + nested_component_field.name);
1698 void process_non_rg_component_tags_recursively(FixDictionaryValidator::Validator& target_validator, std::unordered_map<std::string, Component>& components, std::unordered_map<std::string, Field>& fields, std::vector<uint32_t>& count_tags_stack,
const std::string& message_type,
const Component& component,
bool is_parent_required,
int& depth)
1702 for (
const auto& field : component.fields)
1704 process_repeating_group_tag(target_validator, fields, count_tags_stack, field.name, message_type, field.required && is_parent_required,
false);
1707 for (
const auto& nested_component : component.components)
1709 if (components.find(nested_component.name) != components.end())
1711 process_non_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message_type, components[nested_component.name], nested_component.required && is_parent_required, depth);
1716 on_dictionary_load_error(
"Could not find component " + nested_component.name);
1721 void process_group_field_rg_tags_recursively(FixDictionaryValidator::Validator& target_validator, std::unordered_map<std::string, Component>& components, std::unordered_map<std::string, Field>& fields, std::vector<uint32_t>& count_tags_stack,
const std::string& message_type,
const GroupField& group_field ,
bool is_parent_required,
int& depth)
1725 auto count_tag = fields[group_field.name].tag;
1727 count_tags_stack.push_back(count_tag);
1729 process_repeating_group_tag(target_validator, fields, count_tags_stack, group_field.name, message_type, group_field.required && is_parent_required,
true);
1731 for (
const auto& field : group_field.fields)
1733 process_repeating_group_tag(target_validator, fields, count_tags_stack, field.name, message_type, field.required && is_parent_required,
false);
1736 for (
const auto& nested_component : group_field.component_fields)
1738 if (components.find(nested_component.name) != components.end())
1740 int nested_component_traversal_depth{ 0 };
1741 process_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message_type, components[nested_component.name], nested_component.required && is_parent_required, nested_component_traversal_depth);
1743 nested_component_traversal_depth = 0;
1744 process_non_rg_component_tags_recursively(target_validator, components, fields, count_tags_stack, message_type, components[nested_component.name], nested_component.required && is_parent_required, nested_component_traversal_depth);
1748 on_dictionary_load_error(
"Could not find component " + nested_component.name);
1752 for (
const auto& nested_group : group_field.group_fields)
1754 process_group_field_rg_tags_recursively(target_validator, components, fields, count_tags_stack, message_type, nested_group, nested_group.required && is_parent_required, depth);
1758 count_tags_stack.pop_back();
1761 void process_repeating_group_tag(FixDictionaryValidator::Validator& target_validator, std::unordered_map<std::string, Field>& fields, std::vector<uint32_t>& count_tags_stack,
const std::string& field_name,
const std::string& message_type,
bool required,
bool is_count_tag)
1763 if (fields.find(field_name) != fields.end())
1765 uint32_t current_tag = fields[field_name].tag;
1769 m_repeating_group_specs.add_count_tag(message_type, current_tag);
1772 for (
auto it = count_tags_stack.begin(); it != count_tags_stack.end() - 1; ++it)
1774 m_repeating_group_specs.add_repeating_group_tag(message_type, *it, current_tag);
1779 target_validator.specify_repeating_group_count_tag(message_type, current_tag);
1784 for (
const auto& parent_count_tag : count_tags_stack)
1786 m_repeating_group_specs.add_repeating_group_tag(message_type, parent_count_tag, current_tag);
1792 on_dictionary_load_error(
"Could not find field " + field_name);
1796 static FixDictionaryValidator::FieldType get_validator_field_type(FieldType type)
1801 case FieldType::CHAR:
return FixDictionaryValidator::FieldType::CHAR;
1803 case FieldType::BOOLEAN:
return FixDictionaryValidator::FieldType::BOOL;
1806 case FieldType::INT:
return FixDictionaryValidator::FieldType::INT;
1807 case FieldType::TAGNUM:
return FixDictionaryValidator::FieldType::INT;
1808 case FieldType::SEQNUM:
return FixDictionaryValidator::FieldType::INT;
1809 case FieldType::NUMINGROUP:
return FixDictionaryValidator::FieldType::INT;
1810 case FieldType::LENGTH:
return FixDictionaryValidator::FieldType::INT;
1813 case FieldType::FLOAT:
return FixDictionaryValidator::FieldType::FLOAT;
1814 case FieldType::AMT:
return FixDictionaryValidator::FieldType::FLOAT;
1815 case FieldType::PRICE:
return FixDictionaryValidator::FieldType::FLOAT;
1816 case FieldType::PRICEOFFSET:
return FixDictionaryValidator::FieldType::FLOAT;
1817 case FieldType::QTY:
return FixDictionaryValidator::FieldType::FLOAT;
1818 case FieldType::QUANTITY:
return FixDictionaryValidator::FieldType::FLOAT;
1819 case FieldType::PERCENTAGE:
return FixDictionaryValidator::FieldType::FLOAT;
1822 case FieldType::UTCTIMESTAMP:
return FixDictionaryValidator::FieldType::TIMESTAMP;
1823 case FieldType::TZTIMESTAMP:
return FixDictionaryValidator::FieldType::TIMESTAMP;
1826 case FieldType::UTCTIMEONLY:
return FixDictionaryValidator::FieldType::TIME_ONLY;
1827 case FieldType::TZTIMEONLY:
return FixDictionaryValidator::FieldType::TIME_ONLY;
1828 case FieldType::UTCTIME:
return FixDictionaryValidator::FieldType::TIME_ONLY;
1829 case FieldType::TIME:
return FixDictionaryValidator::FieldType::TIME_ONLY;
1830 case FieldType::LOCALMKTTIME:
return FixDictionaryValidator::FieldType::TIME_ONLY;
1833 case FieldType::UTCDATEONLY:
return FixDictionaryValidator::FieldType::DATE_ONLY;
1834 case FieldType::UTCDATE:
return FixDictionaryValidator::FieldType::DATE_ONLY;
1835 case FieldType::DATE:
return FixDictionaryValidator::FieldType::DATE_ONLY;
1836 case FieldType::LOCALMKTDATE:
return FixDictionaryValidator::FieldType::DATE_ONLY;
1839 case FieldType::MONTHYEAR:
return FixDictionaryValidator::FieldType::STRING;
1840 case FieldType::DAYOFMONTH:
return FixDictionaryValidator::FieldType::INT;
1843 case FieldType::DATA:
return FixDictionaryValidator::FieldType::DATA;
1844 case FieldType::XMLDATA:
return FixDictionaryValidator::FieldType::DATA;
1847 case FieldType::STRING:
return FixDictionaryValidator::FieldType::STRING;
1848 case FieldType::MULTIPLESTRINGVALUE:
return FixDictionaryValidator::FieldType::STRING;
1849 case FieldType::MULTIPLEVALUESTRING:
return FixDictionaryValidator::FieldType::STRING;
1850 case FieldType::MULTIPLEVALUECHAR:
return FixDictionaryValidator::FieldType::STRING;
1851 case FieldType::MULTIPLECHARVALUE:
return FixDictionaryValidator::FieldType::STRING;
1852 case FieldType::COUNTRY:
return FixDictionaryValidator::FieldType::STRING;
1853 case FieldType::CURRENCY:
return FixDictionaryValidator::FieldType::STRING;
1854 case FieldType::EXCHANGE:
return FixDictionaryValidator::FieldType::STRING;
1855 case FieldType::LANGUAGE:
return FixDictionaryValidator::FieldType::STRING;
1856 case FieldType::RESERVED100PLUS:
return FixDictionaryValidator::FieldType::STRING;
1857 case FieldType::RESERVED1000PLUS:
return FixDictionaryValidator::FieldType::STRING;
1858 case FieldType::RESERVED4000PLUS:
return FixDictionaryValidator::FieldType::STRING;
1859 case FieldType::PATTERN:
return FixDictionaryValidator::FieldType::STRING;
1860 case FieldType::TENOR:
return FixDictionaryValidator::FieldType::STRING;
1861 case FieldType::XID:
return FixDictionaryValidator::FieldType::STRING;
1862 case FieldType::XIDREF:
return FixDictionaryValidator::FieldType::STRING;
1865 case FieldType::NONE:
return FixDictionaryValidator::FieldType::NONE;
1866 default:
return FixDictionaryValidator::FieldType::NONE;
1871 void set_last_error_tag(uint32_t tag)
1873 m_last_error_tag = tag;
1876 FixSession(
const FixSession& other) =
delete;
1877 FixSession& operator= (
const FixSession& other) =
delete;
1878 FixSession(FixSession&& other) =
delete;
1879 FixSession& operator=(FixSession&& other) =
delete;