QuickFIX/J

Header with BeginString=FIXT.1.1 incorrectly parsed by FIXMessageDecoder (manifests as missing messages)

Details

  • Type: Bug Bug
  • Status: Open Open
  • Priority: Default Default
  • Resolution: Unresolved
  • Affects Version/s: 1.4.0
  • Fix Version/s: None
  • Component/s: Engine
  • Labels:
    None

Description

When BeginString=FIXT.1.1 messages can be skipped if the buffer ends before the last '=' of "8=FIXT.1.1\0019=". That will happen if the buffer contains a correct message before that.

Example:

in messages:

8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\0018=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001

the second message will fail to be decoded if the buffer contents presented to the FixMessageDecoder in two subsequent decode() invocations are:

"8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\0018=FIXT.1.1\0019"

and

"=12\00135=X\001108=30\00110=036\001"



I have created tests to replicate this issue (and also issue QFJ-505) and included fixes (for this and the fix proposed in QFJ-505).
Here is the diff:

Index: core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java
===================================================================
--- core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 46)
+++ core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 49)
@@ -348,7 +348,22 @@
 
     @Test
     public void testMinaDemux() throws Exception {
- DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
+ String message = "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001";
+
+ doTestMinaDemux(message);
+
+ }
+
+ @Test
+ public void testMinaDemuxFixt() throws Exception {
+ String message = "8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001";
+
+ doTestMinaDemux(message);
+
+ }
+
+ private void doTestMinaDemux(String message) throws Exception, UnsupportedEncodingException {
+ DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
         codecFactory.register(FIXMessageDecoder.class);
 
         ProtocolDecoder decoder = codecFactory.getDecoder();
@@ -359,7 +374,7 @@
         int count = 5;
         String data = "";
         for (int i = 0; i < count; i++) {
- data += "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001";
+ data += message;
         }
 
         for (int i = 1; i < data.length(); i++) {
@@ -379,9 +394,8 @@
             output.reset();
             buffer.clear();
         }
-
- }
-
+ }
+
     private void assertMessageFound(String data) throws ProtocolCodecException {
         assertMessageFound(data, 1);
     }
Index: core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java
===================================================================
--- core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 46)
+++ core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 49)
@@ -123,7 +123,7 @@
         }
         if (messageCount > 0) {
             // Mina will compact the buffer because we can't detect a header
- if (in.remaining() < minMaskLength(HEADER_PATTERN)) {
+ if (state == SEEKING_HEADER) {
                 position = 0;
             }
             return MessageDecoderResult.OK;
@@ -297,7 +297,8 @@
     }
 
     private static BufPos indexOf(ByteBuffer buffer, int position, byte[] data) {
- for (int offset = position, limit = buffer.limit() - minMaskLength(data) + 1; offset < limit; offset++) {
+ int limit = buffer.limit() - minMaskLength(data) + 1;
+ for (int offset = position ; offset < limit; offset++) {
             int length;
             if (buffer.get(offset) == data[0] && (length = startsWith(buffer, offset, data)) > 0) {
                 return new BufPos(offset, length);
@@ -337,6 +338,10 @@
                 return -1;
             }
         }
+ if(dataOffset != data.length){
+ // when minMaskLength(data) != data.length we might run out of buffer before we run out of data
+ return -1;
+ }
         return bufferOffset - initOffset;
     }

Activity

Hide
Stelios Papadopoulos added a comment - 20/Jul/10 11:56 AM

the svn references are unrelated to the QuickFixJ svn repository.

Show
Stelios Papadopoulos added a comment - 20/Jul/10 11:56 AM the svn references are unrelated to the QuickFixJ svn repository.
Hide
Stelios Papadopoulos added a comment - 20/Jul/10 12:38 PM

Found the same issue in 1.5.0 here's my diffs for the tests and the fix:

Index: C:/dev/projects/QUICKFIXJ-IG/core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java
===================================================================
— C:/dev/projects/QUICKFIXJ-IG/core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 52)
+++ C:/dev/projects/QUICKFIXJ-IG/core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (working copy)
@@ -327,7 +327,22 @@

@Test
public void testMinaDemux() throws Exception { - DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory(); + String message = "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001"; + + doTestMinaDemux(message); + + }
+
+ @Test
+ public void testMinaDemuxFixt() throws Exception { + String message = "8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001"; + + doTestMinaDemux(message); + + }
+
+ private void doTestMinaDemux(String message) throws Exception, UnsupportedEncodingException {
+ DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory();
codecFactory.register(FIXMessageDecoder.class);

ProtocolDecoder decoder = codecFactory.getDecoder();
@@ -338,7 +353,7 @@
int count = 5;
String data = "";
for (int i = 0; i < count; i++) { - data += "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001"; + data += message; }

for (int i = 1; i < data.length(); i++) { @@ -358,9 +373,8 @@ output.reset(); buffer.clear(); }
+ }

  • }
    -
    private void assertMessageFound(String data) throws ProtocolCodecException { assertMessageFound(data, 1); }

