From 03482447c1920c0902b08fd20587257c1bac28f5 Mon Sep 17 00:00:00 2001 From: Mike Gatny Date: Fri, 12 May 2023 08:58:20 -0400 Subject: [PATCH 1/5] Use UInt64 instead of Int32 for seqnums Per the recommendation of the FIX Trading Community Continuous Markets Working Group, use UInt64 for seqnums to allow for non-stop sessions with no sequence reset. --- QuickFIXn/Dictionary.cs | 16 ++ QuickFIXn/Fields/Converters/AsciiConverter.cs | 29 ++ .../Fields/Converters/DecimalConverter.cs | 4 +- QuickFIXn/Fields/Converters/IntConverter.cs | 14 +- QuickFIXn/Fields/Converters/ULongConverter.cs | 39 +++ QuickFIXn/Fields/Fields.cs | 270 +++++++++--------- QuickFIXn/Fields/ULongField.cs | 30 ++ QuickFIXn/FileStore.cs | 20 +- QuickFIXn/HttpServer.cs | 53 ++-- QuickFIXn/IMessageStore.cs | 8 +- QuickFIXn/MemoryStore.cs | 14 +- QuickFIXn/Message/FieldMap.cs | 34 +++ QuickFIXn/ResendRange.cs | 10 +- QuickFIXn/Session.cs | 80 +++--- QuickFIXn/SessionFactory.cs | 2 +- QuickFIXn/SessionState.cs | 27 +- UnitTests/FileStoreTests.cs | 39 +++ UnitTests/SessionStateTest.cs | 6 +- UnitTests/SessionTest.cs | 24 +- generator/fields_gen.rb | 4 +- generator/message_factory_gen.rb | 2 +- generator/messages_gen.rb | 2 +- spec/fix/FIX40.xml | 10 +- spec/fix/FIX41.xml | 10 +- spec/fix/FIX42.xml | 12 +- 25 files changed, 476 insertions(+), 283 deletions(-) create mode 100644 QuickFIXn/Fields/Converters/AsciiConverter.cs create mode 100644 QuickFIXn/Fields/Converters/ULongConverter.cs create mode 100644 QuickFIXn/Fields/ULongField.cs diff --git a/QuickFIXn/Dictionary.cs b/QuickFIXn/Dictionary.cs index ae3753a07..c8c45bf55 100755 --- a/QuickFIXn/Dictionary.cs +++ b/QuickFIXn/Dictionary.cs @@ -105,6 +105,22 @@ public long GetLong(string key) } } + public ulong GetULong(string key) + { + try + { + return Convert.ToUInt64(GetString(key)); + } + catch(FormatException) + { + throw new ConfigError("Incorrect data type"); + } + catch(QuickFIXException) + { + throw new ConfigError("No value for key: " + key); + } + } + public double GetDouble(string key) { try diff --git a/QuickFIXn/Fields/Converters/AsciiConverter.cs b/QuickFIXn/Fields/Converters/AsciiConverter.cs new file mode 100644 index 000000000..a798ef93f --- /dev/null +++ b/QuickFIXn/Fields/Converters/AsciiConverter.cs @@ -0,0 +1,29 @@ + +namespace QuickFix.Fields.Converters +{ + /// + /// convert Int64 to/from string + /// + public static class AsciiValidator + { + public const int ASCII_ZERO = 48; + public const int ASCII_NINE = 57; + public const int ASCII_MINUS = 45; + + /// + /// TODO can we use NumberFormatInfo or NumberStyles to avoid this bit of ASCII hackery? + /// Validates that a string looks like number (for use before conversion to an int, ulong, etc.). + /// + /// + /// + public static void Validate(string i) + { + if ((null == i) || (i.Length < 1)) + throw new FieldConvertError("The argument string cannot be null or empty"); + int asciiValOfFirstChar = System.Convert.ToInt32(i[0]); + if ((asciiValOfFirstChar < ASCII_ZERO) || (asciiValOfFirstChar > ASCII_NINE)) + if (asciiValOfFirstChar != ASCII_MINUS) + throw new FieldConvertError("Could not convert string to int (" + i + "): The first character must be a digit or a minus sign"); + } + } +} diff --git a/QuickFIXn/Fields/Converters/DecimalConverter.cs b/QuickFIXn/Fields/Converters/DecimalConverter.cs index 550d9fa85..749fa180f 100644 --- a/QuickFIXn/Fields/Converters/DecimalConverter.cs +++ b/QuickFIXn/Fields/Converters/DecimalConverter.cs @@ -23,8 +23,8 @@ public static Decimal Convert(string d) if((null == d) || (d.Length < 1)) throw new FieldConvertError("The argument string cannot be null or empty"); int asciiValOfFirstChar = System.Convert.ToInt32(d[0]); - if ((asciiValOfFirstChar < IntConverter.ASCII_ZERO) || (asciiValOfFirstChar > IntConverter.ASCII_NINE)) - if (asciiValOfFirstChar != IntConverter.ASCII_MINUS && asciiValOfFirstChar != ASCII_DECIMALPOINT) + if ((asciiValOfFirstChar < AsciiValidator.ASCII_ZERO) || (asciiValOfFirstChar > AsciiValidator.ASCII_NINE)) + if (asciiValOfFirstChar != AsciiValidator.ASCII_MINUS && asciiValOfFirstChar != ASCII_DECIMALPOINT) throw new FieldConvertError("Could not convert string to decimal (" + d + "): The first character must be a digit, decimal point, or minus sign"); return decimal.Parse(d, System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture); } diff --git a/QuickFIXn/Fields/Converters/IntConverter.cs b/QuickFIXn/Fields/Converters/IntConverter.cs index 261fb0d8c..bb38bdb42 100644 --- a/QuickFIXn/Fields/Converters/IntConverter.cs +++ b/QuickFIXn/Fields/Converters/IntConverter.cs @@ -6,12 +6,7 @@ namespace QuickFix.Fields.Converters /// public static class IntConverter { - public const int ASCII_ZERO = 48; - public const int ASCII_NINE = 57; - public const int ASCII_MINUS = 45; - /// - /// TODO can we use NumberFormatInfo or NumberStyles to avoid this bit of ASCII hackery? /// Converts string to int. /// /// @@ -20,12 +15,7 @@ public static int Convert(string i) { try { - if ((null == i) || (i.Length < 1)) - throw new FieldConvertError("The argument string cannot be null or empty"); - int asciiValOfFirstChar = System.Convert.ToInt32(i[0]); - if ((asciiValOfFirstChar < ASCII_ZERO) || (asciiValOfFirstChar > ASCII_NINE)) - if (asciiValOfFirstChar != ASCII_MINUS) - throw new FieldConvertError("Could not convert string to int (" + i + "): The first character must be a digit or a minus sign"); + AsciiValidator.Validate(i); return System.Convert.ToInt32(i); } catch (System.FormatException e) @@ -34,7 +24,7 @@ public static int Convert(string i) } catch (System.OverflowException e) { - throw new FieldConvertError("Could not convert string to int(" + i + ")", e); + throw new FieldConvertError("Could not convert string to int (" + i + ")", e); } } diff --git a/QuickFIXn/Fields/Converters/ULongConverter.cs b/QuickFIXn/Fields/Converters/ULongConverter.cs new file mode 100644 index 000000000..efc4a7f42 --- /dev/null +++ b/QuickFIXn/Fields/Converters/ULongConverter.cs @@ -0,0 +1,39 @@ + +namespace QuickFix.Fields.Converters +{ + /// + /// convert UInt64 to/from string + /// + public static class ULongConverter + { + /// + /// Converts string to ulong. + /// + /// + /// + public static ulong Convert(string i) + { + try + { + AsciiValidator.Validate(i); + return System.Convert.ToUInt64(i); + } + catch (System.FormatException e) + { + throw new FieldConvertError("Could not convert string to ulong (" + i + ")", e); + } + catch (System.OverflowException e) + { + throw new FieldConvertError("Could not convert string to ulong (" + i + ")", e); + } + } + + /// + /// convert ulong to string + /// + public static string Convert(System.UInt64 i) + { + return i.ToString(); + } + } +} diff --git a/QuickFIXn/Fields/Fields.cs b/QuickFIXn/Fields/Fields.cs index 1da11bc56..d79af1630 100644 --- a/QuickFIXn/Fields/Fields.cs +++ b/QuickFIXn/Fields/Fields.cs @@ -108,13 +108,13 @@ public AvgPx(Decimal val) /// /// BeginSeqNo Field /// / - public sealed class BeginSeqNo : IntField + public sealed class BeginSeqNo : ULongField { public const int TAG = 7; public BeginSeqNo() :base(Tags.BeginSeqNo) {} - public BeginSeqNo(int val) + public BeginSeqNo(ulong val) :base(Tags.BeginSeqNo, val) {} } @@ -257,13 +257,13 @@ public Currency(string val) /// /// EndSeqNo Field /// / - public sealed class EndSeqNo : IntField + public sealed class EndSeqNo : ULongField { public const int TAG = 16; public EndSeqNo() :base(Tags.EndSeqNo) {} - public EndSeqNo(int val) + public EndSeqNo(ulong val) :base(Tags.EndSeqNo, val) {} } @@ -637,13 +637,13 @@ public LinesOfText(int val) /// /// MsgSeqNum Field /// / - public sealed class MsgSeqNum : IntField + public sealed class MsgSeqNum : ULongField { public const int TAG = 34; public MsgSeqNum() :base(Tags.MsgSeqNum) {} - public MsgSeqNum(int val) + public MsgSeqNum(ulong val) :base(Tags.MsgSeqNum, val) {} } @@ -664,16 +664,112 @@ public MsgType(string val) // Field Enumerations public const string HEARTBEAT = "0"; + public const string TEST_REQUEST = "1"; + public const string RESEND_REQUEST = "2"; + public const string REJECT = "3"; + public const string SEQUENCE_RESET = "4"; + public const string LOGOUT = "5"; + public const string INDICATION_OF_INTEREST = "6"; + public const string ADVERTISEMENT = "7"; + public const string EXECUTION_REPORT = "8"; + public const string ORDER_CANCEL_REJECT = "9"; + public const string LOGON = "A"; + public const string NEWS = "B"; + public const string EMAIL = "C"; + public const string ORDER_SINGLE = "D"; + public const string ORDER_LIST = "E"; + public const string ORDER_CANCEL_REQUEST = "F"; + public const string ORDER_CANCEL_REPLACE_REQUEST = "G"; + public const string ORDER_STATUS_REQUEST = "H"; + public const string ALLOCATION_INSTRUCTION = "J"; + public const string LIST_CANCEL_REQUEST = "K"; + public const string LIST_EXECUTE = "L"; + public const string LIST_STATUS_REQUEST = "M"; + public const string LIST_STATUS = "N"; + public const string ALLOCATION_INSTRUCTION_ACK = "P"; + public const string DONT_KNOW_TRADE = "Q"; + public const string QUOTE_REQUEST = "R"; + public const string QUOTE = "S"; + public const string SETTLEMENT_INSTRUCTIONS = "T"; + public const string MARKET_DATA_REQUEST = "V"; + public const string MARKET_DATA_SNAPSHOT_FULL_REFRESH = "W"; + public const string MARKET_DATA_INCREMENTAL_REFRESH = "X"; + public const string MARKET_DATA_REQUEST_REJECT = "Y"; + public const string QUOTE_CANCEL = "Z"; + public const string QUOTE_STATUS_REQUEST = "a"; + public const string MASS_QUOTE_ACKNOWLEDGEMENT = "b"; + public const string SECURITY_DEFINITION_REQUEST = "c"; + public const string SECURITY_DEFINITION = "d"; + public const string SECURITY_STATUS_REQUEST = "e"; + public const string SECURITY_STATUS = "f"; + public const string TRADING_SESSION_STATUS_REQUEST = "g"; + public const string TRADING_SESSION_STATUS = "h"; + public const string MASS_QUOTE = "i"; + public const string BUSINESS_MESSAGE_REJECT = "j"; + public const string BID_REQUEST = "k"; + public const string BID_RESPONSE = "l"; + public const string LIST_STRIKE_PRICE = "m"; + public const string XML_MESSAGE = "n"; + public const string REGISTRATION_INSTRUCTIONS = "o"; + public const string REGISTRATION_INSTRUCTIONS_RESPONSE = "p"; + public const string ORDER_MASS_CANCEL_REQUEST = "q"; + public const string ORDER_MASS_CANCEL_REPORT = "r"; + public const string NEW_ORDER_CROSS = "s"; + public const string CROSS_ORDER_CANCEL_REPLACE_REQUEST = "t"; + public const string CROSS_ORDER_CANCEL_REQUEST = "u"; + public const string SECURITY_TYPE_REQUEST = "v"; + public const string SECURITY_TYPES = "w"; + public const string SECURITY_LIST_REQUEST = "x"; + public const string SECURITY_LIST = "y"; + public const string DERIVATIVE_SECURITY_LIST_REQUEST = "z"; + public const string DERIVATIVE_SECURITY_LIST = "AA"; + public const string NEW_ORDER_MULTILEG = "AB"; + public const string MULTILEG_ORDER_CANCEL_REPLACE = "AC"; + public const string TRADE_CAPTURE_REPORT_REQUEST = "AD"; + public const string TRADE_CAPTURE_REPORT = "AE"; + public const string ORDER_MASS_STATUS_REQUEST = "AF"; + public const string QUOTE_REQUEST_REJECT = "AG"; + public const string RFQ_REQUEST = "AH"; + public const string QUOTE_STATUS_REPORT = "AI"; + public const string QUOTE_RESPONSE = "AJ"; + public const string CONFIRMATION = "AK"; + public const string POSITION_MAINTENANCE_REQUEST = "AL"; + public const string POSITION_MAINTENANCE_REPORT = "AM"; + public const string REQUEST_FOR_POSITIONS = "AN"; + public const string REQUEST_FOR_POSITIONS_ACK = "AO"; + public const string POSITION_REPORT = "AP"; + public const string TRADE_CAPTURE_REPORT_REQUEST_ACK = "AQ"; + public const string TRADE_CAPTURE_REPORT_ACK = "AR"; + public const string ALLOCATION_REPORT = "AS"; + public const string ALLOCATION_REPORT_ACK = "AT"; + public const string CONFIRMATION_ACK = "AU"; + public const string SETTLEMENT_INSTRUCTION_REQUEST = "AV"; + public const string ASSIGNMENT_REPORT = "AW"; + public const string COLLATERAL_REQUEST = "AX"; + public const string COLLATERAL_ASSIGNMENT = "AY"; + public const string COLLATERAL_RESPONSE = "AZ"; + public const string COLLATERAL_REPORT = "BA"; + public const string COLLATERAL_INQUIRY = "BB"; + public const string NETWORK_STATUS_REQUEST = "BC"; + public const string NETWORK_STATUS_RESPONSE = "BD"; + public const string USER_REQUEST = "BE"; + public const string USER_RESPONSE = "BF"; + public const string COLLATERAL_INQUIRY_ACK = "BG"; + public const string CONFIRMATION_REQUEST = "BH"; + public const string TRADING_SESSION_LIST_REQUEST = "BI"; + public const string TRADING_SESSION_LIST = "BJ"; + public const string SECURITY_LIST_UPDATE_REPORT = "BK"; + public const string ADJUSTED_POSITION_REPORT = "BL"; + public const string ALLOCATION_INSTRUCTION_ALERT = "BM"; + public const string EXECUTION_ACKNOWLEDGEMENT = "BN"; + public const string CONTRARY_INTENTION_REPORT = "BO"; + public const string SECURITY_DEFINITION_UPDATE_REPORT = "BP"; public const string TESTREQUEST = "1"; public const string RESENDREQUEST = "2"; - public const string REJECT = "3"; public const string SEQUENCERESET = "4"; - public const string LOGOUT = "5"; public const string IOI = "6"; - public const string ADVERTISEMENT = "7"; public const string EXECUTIONREPORT = "8"; public const string ORDERCANCELREJECT = "9"; - public const string LOGON = "A"; public const string DERIVATIVESECURITYLIST = "AA"; public const string NEWORDERMULTILEG = "AB"; public const string MULTILEGORDERCANCELREPLACE = "AC"; @@ -684,7 +780,6 @@ public MsgType(string val) public const string RFQREQUEST = "AH"; public const string QUOTESTATUSREPORT = "AI"; public const string QUOTERESPONSE = "AJ"; - public const string CONFIRMATION = "AK"; public const string POSITIONMAINTENANCEREQUEST = "AL"; public const string POSITIONMAINTENANCEREPORT = "AM"; public const string REQUESTFORPOSITIONS = "AN"; @@ -694,13 +789,11 @@ public MsgType(string val) public const string TRADECAPTUREREPORTACK = "AR"; public const string ALLOCATIONREPORT = "AS"; public const string ALLOCATIONREPORTACK = "AT"; - public const string CONFIRMATION_ACK = "AU"; public const string SETTLEMENTINSTRUCTIONREQUEST = "AV"; public const string ASSIGNMENTREPORT = "AW"; public const string COLLATERALREQUEST = "AX"; public const string COLLATERALASSIGNMENT = "AY"; public const string COLLATERALRESPONSE = "AZ"; - public const string NEWS = "B"; public const string COLLATERALREPORT = "BA"; public const string COLLATERALINQUIRY = "BB"; public const string NETWORKCOUNTERPARTYSYSTEMSTATUSREQUEST = "BC"; @@ -727,7 +820,6 @@ public MsgType(string val) public const string APPLICATIONMESSAGEREQUESTACK = "BX"; public const string APPLICATIONMESSAGEREPORT = "BY"; public const string ORDERMASSACTIONREPORT = "BZ"; - public const string EMAIL = "C"; public const string ORDERMASSACTIONREQUEST = "CA"; public const string USERNOTIFICATION = "CB"; public const string STREAMASSIGNMENTREQUEST = "CC"; @@ -748,7 +840,6 @@ public MsgType(string val) public const string ALLOCATIONINSTRUCTIONACK = "P"; public const string DONTKNOWTRADEDK = "Q"; public const string QUOTEREQUEST = "R"; - public const string QUOTE = "S"; public const string SETTLEMENTINSTRUCTIONS = "T"; public const string MARKETDATAREQUEST = "V"; public const string MARKETDATASNAPSHOTFULLREFRESH = "W"; @@ -781,105 +872,14 @@ public MsgType(string val) public const string SECURITYLISTREQUEST = "x"; public const string SECURITYLIST = "y"; public const string DERIVATIVESECURITYLISTREQUEST = "z"; - public const string TEST_REQUEST = "1"; - public const string RESEND_REQUEST = "2"; - public const string SEQUENCE_RESET = "4"; - public const string INDICATION_OF_INTEREST = "6"; - public const string EXECUTION_REPORT = "8"; - public const string ORDER_CANCEL_REJECT = "9"; - public const string QUOTE_STATUS_REQUEST = "a"; - public const string DERIVATIVE_SECURITY_LIST = "AA"; public const string NEW_ORDER_AB = "AB"; - public const string MULTILEG_ORDER_CANCEL_REPLACE = "AC"; - public const string TRADE_CAPTURE_REPORT_REQUEST = "AD"; - public const string TRADE_CAPTURE_REPORT = "AE"; - public const string ORDER_MASS_STATUS_REQUEST = "AF"; - public const string QUOTE_REQUEST_REJECT = "AG"; - public const string RFQ_REQUEST = "AH"; - public const string QUOTE_STATUS_REPORT = "AI"; - public const string QUOTE_RESPONSE = "AJ"; - public const string POSITION_MAINTENANCE_REQUEST = "AL"; - public const string POSITION_MAINTENANCE_REPORT = "AM"; - public const string REQUEST_FOR_POSITIONS = "AN"; - public const string REQUEST_FOR_POSITIONS_ACK = "AO"; - public const string POSITION_REPORT = "AP"; - public const string TRADE_CAPTURE_REPORT_REQUEST_ACK = "AQ"; - public const string TRADE_CAPTURE_REPORT_ACK = "AR"; - public const string ALLOCATION_REPORT = "AS"; - public const string ALLOCATION_REPORT_ACK = "AT"; - public const string SETTLEMENT_INSTRUCTION_REQUEST = "AV"; - public const string ASSIGNMENT_REPORT = "AW"; - public const string COLLATERAL_REQUEST = "AX"; - public const string COLLATERAL_ASSIGNMENT = "AY"; - public const string COLLATERAL_RESPONSE = "AZ"; - public const string MASS_QUOTE_ACKNOWLEDGEMENT = "b"; - public const string COLLATERAL_REPORT = "BA"; - public const string COLLATERAL_INQUIRY = "BB"; public const string NETWORK_COUNTERPARTY_SYSTEM_STATUS_REQUEST = "BC"; public const string NETWORK_COUNTERPARTY_SYSTEM_STATUS_RESPONSE = "BD"; - public const string USER_REQUEST = "BE"; - public const string USER_RESPONSE = "BF"; - public const string COLLATERAL_INQUIRY_ACK = "BG"; - public const string CONFIRMATION_REQUEST = "BH"; - public const string SECURITY_DEFINITION_REQUEST = "c"; - public const string SECURITY_DEFINITION = "d"; public const string NEW_ORDER_D = "D"; - public const string SECURITY_STATUS_REQUEST = "e"; public const string NEW_ORDER_E = "E"; - public const string ORDER_CANCEL_REQUEST = "F"; - public const string SECURITY_STATUS = "f"; - public const string ORDER_CANCEL_REPLACE_REQUEST = "G"; - public const string TRADING_SESSION_STATUS_REQUEST = "g"; - public const string ORDER_STATUS_REQUEST = "H"; - public const string TRADING_SESSION_STATUS = "h"; - public const string MASS_QUOTE = "i"; - public const string BUSINESS_MESSAGE_REJECT = "j"; - public const string ALLOCATION_INSTRUCTION = "J"; - public const string BID_REQUEST = "k"; - public const string LIST_CANCEL_REQUEST = "K"; - public const string BID_RESPONSE = "l"; - public const string LIST_EXECUTE = "L"; - public const string LIST_STRIKE_PRICE = "m"; - public const string LIST_STATUS_REQUEST = "M"; - public const string XML_MESSAGE = "n"; - public const string LIST_STATUS = "N"; - public const string REGISTRATION_INSTRUCTIONS = "o"; - public const string REGISTRATION_INSTRUCTIONS_RESPONSE = "p"; - public const string ALLOCATION_INSTRUCTION_ACK = "P"; - public const string ORDER_MASS_CANCEL_REQUEST = "q"; - public const string DONT_KNOW_TRADE = "Q"; - public const string QUOTE_REQUEST = "R"; - public const string ORDER_MASS_CANCEL_REPORT = "r"; public const string NEW_ORDER_s = "s"; - public const string SETTLEMENT_INSTRUCTIONS = "T"; - public const string CROSS_ORDER_CANCEL_REPLACE_REQUEST = "t"; - public const string CROSS_ORDER_CANCEL_REQUEST = "u"; - public const string MARKET_DATA_REQUEST = "V"; - public const string SECURITY_TYPE_REQUEST = "v"; - public const string SECURITY_TYPES = "w"; public const string MARKET_DATA_W = "W"; - public const string SECURITY_LIST_REQUEST = "x"; public const string MARKET_DATA_X = "X"; - public const string MARKET_DATA_REQUEST_REJECT = "Y"; - public const string SECURITY_LIST = "y"; - public const string QUOTE_CANCEL = "Z"; - public const string DERIVATIVE_SECURITY_LIST_REQUEST = "z"; - public const string CONTRARY_INTENTION_REPORT = "BO"; - public const string SECURITY_DEFINITION_UPDATE_REPORT = "BP"; - public const string SECURITY_LIST_UPDATE_REPORT = "BK"; - public const string ADJUSTED_POSITION_REPORT = "BL"; - public const string ALLOCATION_INSTRUCTION_ALERT = "BM"; - public const string EXECUTION_ACKNOWLEDGEMENT = "BN"; - public const string TRADING_SESSION_LIST = "BJ"; - public const string TRADING_SESSION_LIST_REQUEST = "BI"; - public const string ORDER_SINGLE = "D"; - public const string ORDER_LIST = "E"; - public const string MARKET_DATA_SNAPSHOT_FULL_REFRESH = "W"; - public const string MARKET_DATA_INCREMENTAL_REFRESH = "X"; - public const string NEW_ORDER_CROSS = "s"; - public const string NEW_ORDER_MULTILEG = "AB"; - public const string NETWORK_STATUS_REQUEST = "BC"; - public const string NETWORK_STATUS_RESPONSE = "BD"; public const string ORDER_CANCEL = "G"; public const string ALLOCATION = "J"; public const string ALLOCATION_ACK = "P"; @@ -892,13 +892,13 @@ public MsgType(string val) /// /// NewSeqNo Field /// / - public sealed class NewSeqNo : IntField + public sealed class NewSeqNo : ULongField { public const int TAG = 36; public NewSeqNo() :base(Tags.NewSeqNo) {} - public NewSeqNo(int val) + public NewSeqNo(ulong val) :base(Tags.NewSeqNo, val) {} } @@ -1083,13 +1083,13 @@ public Price(Decimal val) /// /// RefSeqNum Field /// / - public sealed class RefSeqNum : IntField + public sealed class RefSeqNum : ULongField { public const int TAG = 45; public RefSeqNum() :base(Tags.RefSeqNum) {} - public RefSeqNum(int val) + public RefSeqNum(ulong val) :base(Tags.RefSeqNum, val) {} } @@ -2067,19 +2067,19 @@ public EncryptMethod(int val) // Field Enumerations - public const int NONE = 0; - public const int PKCS_1 = 1; - public const int DES = 2; - public const int PKCS_3 = 3; - public const int PGP_4 = 4; - public const int PGP_5 = 5; - public const int PEM = 6; public const int NONE_OTHER = 0; public const int PKCS = 1; + public const int DES = 2; public const int PKCS_DES = 3; public const int PGP_DES = 4; public const int PGP_DES_MD5 = 5; public const int PEM_DES_MD5 = 6; + public const int NONE = 0; + public const int PKCS_1 = 1; + public const int PKCS_3 = 3; + public const int PGP_4 = 4; + public const int PGP_5 = 5; + public const int PEM = 6; public const int PKCS_PROPRIETARY = 1; public const int PKCSDES = 3; public const int PGPDES = 4; @@ -6454,13 +6454,13 @@ public QuoteEntryRejectReason(int val) /// /// LastMsgSeqNumProcessed Field /// / - public sealed class LastMsgSeqNumProcessed : IntField + public sealed class LastMsgSeqNumProcessed : ULongField { public const int TAG = 369; public LastMsgSeqNumProcessed() :base(Tags.LastMsgSeqNumProcessed) {} - public LastMsgSeqNumProcessed(int val) + public LastMsgSeqNumProcessed(ulong val) :base(Tags.LastMsgSeqNumProcessed, val) {} } @@ -12221,13 +12221,13 @@ public HopSendingTime(DateTime val, Converters.TimeStampPrecision precision) /// /// HopRefID Field /// / - public sealed class HopRefID : IntField + public sealed class HopRefID : ULongField { public const int TAG = 630; public HopRefID() :base(Tags.HopRefID) {} - public HopRefID(int val) + public HopRefID(ulong val) :base(Tags.HopRefID, val) {} } @@ -15184,13 +15184,13 @@ public TerminationType(int val) /// /// NextExpectedMsgSeqNum Field /// / - public sealed class NextExpectedMsgSeqNum : IntField + public sealed class NextExpectedMsgSeqNum : ULongField { public const int TAG = 789; public NextExpectedMsgSeqNum() :base(Tags.NextExpectedMsgSeqNum) {} - public NextExpectedMsgSeqNum(int val) + public NextExpectedMsgSeqNum(ulong val) :base(Tags.NextExpectedMsgSeqNum, val) {} } @@ -21987,13 +21987,13 @@ public ApplID(string val) /// /// ApplSeqNum Field /// / - public sealed class ApplSeqNum : IntField + public sealed class ApplSeqNum : ULongField { public const int TAG = 1181; public ApplSeqNum() :base(Tags.ApplSeqNum) {} - public ApplSeqNum(int val) + public ApplSeqNum(ulong val) :base(Tags.ApplSeqNum, val) {} } @@ -22002,13 +22002,13 @@ public ApplSeqNum(int val) /// /// ApplBegSeqNum Field /// / - public sealed class ApplBegSeqNum : IntField + public sealed class ApplBegSeqNum : ULongField { public const int TAG = 1182; public ApplBegSeqNum() :base(Tags.ApplBegSeqNum) {} - public ApplBegSeqNum(int val) + public ApplBegSeqNum(ulong val) :base(Tags.ApplBegSeqNum, val) {} } @@ -22017,13 +22017,13 @@ public ApplBegSeqNum(int val) /// /// ApplEndSeqNum Field /// / - public sealed class ApplEndSeqNum : IntField + public sealed class ApplEndSeqNum : ULongField { public const int TAG = 1183; public ApplEndSeqNum() :base(Tags.ApplEndSeqNum) {} - public ApplEndSeqNum(int val) + public ApplEndSeqNum(ulong val) :base(Tags.ApplEndSeqNum, val) {} } @@ -24568,13 +24568,13 @@ public ApplTotalMessageCount(int val) /// /// ApplLastSeqNum Field /// / - public sealed class ApplLastSeqNum : IntField + public sealed class ApplLastSeqNum : ULongField { public const int TAG = 1350; public ApplLastSeqNum() :base(Tags.ApplLastSeqNum) {} - public ApplLastSeqNum(int val) + public ApplLastSeqNum(ulong val) :base(Tags.ApplLastSeqNum, val) {} } @@ -24678,13 +24678,13 @@ public ApplReportID(string val) /// /// RefApplLastSeqNum Field /// / - public sealed class RefApplLastSeqNum : IntField + public sealed class RefApplLastSeqNum : ULongField { public const int TAG = 1357; public RefApplLastSeqNum() :base(Tags.RefApplLastSeqNum) {} - public RefApplLastSeqNum(int val) + public RefApplLastSeqNum(ulong val) :base(Tags.RefApplLastSeqNum, val) {} } @@ -25390,13 +25390,13 @@ public EncodedMktSegmDesc(string val) /// /// ApplNewSeqNum Field /// / - public sealed class ApplNewSeqNum : IntField + public sealed class ApplNewSeqNum : ULongField { public const int TAG = 1399; public ApplNewSeqNum() :base(Tags.ApplNewSeqNum) {} - public ApplNewSeqNum(int val) + public ApplNewSeqNum(ulong val) :base(Tags.ApplNewSeqNum, val) {} } diff --git a/QuickFIXn/Fields/ULongField.cs b/QuickFIXn/Fields/ULongField.cs new file mode 100644 index 000000000..6a30c7ad7 --- /dev/null +++ b/QuickFIXn/Fields/ULongField.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickFix.Fields +{ + /// + /// A ulong (System.UInt64) message field + /// + public class ULongField: FieldBase + { + public ULongField(int tag) + : base(tag, 0L) { } + + public ULongField(int tag, ulong val) + : base(tag, val) {} + + // quickfix compat + public ulong getValue() + { return Obj; } + + public void setValue(ulong v) + { Obj = v; } + + protected override string makeString() + { + return Converters.ULongConverter.Convert(Obj); + } + } +} diff --git a/QuickFIXn/FileStore.cs b/QuickFIXn/FileStore.cs index 47e2a3216..11378274b 100755 --- a/QuickFIXn/FileStore.cs +++ b/QuickFIXn/FileStore.cs @@ -33,7 +33,7 @@ public MsgDef(long index, int size) private MemoryStore cache_ = new MemoryStore(); - System.Collections.Generic.Dictionary offsets_ = new Dictionary(); + System.Collections.Generic.Dictionary offsets_ = new Dictionary(); public static string Prefix(SessionID sessionID) { @@ -132,7 +132,7 @@ private void ConstructFromFileCache() string[] headerParts = line.Split(','); if (headerParts.Length == 3) { - offsets_[Convert.ToInt32(headerParts[0])] = new MsgDef( + offsets_[Convert.ToUInt64(headerParts[0])] = new MsgDef( Convert.ToInt64(headerParts[1]), Convert.ToInt32(headerParts[2])); } } @@ -146,8 +146,8 @@ private void ConstructFromFileCache() string[] parts = seqNumReader.ReadToEnd().Split(':'); if (parts.Length == 2) { - cache_.NextSenderMsgSeqNum = Convert.ToInt32(parts[0]); - cache_.NextTargetMsgSeqNum = Convert.ToInt32(parts[1]); + cache_.NextSenderMsgSeqNum = Convert.ToUInt64(parts[0]); + cache_.NextTargetMsgSeqNum = Convert.ToUInt64(parts[1]); } } } @@ -181,9 +181,9 @@ private void InitializeSessionCreateTime() /// /// /// - public void Get(int startSeqNum, int endSeqNum, List messages) + public void Get(ulong startSeqNum, ulong endSeqNum, List messages) { - for (int i = startSeqNum; i <= endSeqNum; i++) + for (ulong i = startSeqNum; i <= endSeqNum; i++) { if (offsets_.ContainsKey(i)) { @@ -203,7 +203,7 @@ public void Get(int startSeqNum, int endSeqNum, List messages) /// /// /// - public bool Set(int msgSeqNum, string msg) + public bool Set(ulong msgSeqNum, string msg) { msgFile_.Seek(0, System.IO.SeekOrigin.End); @@ -225,7 +225,7 @@ public bool Set(int msgSeqNum, string msg) return true; } - public int NextSenderMsgSeqNum { + public ulong NextSenderMsgSeqNum { get { return cache_.NextSenderMsgSeqNum; } set { cache_.NextSenderMsgSeqNum = value; @@ -233,7 +233,7 @@ public int NextSenderMsgSeqNum { } } - public int NextTargetMsgSeqNum { + public ulong NextTargetMsgSeqNum { get { return cache_.NextTargetMsgSeqNum; } set { cache_.NextTargetMsgSeqNum = value; @@ -258,7 +258,7 @@ private void setSeqNum() seqNumsFile_.Seek(0, System.IO.SeekOrigin.Begin); System.IO.StreamWriter writer = new System.IO.StreamWriter(seqNumsFile_); - writer.Write(NextSenderMsgSeqNum.ToString("D10") + " : " + NextTargetMsgSeqNum.ToString("D10") + " "); + writer.Write(NextSenderMsgSeqNum.ToString("D20") + " : " + NextTargetMsgSeqNum.ToString("D20") + " "); writer.Flush(); } diff --git a/QuickFIXn/HttpServer.cs b/QuickFIXn/HttpServer.cs index 08916d88a..adb9b3d57 100644 --- a/QuickFIXn/HttpServer.cs +++ b/QuickFIXn/HttpServer.cs @@ -381,15 +381,15 @@ public string SessionDetails(HttpListenerRequest request) if (request.QueryString["next incoming"] != null) { - int value = Convert.ToInt16(request.QueryString["next incoming"]); - sessionDetails.NextTargetMsgSeqNum = value <= 0 ? 1 : value; + ulong val = Convert.ToUInt64(request.QueryString["next incoming"]); + sessionDetails.NextTargetMsgSeqNum = (val == 0 || val == System.UInt64.MaxValue) ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "next incoming"); } if (request.QueryString["Next Outgoing"] != null) { - int value = Convert.ToInt16(request.QueryString["Next Outgoing"]); - sessionDetails.NextSenderMsgSeqNum = value <= 0 ? 1 : value; + ulong val = Convert.ToUInt64(request.QueryString["Next Outgoing"]); + sessionDetails.NextSenderMsgSeqNum = (val == 0 || val == System.UInt64.MaxValue) ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "Next Outgoing"); } @@ -413,22 +413,22 @@ public string SessionDetails(HttpListenerRequest request) if (request.QueryString["MaxLatency"] != null) { - int value = Convert.ToInt16(request.QueryString["MaxLatency"]); - sessionDetails.MaxLatency = value <= 0 ? 1 : value; + int val = Convert.ToInt16(request.QueryString["MaxLatency"]); + sessionDetails.MaxLatency = val <= 0 ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "MaxLatency"); } if (request.QueryString["LogonTimeout"] != null) { - int value = Convert.ToInt16(request.QueryString["LogonTimeout"]); - sessionDetails.LogonTimeout = value <= 0 ? 1 : value; + int val = Convert.ToInt16(request.QueryString["LogonTimeout"]); + sessionDetails.LogonTimeout = val <= 0 ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "LogonTimeout"); } if (request.QueryString["LogoutTimeout"] != null) { - int value = Convert.ToInt16(request.QueryString["LogoutTimeout"]); - sessionDetails.LogoutTimeout = value <= 0 ? 1 : value; + int val = Convert.ToInt16(request.QueryString["LogoutTimeout"]); + sessionDetails.LogoutTimeout = val <= 0 ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "LogoutTimeout"); } @@ -520,30 +520,41 @@ public static string GetParameterList(string url) return HttpUtility.ParseQueryString((new Uri(url).Query)).ToString(); } - private static string AddRow(string colName, bool value, string url="") + private static string AddRow(string colName, bool val, string url="") { - string valueAsStr = value ? "yes" : "no"; + string valueAsStr = val ? "yes" : "no"; string innerHtml = url.Length > 0 - ? $"toggle" + ? $"toggle" : ""; return AddRow(colName, valueAsStr, innerHtml); } - private static string AddRow(string colName, int value, string url = "") + private static string AddRow(string colName, int val, string url = "") { - string innerHtml = $" << " + - $" < " + + string innerHtml = $" << " + + $" < " + " | " + - $" > " + - $" >> "; - return AddRow(colName, value.ToString(), innerHtml); + $" > " + + $" >> "; + return AddRow(colName, val.ToString(), innerHtml); } - private static string AddRow(string colName, string value, string innerHtml = "") + + private static string AddRow(string colName, ulong val, string url = "") + { + string innerHtml = $" << " + + $" < " + + " | " + + $" > " + + $" >> "; + return AddRow(colName, val.ToString(), innerHtml); + } + + private static string AddRow(string colName, string val, string innerHtml = "") { StringBuilder row = new StringBuilder(); row.Append(""); row.Append(AddCell(colName)); - row.Append(AddCell(value)); + row.Append(AddCell(val)); row.Append(AddCell(innerHtml)); row.Append(""); return row.ToString(); diff --git a/QuickFIXn/IMessageStore.cs b/QuickFIXn/IMessageStore.cs index 035413e9f..350c5820c 100755 --- a/QuickFIXn/IMessageStore.cs +++ b/QuickFIXn/IMessageStore.cs @@ -16,7 +16,7 @@ public interface IMessageStore : IDisposable /// the starting message sequence number /// the ending message sequence number /// the retrieved messages (out parameter) - void Get(int startSeqNum, int endSeqNum, List messages); + void Get(ulong startSeqNum, ulong endSeqNum, List messages); /// /// Adds a raw fix message to the store with the give sequence number @@ -24,10 +24,10 @@ public interface IMessageStore : IDisposable /// the sequence number /// the raw FIX message string /// true if successful, false otherwise - bool Set(int msgSeqNum, string msg); + bool Set(ulong msgSeqNum, string msg); - int NextSenderMsgSeqNum { get; set; } - int NextTargetMsgSeqNum { get; set; } + ulong NextSenderMsgSeqNum { get; set; } + ulong NextTargetMsgSeqNum { get; set; } void IncrNextSenderMsgSeqNum(); void IncrNextTargetMsgSeqNum(); diff --git a/QuickFIXn/MemoryStore.cs b/QuickFIXn/MemoryStore.cs index 97ba252c0..25ac0b872 100755 --- a/QuickFIXn/MemoryStore.cs +++ b/QuickFIXn/MemoryStore.cs @@ -10,20 +10,20 @@ public class MemoryStore : IMessageStore { #region Private Members - System.Collections.Generic.Dictionary messages_; + System.Collections.Generic.Dictionary messages_; DateTime? creationTime; #endregion public MemoryStore() { - messages_ = new System.Collections.Generic.Dictionary(); + messages_ = new System.Collections.Generic.Dictionary(); Reset(); } - public void Get(int begSeqNo, int endSeqNo, List messages) + public void Get(ulong begSeqNo, ulong endSeqNo, List messages) { - for (int current = begSeqNo; current <= endSeqNo; current++) + for (ulong current = begSeqNo; current <= endSeqNo; current++) { if (messages_.ContainsKey(current)) messages.Add(messages_[current]); @@ -32,14 +32,14 @@ public void Get(int begSeqNo, int endSeqNo, List messages) #region MessageStore Members - public bool Set(int msgSeqNum, string msg) + public bool Set(ulong msgSeqNum, string msg) { messages_[msgSeqNum] = msg; return true; } - public int NextSenderMsgSeqNum { get; set; } - public int NextTargetMsgSeqNum { get; set; } + public ulong NextSenderMsgSeqNum { get; set; } + public ulong NextTargetMsgSeqNum { get; set; } public void IncrNextSenderMsgSeqNum() { ++NextSenderMsgSeqNum; } diff --git a/QuickFIXn/Message/FieldMap.cs b/QuickFIXn/Message/FieldMap.cs index e12bea7e6..f44172fc0 100644 --- a/QuickFIXn/Message/FieldMap.cs +++ b/QuickFIXn/Message/FieldMap.cs @@ -167,6 +167,18 @@ public Fields.IntField GetField(Fields.IntField field) return field; } + /// + /// Gets a ulong field; saves its value into the parameter object, which is also the return value. + /// + /// this field's tag is used to extract the value from the message; that value is saved back into this object + /// thrown if isn't found + /// + public Fields.ULongField GetField(Fields.ULongField field) + { + field.Obj = GetULong(field.Tag); + return field; + } + /// /// Gets a decimal field; saves its value into the parameter object, which is also the return value. /// @@ -328,6 +340,28 @@ public int GetInt(int tag) } } + /// + /// Gets the ulong value of a field + /// + /// the FIX tag + /// the ulong field value + /// + public ulong GetULong(int tag) + { + try + { + Fields.IField fld = _fields[tag]; + if (fld.GetType() == typeof(ULongField)) + return ((ULongField)fld).Obj; + else + return ULongConverter.Convert(fld.ToString()); + } + catch (System.Collections.Generic.KeyNotFoundException) + { + throw new FieldNotFoundException(tag); + } + } + /// /// Gets the DateTime value of a field /// diff --git a/QuickFIXn/ResendRange.cs b/QuickFIXn/ResendRange.cs index 5ca7b0133..c6de501ff 100755 --- a/QuickFIXn/ResendRange.cs +++ b/QuickFIXn/ResendRange.cs @@ -2,15 +2,17 @@ { public class ResendRange { - public int BeginSeqNo { get; set; } - public int EndSeqNo { get; set; } - public int ChunkEndSeqNo { get; set; } + public const ulong NOT_SET = System.UInt64.MaxValue; + + public ulong BeginSeqNo { get; set; } + public ulong EndSeqNo { get; set; } + public ulong ChunkEndSeqNo { get; set; } public ResendRange() { BeginSeqNo = 0; EndSeqNo = 0; - ChunkEndSeqNo = -1; + ChunkEndSeqNo = ResendRange.NOT_SET; } public override string ToString() diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs index 3e9b8271b..c6b223648 100755 --- a/QuickFIXn/Session.cs +++ b/QuickFIXn/Session.cs @@ -76,7 +76,7 @@ public bool IsNewSession /// /// Gets or sets the next expected outgoing sequence number /// - public int NextSenderMsgSeqNum + public ulong NextSenderMsgSeqNum { get { @@ -91,7 +91,7 @@ public int NextSenderMsgSeqNum /// /// Gets or sets the next expected incoming sequence number /// - public int NextTargetMsgSeqNum + public ulong NextTargetMsgSeqNum { get { @@ -210,7 +210,7 @@ public TimeStampPrecision TimeStampPrecision /// /// Sets a maximum number of messages to request in a resend request. /// - public int MaxMessagesInResendRequest { get; set; } + public ulong MaxMessagesInResendRequest { get; set; } /// /// This is the FIX field value, e.g. "6" for FIX44 @@ -749,7 +749,7 @@ protected void NextLogon(Message logon) state_.SentReset = false; state_.ReceivedReset = false; - int msgSeqNum = logon.Header.GetInt(Fields.Tags.MsgSeqNum); + ulong msgSeqNum = logon.Header.GetULong(Fields.Tags.MsgSeqNum); if (IsTargetTooHigh(msgSeqNum) && !resetSeqNumFlag.Obj) { DoTargetTooHigh(logon, msgSeqNum); @@ -777,11 +777,11 @@ protected void NextResendRequest(Message resendReq) return; try { - int msgSeqNum = 0; + ulong msgSeqNum = 0; if (!(this.IgnorePossDupResendRequests && resendReq.Header.IsSetField(Tags.PossDupFlag))) { - int begSeqNo = resendReq.GetInt(Fields.Tags.BeginSeqNo); - int endSeqNo = resendReq.GetInt(Fields.Tags.EndSeqNo); + ulong begSeqNo = resendReq.GetULong(Fields.Tags.BeginSeqNo); + ulong endSeqNo = resendReq.GetULong(Fields.Tags.EndSeqNo); this.Log.OnEvent("Got resend request from " + begSeqNo + " to " + endSeqNo); if ((endSeqNo == 999999) || (endSeqNo == 0)) @@ -792,11 +792,11 @@ protected void NextResendRequest(Message resendReq) if (!PersistMessages) { endSeqNo++; - int next = state_.NextSenderMsgSeqNum; + ulong next = state_.NextSenderMsgSeqNum; if (endSeqNo > next) endSeqNo = next; GenerateSequenceReset(resendReq, begSeqNo, endSeqNo); - msgSeqNum = resendReq.Header.GetInt(Tags.MsgSeqNum); + msgSeqNum = resendReq.Header.GetULong(Tags.MsgSeqNum); if (!IsTargetTooHigh(msgSeqNum) && !IsTargetTooLow(msgSeqNum)) { state_.IncrNextTargetMsgSeqNum(); @@ -806,13 +806,13 @@ protected void NextResendRequest(Message resendReq) List messages = new List(); state_.Get(begSeqNo, endSeqNo, messages); - int current = begSeqNo; - int begin = 0; + ulong current = begSeqNo; + ulong begin = 0; foreach (string msgStr in messages) { Message msg = new Message(); msg.FromString(msgStr, true, this.SessionDataDictionary, this.ApplicationDataDictionary, msgFactory_); - msgSeqNum = msg.Header.GetInt(Tags.MsgSeqNum); + msgSeqNum = msg.Header.GetULong(Tags.MsgSeqNum); if ((current != msgSeqNum) && begin == 0) { @@ -845,7 +845,7 @@ protected void NextResendRequest(Message resendReq) current = msgSeqNum + 1; } - int nextSeqNum = state_.NextSenderMsgSeqNum; + ulong nextSeqNum = state_.NextSenderMsgSeqNum; if (++endSeqNo > nextSeqNum) { endSeqNo = nextSeqNum; @@ -861,7 +861,7 @@ protected void NextResendRequest(Message resendReq) GenerateSequenceReset(resendReq, begin, endSeqNo); } } - msgSeqNum = resendReq.Header.GetInt(Tags.MsgSeqNum); + msgSeqNum = resendReq.Header.GetULong(Tags.MsgSeqNum); if (!IsTargetTooHigh(msgSeqNum) && !IsTargetTooLow(msgSeqNum)) { state_.IncrNextTargetMsgSeqNum(); @@ -931,7 +931,7 @@ protected void NextSequenceReset(Message sequenceReset) if (sequenceReset.IsSetField(Fields.Tags.NewSeqNo)) { - int newSeqNo = sequenceReset.GetInt(Fields.Tags.NewSeqNo); + ulong newSeqNo = sequenceReset.GetULong(Fields.Tags.NewSeqNo); this.Log.OnEvent("Received SequenceReset FROM: " + state_.NextTargetMsgSeqNum + " TO: " + newSeqNo); if (newSeqNo > state_.NextTargetMsgSeqNum) @@ -953,7 +953,7 @@ public bool Verify(Message message) public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) { - int msgSeqNum = 0; + ulong msgSeqNum = 0; string msgType = ""; try @@ -970,7 +970,7 @@ public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) } if (checkTooHigh || checkTooLow) - msgSeqNum = msg.Header.GetInt(Fields.Tags.MsgSeqNum); + msgSeqNum = msg.Header.GetULong(Fields.Tags.MsgSeqNum); if (checkTooHigh && IsTargetTooHigh(msgSeqNum)) { @@ -994,7 +994,7 @@ public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) else if (msgSeqNum >= range.ChunkEndSeqNo) { this.Log.OnEvent("Chunked ResendRequest for messages FROM: " + range.BeginSeqNo + " TO: " + range.ChunkEndSeqNo + " has been satisfied."); - int newChunkEndSeqNo = Math.Min(range.EndSeqNo, range.ChunkEndSeqNo + this.MaxMessagesInResendRequest); + ulong newChunkEndSeqNo = Math.Min(range.EndSeqNo, range.ChunkEndSeqNo + this.MaxMessagesInResendRequest); GenerateResendRequestRange(msg.Header.GetString(Fields.Tags.BeginString), range.ChunkEndSeqNo + 1, newChunkEndSeqNo); range.ChunkEndSeqNo = newChunkEndSeqNo; } @@ -1095,17 +1095,17 @@ protected bool IsTimeToGenerateLogon() return true; } - protected bool IsTargetTooHigh(int msgSeqNum) + protected bool IsTargetTooHigh(ulong msgSeqNum) { return msgSeqNum > state_.NextTargetMsgSeqNum; } - protected bool IsTargetTooLow(int msgSeqNum) + protected bool IsTargetTooLow(ulong msgSeqNum) { return msgSeqNum < state_.NextTargetMsgSeqNum; } - protected void DoTargetTooHigh(Message msg, int msgSeqNum) + protected void DoTargetTooHigh(Message msg, ulong msgSeqNum) { string beginString = msg.Header.GetString(Fields.Tags.BeginString); @@ -1126,7 +1126,7 @@ protected void DoTargetTooHigh(Message msg, int msgSeqNum) GenerateResendRequest(beginString, msgSeqNum); } - protected void DoTargetTooLow(Message msg, int msgSeqNum) + protected void DoTargetTooLow(Message msg, ulong msgSeqNum) { bool possDupFlag = false; if (msg.Header.IsSetField(Fields.Tags.PossDupFlag)) @@ -1176,7 +1176,7 @@ protected void DoPossDup(Message msg) protected void GenerateBusinessMessageReject(Message message, int err, int field) { string msgType = message.Header.GetString(Tags.MsgType); - int msgSeqNum = message.Header.GetInt(Tags.MsgSeqNum); + ulong msgSeqNum = message.Header.GetULong(Tags.MsgSeqNum); string reason = FixValues.BusinessRejectReason.RejText[err]; Message reject; if (this.SessionID.BeginString.CompareTo(FixValues.BeginString.FIX42) >= 0) @@ -1202,7 +1202,7 @@ protected void GenerateBusinessMessageReject(Message message, int err, int field SendRaw(reject, 0); } - protected bool GenerateResendRequestRange(string beginString, int startSeqNum, int endSeqNum) + protected bool GenerateResendRequestRange(string beginString, ulong startSeqNum, ulong endSeqNum) { Message resendRequest = msgFactory_.Create(beginString, MsgType.RESEND_REQUEST); @@ -1222,11 +1222,11 @@ protected bool GenerateResendRequestRange(string beginString, int startSeqNum, i } } - protected bool GenerateResendRequest(string beginString, int msgSeqNum) + protected bool GenerateResendRequest(string beginString, ulong msgSeqNum) { - int beginSeqNum = state_.NextTargetMsgSeqNum; - int endRangeSeqNum = msgSeqNum - 1; - int endChunkSeqNum; + ulong beginSeqNum = state_.NextTargetMsgSeqNum; + ulong endRangeSeqNum = msgSeqNum - 1; + ulong endChunkSeqNum; if (this.MaxMessagesInResendRequest > 0) { endChunkSeqNum = Math.Min(endRangeSeqNum, beginSeqNum + this.MaxMessagesInResendRequest - 1); @@ -1288,7 +1288,7 @@ protected bool GenerateLogon(Message otherLogon) logon.SetField(new Fields.DefaultApplVerID(this.SenderDefaultApplVerID)); logon.SetField(new Fields.HeartBtInt(otherLogon.GetInt(Tags.HeartBtInt))); if (this.EnableLastMsgSeqNumProcessed) - logon.Header.SetField(new Fields.LastMsgSeqNumProcessed(otherLogon.Header.GetInt(Tags.MsgSeqNum))); + logon.Header.SetField(new Fields.LastMsgSeqNumProcessed(otherLogon.Header.GetULong(Tags.MsgSeqNum))); InitializeHeader(logon); state_.SentLogon = SendRaw(logon, 0); @@ -1348,7 +1348,7 @@ private bool GenerateLogout(Message other, string text) { try { - logout.Header.SetField(new Fields.LastMsgSeqNumProcessed(other.Header.GetInt(Tags.MsgSeqNum))); + logout.Header.SetField(new Fields.LastMsgSeqNumProcessed(other.Header.GetULong(Tags.MsgSeqNum))); } catch (FieldNotFoundException) { @@ -1375,7 +1375,7 @@ public bool GenerateHeartbeat(Message testRequest) heartbeat.SetField(new Fields.TestReqID(testRequest.GetString(Fields.Tags.TestReqID))); if (this.EnableLastMsgSeqNumProcessed) { - heartbeat.Header.SetField(new Fields.LastMsgSeqNumProcessed(testRequest.Header.GetInt(Tags.MsgSeqNum))); + heartbeat.Header.SetField(new Fields.LastMsgSeqNumProcessed(testRequest.Header.GetULong(Tags.MsgSeqNum))); } } catch (FieldNotFoundException) @@ -1413,12 +1413,12 @@ public bool GenerateReject(Message message, FixValues.SessionRejectReason reason else msgType = ""; - int msgSeqNum = 0; + ulong msgSeqNum = 0; if (message.Header.IsSetField(Fields.Tags.MsgSeqNum)) { try { - msgSeqNum = message.Header.GetInt(Fields.Tags.MsgSeqNum); + msgSeqNum = message.Header.GetULong(Fields.Tags.MsgSeqNum); reject.SetField(new Fields.RefSeqNum(msgSeqNum)); } catch (System.Exception) @@ -1493,7 +1493,7 @@ protected void PopulateRejectReason(Message reject, string text) /// /// /// - protected void InitializeHeader(Message m, int msgSeqNum) + protected void InitializeHeader(Message m, ulong msgSeqNum) { state_.LastSentTimeDT = DateTime.UtcNow; m.Header.SetField(new Fields.BeginString(this.SessionID.BeginString)); @@ -1540,7 +1540,7 @@ protected void Persist(Message message, string messageString) { if (this.PersistMessages) { - int msgSeqNum = message.Header.GetInt(Fields.Tags.MsgSeqNum); + ulong msgSeqNum = message.Header.GetULong(Fields.Tags.MsgSeqNum); state_.Set(msgSeqNum, messageString); } state_.IncrNextSenderMsgSeqNum(); @@ -1560,12 +1560,12 @@ protected bool IsGoodTime(Message msg) return true; } - private void GenerateSequenceReset(Message receivedMessage, int beginSeqNo, int endSeqNo) + private void GenerateSequenceReset(Message receivedMessage, ulong beginSeqNo, ulong endSeqNo) { string beginString = this.SessionID.BeginString; Message sequenceReset = msgFactory_.Create(beginString, Fields.MsgType.SEQUENCE_RESET); InitializeHeader(sequenceReset); - int newSeqNo = endSeqNo; + ulong newSeqNo = endSeqNo; sequenceReset.Header.SetField(new PossDupFlag(true)); InsertOrigSendingTime(sequenceReset.Header, sequenceReset.Header.GetDateTime(Tags.SendingTime)); @@ -1576,7 +1576,7 @@ private void GenerateSequenceReset(Message receivedMessage, int beginSeqNo, int { try { - sequenceReset.Header.SetField(new Fields.LastMsgSeqNumProcessed(receivedMessage.Header.GetInt(Tags.MsgSeqNum))); + sequenceReset.Header.SetField(new Fields.LastMsgSeqNumProcessed(receivedMessage.Header.GetULong(Tags.MsgSeqNum))); } catch (FieldNotFoundException) { @@ -1605,7 +1605,7 @@ protected void NextQueued() } } - protected bool NextQueued(int num) + protected bool NextQueued(ulong num) { Message msg = state_.Dequeue(num); @@ -1633,7 +1633,7 @@ private bool IsAdminMessage(Message msg) return AdminMsgTypes.Contains(msgType); } - protected bool SendRaw(Message message, int seqNum) + protected bool SendRaw(Message message, ulong seqNum) { lock (sync_) { diff --git a/QuickFIXn/SessionFactory.cs b/QuickFIXn/SessionFactory.cs index a714b4209..c5c66a509 100755 --- a/QuickFIXn/SessionFactory.cs +++ b/QuickFIXn/SessionFactory.cs @@ -146,7 +146,7 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings) if (settings.Has(SessionSettings.ENABLE_LAST_MSG_SEQ_NUM_PROCESSED)) session.EnableLastMsgSeqNumProcessed = settings.GetBool(SessionSettings.ENABLE_LAST_MSG_SEQ_NUM_PROCESSED); if (settings.Has(SessionSettings.MAX_MESSAGES_IN_RESEND_REQUEST)) - session.MaxMessagesInResendRequest = settings.GetInt(SessionSettings.MAX_MESSAGES_IN_RESEND_REQUEST); + session.MaxMessagesInResendRequest = settings.GetULong(SessionSettings.MAX_MESSAGES_IN_RESEND_REQUEST); if (settings.Has(SessionSettings.SEND_LOGOUT_BEFORE_TIMEOUT_DISCONNECT)) session.SendLogoutBeforeTimeoutDisconnect = settings.GetBool(SessionSettings.SEND_LOGOUT_BEFORE_TIMEOUT_DISCONNECT); if (settings.Has(SessionSettings.IGNORE_POSSDUP_RESEND_REQUESTS)) diff --git a/QuickFIXn/SessionState.cs b/QuickFIXn/SessionState.cs index 0d1f0aadf..961297fb7 100755 --- a/QuickFIXn/SessionState.cs +++ b/QuickFIXn/SessionState.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using MessagesBySeqNum = System.Collections.Generic.Dictionary; namespace QuickFix { @@ -29,7 +30,7 @@ public class SessionState : IDisposable private int logoutTimeout_ = 2; private long logoutTimeoutAsMilliSecs_ = 2 * 1000; private ResendRange resendRange_ = new ResendRange(); - private Dictionary msgQueue = new Dictionary(); + private MessagesBySeqNum msgQueue = new MessagesBySeqNum(); private ILog log_; @@ -147,7 +148,7 @@ public long LogoutTimeoutAsMilliSecs get { lock (sync_) { return logoutTimeoutAsMilliSecs_; } } } - private Dictionary MsgQueue + private MessagesBySeqNum MsgQueue { get { lock (sync_) { return msgQueue; } } set { lock (sync_) { msgQueue = value; } } @@ -273,7 +274,7 @@ public ResendRange GetResendRange() return resendRange_; } - public void Get(int begSeqNo, int endSeqNo, List messages) + public void Get(ulong begSeqNo, ulong endSeqNo, List messages) { lock (sync_) { @@ -281,16 +282,16 @@ public void Get(int begSeqNo, int endSeqNo, List messages) } } - public void SetResendRange(int begin, int end) + public void SetResendRange(ulong begin, ulong end) { - SetResendRange(begin, end, -1); + SetResendRange(begin, end, ResendRange.NOT_SET); } - public void SetResendRange(int begin, int end, int chunkEnd) + public void SetResendRange(ulong begin, ulong end, ulong chunkEnd) { resendRange_.BeginSeqNo = begin; resendRange_.EndSeqNo = end; - resendRange_.ChunkEndSeqNo = chunkEnd == -1 ? end : chunkEnd; + resendRange_.ChunkEndSeqNo = chunkEnd == ResendRange.NOT_SET ? end : chunkEnd; } public bool ResendRequested() @@ -298,7 +299,7 @@ public bool ResendRequested() return !(resendRange_.BeginSeqNo == 0 && resendRange_.EndSeqNo == 0); } - public void Queue(int msgSeqNum, Message msg) + public void Queue(ulong msgSeqNum, Message msg) { if (!MsgQueue.ContainsKey(msgSeqNum)) { @@ -311,7 +312,7 @@ public void ClearQueue() MsgQueue.Clear(); } - public QuickFix.Message Dequeue(int num) + public QuickFix.Message Dequeue(ulong num) { if (MsgQueue.ContainsKey(num)) { @@ -322,7 +323,7 @@ public QuickFix.Message Dequeue(int num) return null; } - public Message Retrieve(int msgSeqNum) + public Message Retrieve(ulong msgSeqNum) { Message msg = null; if (MsgQueue.ContainsKey(msgSeqNum)) @@ -355,18 +356,18 @@ public override string ToString() #region MessageStore-manipulating Members - public bool Set(int msgSeqNum, string msg) + public bool Set(ulong msgSeqNum, string msg) { lock (sync_) { return this.MessageStore.Set(msgSeqNum, msg); } } - public int NextSenderMsgSeqNum + public ulong NextSenderMsgSeqNum { get { lock (sync_) { return this.MessageStore.NextSenderMsgSeqNum; } } set { lock (sync_) { this.MessageStore.NextSenderMsgSeqNum = value; } } } - public int NextTargetMsgSeqNum + public ulong NextTargetMsgSeqNum { get { lock (sync_) { return this.MessageStore.NextTargetMsgSeqNum; } } set { lock (sync_) { this.MessageStore.NextTargetMsgSeqNum = value; } } diff --git a/UnitTests/FileStoreTests.cs b/UnitTests/FileStoreTests.cs index cd3529d51..e6a8ea92a 100755 --- a/UnitTests/FileStoreTests.cs +++ b/UnitTests/FileStoreTests.cs @@ -113,6 +113,45 @@ public void IncNextTargetMsgSeqNumTest() Assert.AreEqual(2, _store.NextTargetMsgSeqNum); } + /// Using UInt64 seqnums per FIX Trading Community Continuous Markets Working Group recommendations. + [Test] + public void TestSeqNumLimitsForContinuousMarkets() + { + // Given the next seqnums are UInt64.MaxValue - 1 + _store.NextSenderMsgSeqNum = System.UInt64.MaxValue - 1; + _store.NextTargetMsgSeqNum = _store.NextSenderMsgSeqNum; + + // When the next seqnums are incremented + _store.IncrNextSenderMsgSeqNum(); + _store.IncrNextTargetMsgSeqNum(); + + // Then the next seqnums should be UInt64.MaxValue + Assert.AreEqual(System.UInt64.MaxValue, _store.NextSenderMsgSeqNum); + Assert.AreEqual(System.UInt64.MaxValue, _store.NextTargetMsgSeqNum); + + // When the store is reloaded from files + RebuildStore(); + + // Then the next seqnums should still be UInt64.MaxValue + Assert.AreEqual(System.UInt64.MaxValue, _store.NextSenderMsgSeqNum); + Assert.AreEqual(System.UInt64.MaxValue, _store.NextTargetMsgSeqNum); + + // When the next seqnums are incremented again + _store.IncrNextSenderMsgSeqNum(); + _store.IncrNextTargetMsgSeqNum(); + + // Then the next seqnums should overflow to zero + Assert.AreEqual(0, _store.NextSenderMsgSeqNum); + Assert.AreEqual(0, _store.NextTargetMsgSeqNum); + + // When the store is reloaded from files + RebuildStore(); + + // Then the next seqnums should still be zero + Assert.AreEqual(0, _store.NextSenderMsgSeqNum); + Assert.AreEqual(0, _store.NextTargetMsgSeqNum); + } + [Test] public void ResetTest() { diff --git a/UnitTests/SessionStateTest.cs b/UnitTests/SessionStateTest.cs index 124d178c0..1fa975f55 100755 --- a/UnitTests/SessionStateTest.cs +++ b/UnitTests/SessionStateTest.cs @@ -159,7 +159,7 @@ public void ThreadSafeSetAndGet() { Hashtable getTable = new Hashtable(1000);//only used in 1 thread at a time //Synchronously populate 1000 messages - for (int i = 1; i < 1000; i++) { + for (ulong i = 1; i < 1000; i++) { string msg = "msg" + i; state.Set(i, msg); setTable[i] = msg; @@ -170,7 +170,7 @@ public void ThreadSafeSetAndGet() { ThreadPool.QueueUserWorkItem(delegate(object stateObject) { AutoResetEvent internalSetEvent = (AutoResetEvent)((object[])stateObject)[0]; SessionState internalState = (SessionState)((object[])stateObject)[1]; - for (int i = 1001; i < 2000; i++) { + for (ulong i = 1001; i < 2000; i++) { try { internalState.Set(i, "msg" + i); } @@ -188,7 +188,7 @@ public void ThreadSafeSetAndGet() { ThreadPool.QueueUserWorkItem(delegate(object stateObject){ AutoResetEvent internalGetEvent = (AutoResetEvent)((object[])stateObject)[0]; SessionState internalState = (SessionState)((object[])stateObject)[1]; - for (int i = 1; i < 1000; i++) { + for (ulong i = 1; i < 1000; i++) { try { List lst = new List(1); internalState.Get(i, i, lst); diff --git a/UnitTests/SessionTest.cs b/UnitTests/SessionTest.cs index ba0210dd6..33528e181 100755 --- a/UnitTests/SessionTest.cs +++ b/UnitTests/SessionTest.cs @@ -175,7 +175,7 @@ public class SessionTest QuickFix.Session session = null; QuickFix.Session session2 = null; QuickFix.Dictionary config = null; - int seqNum = 1; + ulong seqNum = 1; Regex msRegex = new Regex(@"\.[\d]{1,3}$"); Regex microsecondRegex = new Regex(@"\.[\d]{1,6}$"); @@ -348,14 +348,14 @@ public void SendNOSMessage() session.Next(order.ToString()); } - public void SendResendRequest(int begin, int end) + public void SendResendRequest(ulong begin, ulong end) { SendTheMessage(new QuickFix.FIX42.ResendRequest( new QuickFix.Fields.BeginSeqNo(begin), new QuickFix.Fields.EndSeqNo(end))); } - public void SendResendRequest40(int begin, int end) + public void SendResendRequest40(ulong begin, ulong end) { SendTheMessage(new QuickFix.FIX40.ResendRequest( new QuickFix.Fields.BeginSeqNo(begin), @@ -458,30 +458,30 @@ public void TestGapFillOnResend() order.Header.SetField(new QuickFix.Fields.TargetCompID(sessionID.TargetCompID)); order.Header.SetField(new QuickFix.Fields.SenderCompID(sessionID.SenderCompID)); - int[] gapStarts = new[] { 1, 5, 11 }; // 1st gap from seq num 1 to 2 is just the Logon message - int[] gapEnds = new[] { 2, 8, 15 }; + ulong[] gapStarts = new[] { 1UL, 5UL, 11UL }; // 1st gap from seq num 1 to 2 is just the Logon message + ulong[] gapEnds = new[] { 2UL, 8UL, 15UL }; int orderCount = 0; - for (int msgSeqNum = gapEnds[0]; msgSeqNum < gapStarts[1]; ++msgSeqNum) + for (ulong msgSeqNum = gapEnds[0]; msgSeqNum < gapStarts[1]; ++msgSeqNum) { order.Header.SetField(new QuickFix.Fields.MsgSeqNum(msgSeqNum)); session.Send(order); ++orderCount; } //seq 4, next is 5 - for (int msgSeqNum = gapStarts[1]; msgSeqNum < gapEnds[1]; ++msgSeqNum) + for (ulong msgSeqNum = gapStarts[1]; msgSeqNum < gapEnds[1]; ++msgSeqNum) { session.GenerateHeartbeat(); } //seq 7, next is 8 - for (int msgSeqNum = gapEnds[1]; msgSeqNum < gapStarts[2]; ++msgSeqNum) + for (ulong msgSeqNum = gapEnds[1]; msgSeqNum < gapStarts[2]; ++msgSeqNum) { order.Header.SetField(new QuickFix.Fields.MsgSeqNum(msgSeqNum)); session.Send(order); ++orderCount; } //seq 10, next is 11 - for (int msgSeqNum = gapStarts[2]; msgSeqNum < gapEnds[2]; ++msgSeqNum) + for (ulong msgSeqNum = gapStarts[2]; msgSeqNum < gapEnds[2]; ++msgSeqNum) { session.GenerateHeartbeat(); } // seq 11 - 14 @@ -496,7 +496,7 @@ public void TestGapFillOnResend() foreach (QuickFix.Message sequenceResestMsg in responder.msgLookup[QuickFix.Fields.MsgType.SEQUENCE_RESET]) { Assert.AreEqual(sequenceResestMsg.GetString(QuickFix.Fields.Tags.GapFillFlag), "Y"); - Assert.AreEqual(sequenceResestMsg.Header.GetInt(QuickFix.Fields.Tags.MsgSeqNum), gapStarts[++count]); + Assert.AreEqual(sequenceResestMsg.Header.GetULong(QuickFix.Fields.Tags.MsgSeqNum), gapStarts[++count]); Assert.AreEqual(sequenceResestMsg.GetInt(QuickFix.Fields.Tags.NewSeqNo), gapEnds[count]); } } @@ -654,7 +654,7 @@ public void TestLastMsgSeqNumProcessed() // Logon Logon(); QuickFix.Message msg = responder.msgLookup[QuickFix.Fields.MsgType.LOGON].Last(); - int lastSeqNumProcessed = msg.Header.GetInt(QuickFix.Fields.Tags.LastMsgSeqNumProcessed); + ulong lastSeqNumProcessed = msg.Header.GetULong(QuickFix.Fields.Tags.LastMsgSeqNumProcessed); Assert.That(lastSeqNumProcessed == 1); // NOS @@ -672,7 +672,7 @@ public void TestLastMsgSeqNumProcessed() session.Send(order); msg = responder.msgLookup[QuickFix.Fields.MsgType.NEW_ORDER_D].Last(); - lastSeqNumProcessed = msg.Header.GetInt(QuickFix.Fields.Tags.LastMsgSeqNumProcessed); + lastSeqNumProcessed = msg.Header.GetULong(QuickFix.Fields.Tags.LastMsgSeqNumProcessed); Assert.That(lastSeqNumProcessed == 1); } diff --git a/generator/fields_gen.rb b/generator/fields_gen.rb index dcc315f99..f69781871 100644 --- a/generator/fields_gen.rb +++ b/generator/fields_gen.rb @@ -13,8 +13,10 @@ def self.type_info( field ) case field[:fldtype] when 'CHAR' {:cs_class => 'CharField', :base_type=>'char'} - when 'INT', 'NUMINGROUP', 'SEQNUM', 'LENGTH' + when 'INT', 'NUMINGROUP', 'LENGTH' {:cs_class => 'IntField', :base_type=>'int'} + when 'SEQNUM' + {:cs_class => 'ULongField', :base_type=>'ulong'} when 'AMT', 'PERCENTAGE', 'PRICE', 'QTY', 'PRICEOFFSET', 'FLOAT' {:cs_class => 'DecimalField', :base_type=>'Decimal'} when 'UTCTIMESTAMP', 'TZTIMESTAMP', 'TIME' diff --git a/generator/message_factory_gen.rb b/generator/message_factory_gen.rb index 55bb4b15b..3f69a6075 100644 --- a/generator/message_factory_gen.rb +++ b/generator/message_factory_gen.rb @@ -1,7 +1,7 @@ class MessageFactoryGen def self.generate(messages, dir, fixver) destdir = File.join(dir,fixver) - Dir.mkdir(destdir) unless File.exists?(destdir) + Dir.mkdir(destdir) unless File.exist?(destdir) file_path = File.join(destdir,"MessageFactory.cs") puts 'generate ' + file_path diff --git a/generator/messages_gen.rb b/generator/messages_gen.rb index da5c96020..2c03218ef 100644 --- a/generator/messages_gen.rb +++ b/generator/messages_gen.rb @@ -3,7 +3,7 @@ class MessageGen def self.generate messages, dir, fixver destdir = File.join(dir, fixver) - Dir.mkdir(destdir) unless File.exists? destdir + Dir.mkdir(destdir) unless File.exist? destdir basemsgstr = gen_basemsg(fixver,destdir) basemsg_path = File.join(destdir, "Message.cs") diff --git a/spec/fix/FIX40.xml b/spec/fix/FIX40.xml index 08bd0e7d9..455e91e89 100644 --- a/spec/fix/FIX40.xml +++ b/spec/fix/FIX40.xml @@ -463,7 +463,7 @@ - + @@ -476,7 +476,7 @@ - + @@ -548,9 +548,9 @@ - + - + @@ -592,7 +592,7 @@ - + diff --git a/spec/fix/FIX41.xml b/spec/fix/FIX41.xml index d1d470eb1..430fdfe9f 100644 --- a/spec/fix/FIX41.xml +++ b/spec/fix/FIX41.xml @@ -689,7 +689,7 @@ - + @@ -702,7 +702,7 @@ - + @@ -778,9 +778,9 @@ - + - + @@ -825,7 +825,7 @@ - + diff --git a/spec/fix/FIX42.xml b/spec/fix/FIX42.xml index d209e06d4..575fc6230 100644 --- a/spec/fix/FIX42.xml +++ b/spec/fix/FIX42.xml @@ -1615,7 +1615,7 @@ - + @@ -1628,7 +1628,7 @@ - + @@ -1708,9 +1708,9 @@ - + - + @@ -1758,7 +1758,7 @@ - + @@ -2491,7 +2491,7 @@ - + From 8fb01ff18cd86daaaab9876f9fa5363593b31819 Mon Sep 17 00:00:00 2001 From: Mike Gatny Date: Fri, 12 May 2023 09:01:20 -0400 Subject: [PATCH 2/5] Shell scripts for building on not-windows --- build.sh | 9 +++++++++ unit_test.sh | 12 ++++++++++++ 2 files changed, 21 insertions(+) create mode 100755 build.sh create mode 100755 unit_test.sh diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..20d574efd --- /dev/null +++ b/build.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +CONFIGURATION=$1 + +[ -z $CONFIGURATION ] && CONFIGURATION=Release + +BUILD_CMD="dotnet build -c ${CONFIGURATION}" +echo "Build command: $BUILD_CMD" +exec $BUILD_CMD diff --git a/unit_test.sh b/unit_test.sh new file mode 100755 index 000000000..3ce0c58df --- /dev/null +++ b/unit_test.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# + +RESULT=0 + +set +e + +dotnet test -c Release --no-build --no-restore UnitTests -l trx + +RESULT=$? + +exit $RESULT From 56482f962a41ac54df415090f607645580b461f3 Mon Sep 17 00:00:00 2001 From: Mike Gatny Date: Fri, 12 May 2023 09:35:42 -0400 Subject: [PATCH 3/5] Alias ulong to SeqNumType vs using it directly Should make it slightly easier to change the underlying type in the future if we ever has to revisit this, or if someone encounters an issue with using ulong instead of int for seqnums. --- QuickFIXn/Fields/Fields.cs | 58 ++++++++++++++++---------------- QuickFIXn/FileStore.cs | 13 ++++---- QuickFIXn/HttpServer.cs | 11 +++--- QuickFIXn/IMessageStore.cs | 9 ++--- QuickFIXn/MemoryStore.cs | 15 +++++---- QuickFIXn/ResendRange.cs | 12 ++++--- QuickFIXn/Session.cs | 63 ++++++++++++++++++----------------- QuickFIXn/SessionState.cs | 19 ++++++----- UnitTests/SessionStateTest.cs | 7 ++-- UnitTests/SessionTest.cs | 21 ++++++------ 10 files changed, 120 insertions(+), 108 deletions(-) diff --git a/QuickFIXn/Fields/Fields.cs b/QuickFIXn/Fields/Fields.cs index d79af1630..7ab9b1af0 100644 --- a/QuickFIXn/Fields/Fields.cs +++ b/QuickFIXn/Fields/Fields.cs @@ -1,6 +1,8 @@ // This is a generated file. Don't edit it directly! using System; +using SeqNumType = System.UInt64; +using SeqNumFieldType = QuickFix.Fields.ULongField; namespace QuickFix.Fields { @@ -108,13 +110,13 @@ public AvgPx(Decimal val) /// /// BeginSeqNo Field /// / - public sealed class BeginSeqNo : ULongField + public sealed class BeginSeqNo : SeqNumFieldType { public const int TAG = 7; public BeginSeqNo() :base(Tags.BeginSeqNo) {} - public BeginSeqNo(ulong val) + public BeginSeqNo(SeqNumType val) :base(Tags.BeginSeqNo, val) {} } @@ -257,13 +259,13 @@ public Currency(string val) /// /// EndSeqNo Field /// / - public sealed class EndSeqNo : ULongField + public sealed class EndSeqNo : SeqNumFieldType { public const int TAG = 16; public EndSeqNo() :base(Tags.EndSeqNo) {} - public EndSeqNo(ulong val) + public EndSeqNo(SeqNumType val) :base(Tags.EndSeqNo, val) {} } @@ -637,13 +639,13 @@ public LinesOfText(int val) /// /// MsgSeqNum Field /// / - public sealed class MsgSeqNum : ULongField + public sealed class MsgSeqNum : SeqNumFieldType { public const int TAG = 34; public MsgSeqNum() :base(Tags.MsgSeqNum) {} - public MsgSeqNum(ulong val) + public MsgSeqNum(SeqNumType val) :base(Tags.MsgSeqNum, val) {} } @@ -892,13 +894,13 @@ public MsgType(string val) /// /// NewSeqNo Field /// / - public sealed class NewSeqNo : ULongField + public sealed class NewSeqNo : SeqNumFieldType { public const int TAG = 36; public NewSeqNo() :base(Tags.NewSeqNo) {} - public NewSeqNo(ulong val) + public NewSeqNo(SeqNumType val) :base(Tags.NewSeqNo, val) {} } @@ -1083,13 +1085,13 @@ public Price(Decimal val) /// /// RefSeqNum Field /// / - public sealed class RefSeqNum : ULongField + public sealed class RefSeqNum : SeqNumFieldType { public const int TAG = 45; public RefSeqNum() :base(Tags.RefSeqNum) {} - public RefSeqNum(ulong val) + public RefSeqNum(SeqNumType val) :base(Tags.RefSeqNum, val) {} } @@ -6454,13 +6456,13 @@ public QuoteEntryRejectReason(int val) /// /// LastMsgSeqNumProcessed Field /// / - public sealed class LastMsgSeqNumProcessed : ULongField + public sealed class LastMsgSeqNumProcessed : SeqNumFieldType { public const int TAG = 369; public LastMsgSeqNumProcessed() :base(Tags.LastMsgSeqNumProcessed) {} - public LastMsgSeqNumProcessed(ulong val) + public LastMsgSeqNumProcessed(SeqNumType val) :base(Tags.LastMsgSeqNumProcessed, val) {} } @@ -12221,13 +12223,13 @@ public HopSendingTime(DateTime val, Converters.TimeStampPrecision precision) /// /// HopRefID Field /// / - public sealed class HopRefID : ULongField + public sealed class HopRefID : SeqNumFieldType { public const int TAG = 630; public HopRefID() :base(Tags.HopRefID) {} - public HopRefID(ulong val) + public HopRefID(SeqNumType val) :base(Tags.HopRefID, val) {} } @@ -15184,13 +15186,13 @@ public TerminationType(int val) /// /// NextExpectedMsgSeqNum Field /// / - public sealed class NextExpectedMsgSeqNum : ULongField + public sealed class NextExpectedMsgSeqNum : SeqNumFieldType { public const int TAG = 789; public NextExpectedMsgSeqNum() :base(Tags.NextExpectedMsgSeqNum) {} - public NextExpectedMsgSeqNum(ulong val) + public NextExpectedMsgSeqNum(SeqNumType val) :base(Tags.NextExpectedMsgSeqNum, val) {} } @@ -21987,13 +21989,13 @@ public ApplID(string val) /// /// ApplSeqNum Field /// / - public sealed class ApplSeqNum : ULongField + public sealed class ApplSeqNum : SeqNumFieldType { public const int TAG = 1181; public ApplSeqNum() :base(Tags.ApplSeqNum) {} - public ApplSeqNum(ulong val) + public ApplSeqNum(SeqNumType val) :base(Tags.ApplSeqNum, val) {} } @@ -22002,13 +22004,13 @@ public ApplSeqNum(ulong val) /// /// ApplBegSeqNum Field /// / - public sealed class ApplBegSeqNum : ULongField + public sealed class ApplBegSeqNum : SeqNumFieldType { public const int TAG = 1182; public ApplBegSeqNum() :base(Tags.ApplBegSeqNum) {} - public ApplBegSeqNum(ulong val) + public ApplBegSeqNum(SeqNumType val) :base(Tags.ApplBegSeqNum, val) {} } @@ -22017,13 +22019,13 @@ public ApplBegSeqNum(ulong val) /// /// ApplEndSeqNum Field /// / - public sealed class ApplEndSeqNum : ULongField + public sealed class ApplEndSeqNum : SeqNumFieldType { public const int TAG = 1183; public ApplEndSeqNum() :base(Tags.ApplEndSeqNum) {} - public ApplEndSeqNum(ulong val) + public ApplEndSeqNum(SeqNumType val) :base(Tags.ApplEndSeqNum, val) {} } @@ -24568,13 +24570,13 @@ public ApplTotalMessageCount(int val) /// /// ApplLastSeqNum Field /// / - public sealed class ApplLastSeqNum : ULongField + public sealed class ApplLastSeqNum : SeqNumFieldType { public const int TAG = 1350; public ApplLastSeqNum() :base(Tags.ApplLastSeqNum) {} - public ApplLastSeqNum(ulong val) + public ApplLastSeqNum(SeqNumType val) :base(Tags.ApplLastSeqNum, val) {} } @@ -24678,13 +24680,13 @@ public ApplReportID(string val) /// /// RefApplLastSeqNum Field /// / - public sealed class RefApplLastSeqNum : ULongField + public sealed class RefApplLastSeqNum : SeqNumFieldType { public const int TAG = 1357; public RefApplLastSeqNum() :base(Tags.RefApplLastSeqNum) {} - public RefApplLastSeqNum(ulong val) + public RefApplLastSeqNum(SeqNumType val) :base(Tags.RefApplLastSeqNum, val) {} } @@ -25390,13 +25392,13 @@ public EncodedMktSegmDesc(string val) /// /// ApplNewSeqNum Field /// / - public sealed class ApplNewSeqNum : ULongField + public sealed class ApplNewSeqNum : SeqNumFieldType { public const int TAG = 1399; public ApplNewSeqNum() :base(Tags.ApplNewSeqNum) {} - public ApplNewSeqNum(ulong val) + public ApplNewSeqNum(SeqNumType val) :base(Tags.ApplNewSeqNum, val) {} } diff --git a/QuickFIXn/FileStore.cs b/QuickFIXn/FileStore.cs index 11378274b..c6faf9c11 100755 --- a/QuickFIXn/FileStore.cs +++ b/QuickFIXn/FileStore.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using QuickFix.Util; +using SeqNumType = System.UInt64; namespace QuickFix { @@ -33,7 +34,7 @@ public MsgDef(long index, int size) private MemoryStore cache_ = new MemoryStore(); - System.Collections.Generic.Dictionary offsets_ = new Dictionary(); + System.Collections.Generic.Dictionary offsets_ = new Dictionary(); public static string Prefix(SessionID sessionID) { @@ -181,9 +182,9 @@ private void InitializeSessionCreateTime() /// /// /// - public void Get(ulong startSeqNum, ulong endSeqNum, List messages) + public void Get(SeqNumType startSeqNum, SeqNumType endSeqNum, List messages) { - for (ulong i = startSeqNum; i <= endSeqNum; i++) + for (SeqNumType i = startSeqNum; i <= endSeqNum; i++) { if (offsets_.ContainsKey(i)) { @@ -203,7 +204,7 @@ public void Get(ulong startSeqNum, ulong endSeqNum, List messages) /// /// /// - public bool Set(ulong msgSeqNum, string msg) + public bool Set(SeqNumType msgSeqNum, string msg) { msgFile_.Seek(0, System.IO.SeekOrigin.End); @@ -225,7 +226,7 @@ public bool Set(ulong msgSeqNum, string msg) return true; } - public ulong NextSenderMsgSeqNum { + public SeqNumType NextSenderMsgSeqNum { get { return cache_.NextSenderMsgSeqNum; } set { cache_.NextSenderMsgSeqNum = value; @@ -233,7 +234,7 @@ public ulong NextSenderMsgSeqNum { } } - public ulong NextTargetMsgSeqNum { + public SeqNumType NextTargetMsgSeqNum { get { return cache_.NextTargetMsgSeqNum; } set { cache_.NextTargetMsgSeqNum = value; diff --git a/QuickFIXn/HttpServer.cs b/QuickFIXn/HttpServer.cs index adb9b3d57..0b83c151a 100644 --- a/QuickFIXn/HttpServer.cs +++ b/QuickFIXn/HttpServer.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Web; using QuickFix; +using SeqNumType = System.UInt64; namespace Acceptor { @@ -381,15 +382,15 @@ public string SessionDetails(HttpListenerRequest request) if (request.QueryString["next incoming"] != null) { - ulong val = Convert.ToUInt64(request.QueryString["next incoming"]); - sessionDetails.NextTargetMsgSeqNum = (val == 0 || val == System.UInt64.MaxValue) ? 1 : val; + SeqNumType val = Convert.ToUInt64(request.QueryString["next incoming"]); + sessionDetails.NextTargetMsgSeqNum = (val == 0 || val == SeqNumType.MaxValue) ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "next incoming"); } if (request.QueryString["Next Outgoing"] != null) { - ulong val = Convert.ToUInt64(request.QueryString["Next Outgoing"]); - sessionDetails.NextSenderMsgSeqNum = (val == 0 || val == System.UInt64.MaxValue) ? 1 : val; + SeqNumType val = Convert.ToUInt64(request.QueryString["Next Outgoing"]); + sessionDetails.NextSenderMsgSeqNum = (val == 0 || val == SeqNumType.MaxValue) ? 1 : val; url = RemoveQueryStringByKey(urlOriginalString, "Next Outgoing"); } @@ -539,7 +540,7 @@ private static string AddRow(string colName, int val, string url = "") return AddRow(colName, val.ToString(), innerHtml); } - private static string AddRow(string colName, ulong val, string url = "") + private static string AddRow(string colName, SeqNumType val, string url = "") { string innerHtml = $" << " + $" < " + diff --git a/QuickFIXn/IMessageStore.cs b/QuickFIXn/IMessageStore.cs index 350c5820c..063d6d86a 100755 --- a/QuickFIXn/IMessageStore.cs +++ b/QuickFIXn/IMessageStore.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System; +using SeqNumType = System.UInt64; namespace QuickFix { @@ -16,7 +17,7 @@ public interface IMessageStore : IDisposable /// the starting message sequence number /// the ending message sequence number /// the retrieved messages (out parameter) - void Get(ulong startSeqNum, ulong endSeqNum, List messages); + void Get(SeqNumType startSeqNum, SeqNumType endSeqNum, List messages); /// /// Adds a raw fix message to the store with the give sequence number @@ -24,10 +25,10 @@ public interface IMessageStore : IDisposable /// the sequence number /// the raw FIX message string /// true if successful, false otherwise - bool Set(ulong msgSeqNum, string msg); + bool Set(SeqNumType msgSeqNum, string msg); - ulong NextSenderMsgSeqNum { get; set; } - ulong NextTargetMsgSeqNum { get; set; } + SeqNumType NextSenderMsgSeqNum { get; set; } + SeqNumType NextTargetMsgSeqNum { get; set; } void IncrNextSenderMsgSeqNum(); void IncrNextTargetMsgSeqNum(); diff --git a/QuickFIXn/MemoryStore.cs b/QuickFIXn/MemoryStore.cs index 25ac0b872..2a9e77c4d 100755 --- a/QuickFIXn/MemoryStore.cs +++ b/QuickFIXn/MemoryStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SeqNumType = System.UInt64; namespace QuickFix { @@ -10,20 +11,20 @@ public class MemoryStore : IMessageStore { #region Private Members - System.Collections.Generic.Dictionary messages_; + System.Collections.Generic.Dictionary messages_; DateTime? creationTime; #endregion public MemoryStore() { - messages_ = new System.Collections.Generic.Dictionary(); + messages_ = new System.Collections.Generic.Dictionary(); Reset(); } - public void Get(ulong begSeqNo, ulong endSeqNo, List messages) + public void Get(SeqNumType begSeqNo, SeqNumType endSeqNo, List messages) { - for (ulong current = begSeqNo; current <= endSeqNo; current++) + for (SeqNumType current = begSeqNo; current <= endSeqNo; current++) { if (messages_.ContainsKey(current)) messages.Add(messages_[current]); @@ -32,14 +33,14 @@ public void Get(ulong begSeqNo, ulong endSeqNo, List messages) #region MessageStore Members - public bool Set(ulong msgSeqNum, string msg) + public bool Set(SeqNumType msgSeqNum, string msg) { messages_[msgSeqNum] = msg; return true; } - public ulong NextSenderMsgSeqNum { get; set; } - public ulong NextTargetMsgSeqNum { get; set; } + public SeqNumType NextSenderMsgSeqNum { get; set; } + public SeqNumType NextTargetMsgSeqNum { get; set; } public void IncrNextSenderMsgSeqNum() { ++NextSenderMsgSeqNum; } diff --git a/QuickFIXn/ResendRange.cs b/QuickFIXn/ResendRange.cs index c6de501ff..1469ba18c 100755 --- a/QuickFIXn/ResendRange.cs +++ b/QuickFIXn/ResendRange.cs @@ -1,12 +1,14 @@ -namespace QuickFix +using SeqNumType = System.UInt64; + +namespace QuickFix { public class ResendRange { - public const ulong NOT_SET = System.UInt64.MaxValue; + public const SeqNumType NOT_SET = SeqNumType.MaxValue; - public ulong BeginSeqNo { get; set; } - public ulong EndSeqNo { get; set; } - public ulong ChunkEndSeqNo { get; set; } + public SeqNumType BeginSeqNo { get; set; } + public SeqNumType EndSeqNo { get; set; } + public SeqNumType ChunkEndSeqNo { get; set; } public ResendRange() { diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs index c6b223648..5a709c674 100755 --- a/QuickFIXn/Session.cs +++ b/QuickFIXn/Session.cs @@ -3,6 +3,7 @@ using System.Threading; using QuickFix.Fields; using QuickFix.Fields.Converters; +using SeqNumType = System.UInt64; namespace QuickFix { @@ -76,7 +77,7 @@ public bool IsNewSession /// /// Gets or sets the next expected outgoing sequence number /// - public ulong NextSenderMsgSeqNum + public SeqNumType NextSenderMsgSeqNum { get { @@ -91,7 +92,7 @@ public ulong NextSenderMsgSeqNum /// /// Gets or sets the next expected incoming sequence number /// - public ulong NextTargetMsgSeqNum + public SeqNumType NextTargetMsgSeqNum { get { @@ -210,7 +211,7 @@ public TimeStampPrecision TimeStampPrecision /// /// Sets a maximum number of messages to request in a resend request. /// - public ulong MaxMessagesInResendRequest { get; set; } + public SeqNumType MaxMessagesInResendRequest { get; set; } /// /// This is the FIX field value, e.g. "6" for FIX44 @@ -749,7 +750,7 @@ protected void NextLogon(Message logon) state_.SentReset = false; state_.ReceivedReset = false; - ulong msgSeqNum = logon.Header.GetULong(Fields.Tags.MsgSeqNum); + SeqNumType msgSeqNum = logon.Header.GetULong(Fields.Tags.MsgSeqNum); if (IsTargetTooHigh(msgSeqNum) && !resetSeqNumFlag.Obj) { DoTargetTooHigh(logon, msgSeqNum); @@ -777,11 +778,11 @@ protected void NextResendRequest(Message resendReq) return; try { - ulong msgSeqNum = 0; + SeqNumType msgSeqNum = 0; if (!(this.IgnorePossDupResendRequests && resendReq.Header.IsSetField(Tags.PossDupFlag))) { - ulong begSeqNo = resendReq.GetULong(Fields.Tags.BeginSeqNo); - ulong endSeqNo = resendReq.GetULong(Fields.Tags.EndSeqNo); + SeqNumType begSeqNo = resendReq.GetULong(Fields.Tags.BeginSeqNo); + SeqNumType endSeqNo = resendReq.GetULong(Fields.Tags.EndSeqNo); this.Log.OnEvent("Got resend request from " + begSeqNo + " to " + endSeqNo); if ((endSeqNo == 999999) || (endSeqNo == 0)) @@ -792,7 +793,7 @@ protected void NextResendRequest(Message resendReq) if (!PersistMessages) { endSeqNo++; - ulong next = state_.NextSenderMsgSeqNum; + SeqNumType next = state_.NextSenderMsgSeqNum; if (endSeqNo > next) endSeqNo = next; GenerateSequenceReset(resendReq, begSeqNo, endSeqNo); @@ -806,8 +807,8 @@ protected void NextResendRequest(Message resendReq) List messages = new List(); state_.Get(begSeqNo, endSeqNo, messages); - ulong current = begSeqNo; - ulong begin = 0; + SeqNumType current = begSeqNo; + SeqNumType begin = 0; foreach (string msgStr in messages) { Message msg = new Message(); @@ -845,7 +846,7 @@ protected void NextResendRequest(Message resendReq) current = msgSeqNum + 1; } - ulong nextSeqNum = state_.NextSenderMsgSeqNum; + SeqNumType nextSeqNum = state_.NextSenderMsgSeqNum; if (++endSeqNo > nextSeqNum) { endSeqNo = nextSeqNum; @@ -931,7 +932,7 @@ protected void NextSequenceReset(Message sequenceReset) if (sequenceReset.IsSetField(Fields.Tags.NewSeqNo)) { - ulong newSeqNo = sequenceReset.GetULong(Fields.Tags.NewSeqNo); + SeqNumType newSeqNo = sequenceReset.GetULong(Fields.Tags.NewSeqNo); this.Log.OnEvent("Received SequenceReset FROM: " + state_.NextTargetMsgSeqNum + " TO: " + newSeqNo); if (newSeqNo > state_.NextTargetMsgSeqNum) @@ -953,7 +954,7 @@ public bool Verify(Message message) public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) { - ulong msgSeqNum = 0; + SeqNumType msgSeqNum = 0; string msgType = ""; try @@ -994,7 +995,7 @@ public bool Verify(Message msg, bool checkTooHigh, bool checkTooLow) else if (msgSeqNum >= range.ChunkEndSeqNo) { this.Log.OnEvent("Chunked ResendRequest for messages FROM: " + range.BeginSeqNo + " TO: " + range.ChunkEndSeqNo + " has been satisfied."); - ulong newChunkEndSeqNo = Math.Min(range.EndSeqNo, range.ChunkEndSeqNo + this.MaxMessagesInResendRequest); + SeqNumType newChunkEndSeqNo = Math.Min(range.EndSeqNo, range.ChunkEndSeqNo + this.MaxMessagesInResendRequest); GenerateResendRequestRange(msg.Header.GetString(Fields.Tags.BeginString), range.ChunkEndSeqNo + 1, newChunkEndSeqNo); range.ChunkEndSeqNo = newChunkEndSeqNo; } @@ -1095,17 +1096,17 @@ protected bool IsTimeToGenerateLogon() return true; } - protected bool IsTargetTooHigh(ulong msgSeqNum) + protected bool IsTargetTooHigh(SeqNumType msgSeqNum) { return msgSeqNum > state_.NextTargetMsgSeqNum; } - protected bool IsTargetTooLow(ulong msgSeqNum) + protected bool IsTargetTooLow(SeqNumType msgSeqNum) { return msgSeqNum < state_.NextTargetMsgSeqNum; } - protected void DoTargetTooHigh(Message msg, ulong msgSeqNum) + protected void DoTargetTooHigh(Message msg, SeqNumType msgSeqNum) { string beginString = msg.Header.GetString(Fields.Tags.BeginString); @@ -1126,7 +1127,7 @@ protected void DoTargetTooHigh(Message msg, ulong msgSeqNum) GenerateResendRequest(beginString, msgSeqNum); } - protected void DoTargetTooLow(Message msg, ulong msgSeqNum) + protected void DoTargetTooLow(Message msg, SeqNumType msgSeqNum) { bool possDupFlag = false; if (msg.Header.IsSetField(Fields.Tags.PossDupFlag)) @@ -1176,7 +1177,7 @@ protected void DoPossDup(Message msg) protected void GenerateBusinessMessageReject(Message message, int err, int field) { string msgType = message.Header.GetString(Tags.MsgType); - ulong msgSeqNum = message.Header.GetULong(Tags.MsgSeqNum); + SeqNumType msgSeqNum = message.Header.GetULong(Tags.MsgSeqNum); string reason = FixValues.BusinessRejectReason.RejText[err]; Message reject; if (this.SessionID.BeginString.CompareTo(FixValues.BeginString.FIX42) >= 0) @@ -1202,7 +1203,7 @@ protected void GenerateBusinessMessageReject(Message message, int err, int field SendRaw(reject, 0); } - protected bool GenerateResendRequestRange(string beginString, ulong startSeqNum, ulong endSeqNum) + protected bool GenerateResendRequestRange(string beginString, SeqNumType startSeqNum, SeqNumType endSeqNum) { Message resendRequest = msgFactory_.Create(beginString, MsgType.RESEND_REQUEST); @@ -1222,11 +1223,11 @@ protected bool GenerateResendRequestRange(string beginString, ulong startSeqNum, } } - protected bool GenerateResendRequest(string beginString, ulong msgSeqNum) + protected bool GenerateResendRequest(string beginString, SeqNumType msgSeqNum) { - ulong beginSeqNum = state_.NextTargetMsgSeqNum; - ulong endRangeSeqNum = msgSeqNum - 1; - ulong endChunkSeqNum; + SeqNumType beginSeqNum = state_.NextTargetMsgSeqNum; + SeqNumType endRangeSeqNum = msgSeqNum - 1; + SeqNumType endChunkSeqNum; if (this.MaxMessagesInResendRequest > 0) { endChunkSeqNum = Math.Min(endRangeSeqNum, beginSeqNum + this.MaxMessagesInResendRequest - 1); @@ -1413,7 +1414,7 @@ public bool GenerateReject(Message message, FixValues.SessionRejectReason reason else msgType = ""; - ulong msgSeqNum = 0; + SeqNumType msgSeqNum = 0; if (message.Header.IsSetField(Fields.Tags.MsgSeqNum)) { try @@ -1493,7 +1494,7 @@ protected void PopulateRejectReason(Message reject, string text) /// /// /// - protected void InitializeHeader(Message m, ulong msgSeqNum) + protected void InitializeHeader(Message m, SeqNumType msgSeqNum) { state_.LastSentTimeDT = DateTime.UtcNow; m.Header.SetField(new Fields.BeginString(this.SessionID.BeginString)); @@ -1540,7 +1541,7 @@ protected void Persist(Message message, string messageString) { if (this.PersistMessages) { - ulong msgSeqNum = message.Header.GetULong(Fields.Tags.MsgSeqNum); + SeqNumType msgSeqNum = message.Header.GetULong(Fields.Tags.MsgSeqNum); state_.Set(msgSeqNum, messageString); } state_.IncrNextSenderMsgSeqNum(); @@ -1560,12 +1561,12 @@ protected bool IsGoodTime(Message msg) return true; } - private void GenerateSequenceReset(Message receivedMessage, ulong beginSeqNo, ulong endSeqNo) + private void GenerateSequenceReset(Message receivedMessage, SeqNumType beginSeqNo, SeqNumType endSeqNo) { string beginString = this.SessionID.BeginString; Message sequenceReset = msgFactory_.Create(beginString, Fields.MsgType.SEQUENCE_RESET); InitializeHeader(sequenceReset); - ulong newSeqNo = endSeqNo; + SeqNumType newSeqNo = endSeqNo; sequenceReset.Header.SetField(new PossDupFlag(true)); InsertOrigSendingTime(sequenceReset.Header, sequenceReset.Header.GetDateTime(Tags.SendingTime)); @@ -1605,7 +1606,7 @@ protected void NextQueued() } } - protected bool NextQueued(ulong num) + protected bool NextQueued(SeqNumType num) { Message msg = state_.Dequeue(num); @@ -1633,7 +1634,7 @@ private bool IsAdminMessage(Message msg) return AdminMsgTypes.Contains(msgType); } - protected bool SendRaw(Message message, ulong seqNum) + protected bool SendRaw(Message message, SeqNumType seqNum) { lock (sync_) { diff --git a/QuickFIXn/SessionState.cs b/QuickFIXn/SessionState.cs index 961297fb7..50b8e2f72 100755 --- a/QuickFIXn/SessionState.cs +++ b/QuickFIXn/SessionState.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using MessagesBySeqNum = System.Collections.Generic.Dictionary; +using SeqNumType = System.UInt64; namespace QuickFix { @@ -274,7 +275,7 @@ public ResendRange GetResendRange() return resendRange_; } - public void Get(ulong begSeqNo, ulong endSeqNo, List messages) + public void Get(SeqNumType begSeqNo, SeqNumType endSeqNo, List messages) { lock (sync_) { @@ -282,12 +283,12 @@ public void Get(ulong begSeqNo, ulong endSeqNo, List messages) } } - public void SetResendRange(ulong begin, ulong end) + public void SetResendRange(SeqNumType begin, SeqNumType end) { SetResendRange(begin, end, ResendRange.NOT_SET); } - public void SetResendRange(ulong begin, ulong end, ulong chunkEnd) + public void SetResendRange(SeqNumType begin, SeqNumType end, SeqNumType chunkEnd) { resendRange_.BeginSeqNo = begin; resendRange_.EndSeqNo = end; @@ -299,7 +300,7 @@ public bool ResendRequested() return !(resendRange_.BeginSeqNo == 0 && resendRange_.EndSeqNo == 0); } - public void Queue(ulong msgSeqNum, Message msg) + public void Queue(SeqNumType msgSeqNum, Message msg) { if (!MsgQueue.ContainsKey(msgSeqNum)) { @@ -312,7 +313,7 @@ public void ClearQueue() MsgQueue.Clear(); } - public QuickFix.Message Dequeue(ulong num) + public QuickFix.Message Dequeue(SeqNumType num) { if (MsgQueue.ContainsKey(num)) { @@ -323,7 +324,7 @@ public QuickFix.Message Dequeue(ulong num) return null; } - public Message Retrieve(ulong msgSeqNum) + public Message Retrieve(SeqNumType msgSeqNum) { Message msg = null; if (MsgQueue.ContainsKey(msgSeqNum)) @@ -356,18 +357,18 @@ public override string ToString() #region MessageStore-manipulating Members - public bool Set(ulong msgSeqNum, string msg) + public bool Set(SeqNumType msgSeqNum, string msg) { lock (sync_) { return this.MessageStore.Set(msgSeqNum, msg); } } - public ulong NextSenderMsgSeqNum + public SeqNumType NextSenderMsgSeqNum { get { lock (sync_) { return this.MessageStore.NextSenderMsgSeqNum; } } set { lock (sync_) { this.MessageStore.NextSenderMsgSeqNum = value; } } } - public ulong NextTargetMsgSeqNum + public SeqNumType NextTargetMsgSeqNum { get { lock (sync_) { return this.MessageStore.NextTargetMsgSeqNum; } } set { lock (sync_) { this.MessageStore.NextTargetMsgSeqNum = value; } } diff --git a/UnitTests/SessionStateTest.cs b/UnitTests/SessionStateTest.cs index 1fa975f55..5b82068f9 100755 --- a/UnitTests/SessionStateTest.cs +++ b/UnitTests/SessionStateTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; +using SeqNumType = System.UInt64; namespace UnitTests { @@ -159,7 +160,7 @@ public void ThreadSafeSetAndGet() { Hashtable getTable = new Hashtable(1000);//only used in 1 thread at a time //Synchronously populate 1000 messages - for (ulong i = 1; i < 1000; i++) { + for (SeqNumType i = 1; i < 1000; i++) { string msg = "msg" + i; state.Set(i, msg); setTable[i] = msg; @@ -170,7 +171,7 @@ public void ThreadSafeSetAndGet() { ThreadPool.QueueUserWorkItem(delegate(object stateObject) { AutoResetEvent internalSetEvent = (AutoResetEvent)((object[])stateObject)[0]; SessionState internalState = (SessionState)((object[])stateObject)[1]; - for (ulong i = 1001; i < 2000; i++) { + for (SeqNumType i = 1001; i < 2000; i++) { try { internalState.Set(i, "msg" + i); } @@ -188,7 +189,7 @@ public void ThreadSafeSetAndGet() { ThreadPool.QueueUserWorkItem(delegate(object stateObject){ AutoResetEvent internalGetEvent = (AutoResetEvent)((object[])stateObject)[0]; SessionState internalState = (SessionState)((object[])stateObject)[1]; - for (ulong i = 1; i < 1000; i++) { + for (SeqNumType i = 1; i < 1000; i++) { try { List lst = new List(1); internalState.Get(i, i, lst); diff --git a/UnitTests/SessionTest.cs b/UnitTests/SessionTest.cs index 33528e181..597682d30 100755 --- a/UnitTests/SessionTest.cs +++ b/UnitTests/SessionTest.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using NUnit.Framework; using System.Threading; +using SeqNumType = System.UInt64; namespace UnitTests { @@ -175,7 +176,7 @@ public class SessionTest QuickFix.Session session = null; QuickFix.Session session2 = null; QuickFix.Dictionary config = null; - ulong seqNum = 1; + SeqNumType seqNum = 1; Regex msRegex = new Regex(@"\.[\d]{1,3}$"); Regex microsecondRegex = new Regex(@"\.[\d]{1,6}$"); @@ -348,14 +349,14 @@ public void SendNOSMessage() session.Next(order.ToString()); } - public void SendResendRequest(ulong begin, ulong end) + public void SendResendRequest(SeqNumType begin, SeqNumType end) { SendTheMessage(new QuickFix.FIX42.ResendRequest( new QuickFix.Fields.BeginSeqNo(begin), new QuickFix.Fields.EndSeqNo(end))); } - public void SendResendRequest40(ulong begin, ulong end) + public void SendResendRequest40(SeqNumType begin, SeqNumType end) { SendTheMessage(new QuickFix.FIX40.ResendRequest( new QuickFix.Fields.BeginSeqNo(begin), @@ -458,30 +459,30 @@ public void TestGapFillOnResend() order.Header.SetField(new QuickFix.Fields.TargetCompID(sessionID.TargetCompID)); order.Header.SetField(new QuickFix.Fields.SenderCompID(sessionID.SenderCompID)); - ulong[] gapStarts = new[] { 1UL, 5UL, 11UL }; // 1st gap from seq num 1 to 2 is just the Logon message - ulong[] gapEnds = new[] { 2UL, 8UL, 15UL }; + SeqNumType[] gapStarts = new[] { 1UL, 5UL, 11UL }; // 1st gap from seq num 1 to 2 is just the Logon message + SeqNumType[] gapEnds = new[] { 2UL, 8UL, 15UL }; int orderCount = 0; - for (ulong msgSeqNum = gapEnds[0]; msgSeqNum < gapStarts[1]; ++msgSeqNum) + for (SeqNumType msgSeqNum = gapEnds[0]; msgSeqNum < gapStarts[1]; ++msgSeqNum) { order.Header.SetField(new QuickFix.Fields.MsgSeqNum(msgSeqNum)); session.Send(order); ++orderCount; } //seq 4, next is 5 - for (ulong msgSeqNum = gapStarts[1]; msgSeqNum < gapEnds[1]; ++msgSeqNum) + for (SeqNumType msgSeqNum = gapStarts[1]; msgSeqNum < gapEnds[1]; ++msgSeqNum) { session.GenerateHeartbeat(); } //seq 7, next is 8 - for (ulong msgSeqNum = gapEnds[1]; msgSeqNum < gapStarts[2]; ++msgSeqNum) + for (SeqNumType msgSeqNum = gapEnds[1]; msgSeqNum < gapStarts[2]; ++msgSeqNum) { order.Header.SetField(new QuickFix.Fields.MsgSeqNum(msgSeqNum)); session.Send(order); ++orderCount; } //seq 10, next is 11 - for (ulong msgSeqNum = gapStarts[2]; msgSeqNum < gapEnds[2]; ++msgSeqNum) + for (SeqNumType msgSeqNum = gapStarts[2]; msgSeqNum < gapEnds[2]; ++msgSeqNum) { session.GenerateHeartbeat(); } // seq 11 - 14 @@ -654,7 +655,7 @@ public void TestLastMsgSeqNumProcessed() // Logon Logon(); QuickFix.Message msg = responder.msgLookup[QuickFix.Fields.MsgType.LOGON].Last(); - ulong lastSeqNumProcessed = msg.Header.GetULong(QuickFix.Fields.Tags.LastMsgSeqNumProcessed); + SeqNumType lastSeqNumProcessed = msg.Header.GetULong(QuickFix.Fields.Tags.LastMsgSeqNumProcessed); Assert.That(lastSeqNumProcessed == 1); // NOS From 90e4bd68f8c3ced212e7224c406a4ef89ca290c6 Mon Sep 17 00:00:00 2001 From: Mike Gatny Date: Fri, 12 May 2023 10:12:24 -0400 Subject: [PATCH 4/5] Removing these, the pwsh scripts work on linux --- build.sh | 9 --------- unit_test.sh | 12 ------------ 2 files changed, 21 deletions(-) delete mode 100755 build.sh delete mode 100755 unit_test.sh diff --git a/build.sh b/build.sh deleted file mode 100755 index 20d574efd..000000000 --- a/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -CONFIGURATION=$1 - -[ -z $CONFIGURATION ] && CONFIGURATION=Release - -BUILD_CMD="dotnet build -c ${CONFIGURATION}" -echo "Build command: $BUILD_CMD" -exec $BUILD_CMD diff --git a/unit_test.sh b/unit_test.sh deleted file mode 100755 index 3ce0c58df..000000000 --- a/unit_test.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# - -RESULT=0 - -set +e - -dotnet test -c Release --no-build --no-restore UnitTests -l trx - -RESULT=$? - -exit $RESULT From d462e4ede17233c64fdc98a6118b7378547c990d Mon Sep 17 00:00:00 2001 From: Mike Gatny Date: Fri, 12 May 2023 16:30:55 -0400 Subject: [PATCH 5/5] Define SeqNumType with `global using` h/t to grantb for pointing out that `global using` now exists, so we don't need to do a `using` per file to get typedef-like aliasing --- QuickFIXn/Fields/Fields.cs | 2 -- QuickFIXn/FileStore.cs | 1 - QuickFIXn/GlobalUsing.cs | 2 ++ QuickFIXn/HttpServer.cs | 1 - QuickFIXn/IMessageStore.cs | 1 - QuickFIXn/MemoryStore.cs | 1 - QuickFIXn/ResendRange.cs | 4 +--- QuickFIXn/Session.cs | 1 - QuickFIXn/SessionState.cs | 1 - UnitTests/GlobalUsing.cs | 2 ++ UnitTests/SessionStateTest.cs | 1 - UnitTests/SessionTest.cs | 1 - 12 files changed, 5 insertions(+), 13 deletions(-) create mode 100644 QuickFIXn/GlobalUsing.cs create mode 100644 UnitTests/GlobalUsing.cs diff --git a/QuickFIXn/Fields/Fields.cs b/QuickFIXn/Fields/Fields.cs index 7ab9b1af0..a1f7ee6af 100644 --- a/QuickFIXn/Fields/Fields.cs +++ b/QuickFIXn/Fields/Fields.cs @@ -1,8 +1,6 @@ // This is a generated file. Don't edit it directly! using System; -using SeqNumType = System.UInt64; -using SeqNumFieldType = QuickFix.Fields.ULongField; namespace QuickFix.Fields { diff --git a/QuickFIXn/FileStore.cs b/QuickFIXn/FileStore.cs index c6faf9c11..afb221af7 100755 --- a/QuickFIXn/FileStore.cs +++ b/QuickFIXn/FileStore.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Text; using QuickFix.Util; -using SeqNumType = System.UInt64; namespace QuickFix { diff --git a/QuickFIXn/GlobalUsing.cs b/QuickFIXn/GlobalUsing.cs new file mode 100644 index 000000000..7747ec155 --- /dev/null +++ b/QuickFIXn/GlobalUsing.cs @@ -0,0 +1,2 @@ +global using SeqNumType = System.UInt64; +global using SeqNumFieldType = QuickFix.Fields.ULongField; diff --git a/QuickFIXn/HttpServer.cs b/QuickFIXn/HttpServer.cs index 0b83c151a..66161d173 100644 --- a/QuickFIXn/HttpServer.cs +++ b/QuickFIXn/HttpServer.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Web; using QuickFix; -using SeqNumType = System.UInt64; namespace Acceptor { diff --git a/QuickFIXn/IMessageStore.cs b/QuickFIXn/IMessageStore.cs index 063d6d86a..a4657ccd9 100755 --- a/QuickFIXn/IMessageStore.cs +++ b/QuickFIXn/IMessageStore.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System; -using SeqNumType = System.UInt64; namespace QuickFix { diff --git a/QuickFIXn/MemoryStore.cs b/QuickFIXn/MemoryStore.cs index 2a9e77c4d..a32a25af3 100755 --- a/QuickFIXn/MemoryStore.cs +++ b/QuickFIXn/MemoryStore.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using SeqNumType = System.UInt64; namespace QuickFix { diff --git a/QuickFIXn/ResendRange.cs b/QuickFIXn/ResendRange.cs index 1469ba18c..0ed685e1d 100755 --- a/QuickFIXn/ResendRange.cs +++ b/QuickFIXn/ResendRange.cs @@ -1,6 +1,4 @@ -using SeqNumType = System.UInt64; - -namespace QuickFix +namespace QuickFix { public class ResendRange { diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs index 5a709c674..128dae377 100755 --- a/QuickFIXn/Session.cs +++ b/QuickFIXn/Session.cs @@ -3,7 +3,6 @@ using System.Threading; using QuickFix.Fields; using QuickFix.Fields.Converters; -using SeqNumType = System.UInt64; namespace QuickFix { diff --git a/QuickFIXn/SessionState.cs b/QuickFIXn/SessionState.cs index 50b8e2f72..5563a4ada 100755 --- a/QuickFIXn/SessionState.cs +++ b/QuickFIXn/SessionState.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using MessagesBySeqNum = System.Collections.Generic.Dictionary; -using SeqNumType = System.UInt64; namespace QuickFix { diff --git a/UnitTests/GlobalUsing.cs b/UnitTests/GlobalUsing.cs new file mode 100644 index 000000000..7747ec155 --- /dev/null +++ b/UnitTests/GlobalUsing.cs @@ -0,0 +1,2 @@ +global using SeqNumType = System.UInt64; +global using SeqNumFieldType = QuickFix.Fields.ULongField; diff --git a/UnitTests/SessionStateTest.cs b/UnitTests/SessionStateTest.cs index 5b82068f9..d16747b06 100755 --- a/UnitTests/SessionStateTest.cs +++ b/UnitTests/SessionStateTest.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Threading; -using SeqNumType = System.UInt64; namespace UnitTests { diff --git a/UnitTests/SessionTest.cs b/UnitTests/SessionTest.cs index 597682d30..ccfa316f4 100755 --- a/UnitTests/SessionTest.cs +++ b/UnitTests/SessionTest.cs @@ -4,7 +4,6 @@ using System.Text.RegularExpressions; using NUnit.Framework; using System.Threading; -using SeqNumType = System.UInt64; namespace UnitTests {