Index: C:/dev/projects/QUICKFIXJ-IG/core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java
===================================================================
— C:/dev/projects/QUICKFIXJ-IG/core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 52)
+++ C:/dev/projects/QUICKFIXJ-IG/core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (working copy)
@@ -123,7 +123,7 @@
}
if (messageCount > 0) {
// Mina will compact the buffer because we can't detect a header

  • if (in.remaining() < minMaskLength(HEADER_PATTERN))
    Unknown macro: {+ if (state == SEEKING_HEADER) { position = 0; } return MessageDecoderResult.OK;@@ -337,6 +337,10 @@ return -1; }

    }
    + if(dataOffset != data.length){ + // when minMaskLength(data) != data.length we might run out of buffer before we run out of data + return -1; + }
    return bufferOffset - initOffset;
    }
Show
Stelios Papadopoulos added a comment - 20/Jul/10 12:38 PM Found the same issue in 1.5.0 here's my diffs for the tests and the fix: Index: C:/dev/projects/QUICKFIXJ-IG/core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java =================================================================== — C:/dev/projects/QUICKFIXJ-IG/core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (revision 52) +++ C:/dev/projects/QUICKFIXJ-IG/core/src/test/java/quickfix/mina/message/FIXMessageDecoderTest.java (working copy) @@ -327,7 +327,22 @@ @Test public void testMinaDemux() throws Exception { - DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory(); + String message = "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001"; + + doTestMinaDemux(message); + + } + + @Test + public void testMinaDemuxFixt() throws Exception { + String message = "8=FIXT.1.1\0019=12\00135=X\001108=30\00110=036\001"; + + doTestMinaDemux(message); + + } + + private void doTestMinaDemux(String message) throws Exception, UnsupportedEncodingException { + DemuxingProtocolCodecFactory codecFactory = new DemuxingProtocolCodecFactory(); codecFactory.register(FIXMessageDecoder.class); ProtocolDecoder decoder = codecFactory.getDecoder(); @@ -338,7 +353,7 @@ int count = 5; String data = ""; for (int i = 0; i < count; i++) { - data += "8=FIX.4.2\0019=12\00135=X\001108=30\00110=036\001"; + data += message; } for (int i = 1; i < data.length(); i++) { @@ -358,9 +373,8 @@ output.reset(); buffer.clear(); } + }
  • } - private void assertMessageFound(String data) throws ProtocolCodecException { assertMessageFound(data, 1); }
Index: C:/dev/projects/QUICKFIXJ-IG/core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java =================================================================== — C:/dev/projects/QUICKFIXJ-IG/core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (revision 52) +++ C:/dev/projects/QUICKFIXJ-IG/core/src/main/java/quickfix/mina/message/FIXMessageDecoder.java (working copy) @@ -123,7 +123,7 @@ } if (messageCount > 0) { // Mina will compact the buffer because we can't detect a header
  • if (in.remaining() < minMaskLength(HEADER_PATTERN))
    Unknown macro: {+ if (state == SEEKING_HEADER) { position = 0; } return MessageDecoderResult.OK;@@ -337,6 +337,10 @@ return -1; }
    } + if(dataOffset != data.length){ + // when minMaskLength(data) != data.length we might run out of buffer before we run out of data + return -1; + } return bufferOffset - initOffset; }

People

Vote (2)
Watch (0)

Dates

  • Created:
    20/Jul/10 11:55 AM
    Updated:
    20/Jul/10 12:38 PM