Re: [Quickfix-users] Message with contents set through Message.setString(string) can't be cracked i
Brought to you by:
orenmnero
From: abaraff <ab...@ra...> - 2011-05-25 11:52:06
|
So I ripped off a bit of the code from the Java version of Quickfix. It's not the prettiest port--I was just trying to get it functional. It does produce correctly typed messages from strings however. I'd love to have someone post a cleaner alternative, but here is the MessageUtils class that I ported over. The parse() methods return messages that can be cracked and are correctly typed: using System; using System.Collections.Generic; using System.Text; namespace QuickFix { public class MessageUtils { private const char FIELD_SEPARATOR = '\x0001'; public const string BEGINSTRING_FIX40 = "FIX.4.0"; public const string BEGINSTRING_FIX41 = "FIX.4.1"; public const string BEGINSTRING_FIX42 = "FIX.4.2"; public const string BEGINSTRING_FIX43 = "FIX.4.3"; public const string BEGINSTRING_FIX44 = "FIX.4.4"; /** * FIX 5.0 does not have a begin string. */ public const string FIX50 = "FIX.5.0"; // FIXT.x.x support public const string FIXT_SESSION_PREFIX = "FIXT."; public const string BEGINSTRING_FIXT11 = FIXT_SESSION_PREFIX + "1.1"; private static Dictionary<string, ApplVerID> BeginStringToApplVerID = new Dictionary<String, ApplVerID>(); static MessageUtils() { // No support for earlier versions of FIX BeginStringToApplVerID.Add(BEGINSTRING_FIX40, new ApplVerID(ApplVerID.FIX40)); BeginStringToApplVerID.Add(BEGINSTRING_FIX41, new ApplVerID(ApplVerID.FIX41)); BeginStringToApplVerID.Add(BEGINSTRING_FIX42, new ApplVerID(ApplVerID.FIX42)); BeginStringToApplVerID.Add(BEGINSTRING_FIX43, new ApplVerID(ApplVerID.FIX43)); BeginStringToApplVerID.Add(BEGINSTRING_FIX44, new ApplVerID(ApplVerID.FIX44)); BeginStringToApplVerID.Add(FIX50, new ApplVerID(ApplVerID.FIX50)); } private static ApplVerID GetApplVerID(Session session, string messageString) { ApplVerID applVerID = null; string applVerIdString = GetStringField(messageString, ApplVerID.FIELD); if (applVerIdString != null) { applVerID = new ApplVerID(applVerIdString); } /* GetTargetDefaultApplicationVersionID doesn't exist in the .Net version if (applVerID == null) { applVerID = session.GetTargetDefaultApplicationVersionID(); }*/ if (applVerID == null && IsLogon(messageString)) { string defaultApplVerIdString = GetStringField(messageString, DefaultApplVerID.FIELD); if (defaultApplVerIdString != null) { applVerID = new ApplVerID(defaultApplVerIdString); } } if (applVerID == null) { throw new InvalidMessage("Can't determine ApplVerID for message"); } return applVerID; } public static string GetMessageType(String messageString) { string value = GetStringField(messageString, 35); if (value == null) { throw new InvalidMessage("Missing or garbled message type in " + messageString); } return value; } public static string GetStringField(String messageString, int tag) { string value = null; string tagString = tag.ToString(); int start = messageString.IndexOf(tagString, 0); while (start != -1 && value == null) { if ((start == 0 || messageString[start - 1] == FIELD_SEPARATOR)) { int end = start + tagString.Length; if ((end + 1) < messageString.Length && messageString[end] == '=') { // found tag, get value start = end = (end + 1); for (; end < messageString.Length && messageString[end] != FIELD_SEPARATOR; end++) { ; } if (end == messageString.Length) { return null; } else { value = messageString.Substring(start, end - start); } } } start = messageString.IndexOf(tagString, start + 1); } return value; } public static bool IsAdminMessage(string msgType) { return msgType.Length == 1 && "0A12345h".IndexOf(msgType) != -1; } public static bool IsLogon(string message) { return IsMessageType(message, MsgType.Logon); } private static bool IsMessageType(string message, string msgType) { try { return msgType == GetMessageType(message); } catch (InvalidMessage e) { return false; } } /** * Utility method for parsing a mesasge. This should only be used for parsing messages from * FIX versions 4.4 or earlier. * * @param messageFactory * @param dataDictionary * @param messageString * @return the parsed message * @throws InvalidMessage */ public static Message parse(MessageFactory messageFactory, DataDictionary dataDictionary, string messageString) { int index = messageString.IndexOf(FIELD_SEPARATOR); if (index < 0) { throw new InvalidMessage("Message does not contain any field separator"); } string beginString = messageString.Substring(2, index - 2); string messageType = GetMessageType(messageString); Message message = messageFactory.create(beginString, messageType); message.setString(messageString, dataDictionary != null, dataDictionary); return message; } /** * NOTE: This method is intended for internal use. * * @param session - the Session that will process the message * @param messageString * @return the parsed message * @throws InvalidMessage */ public static Message parse(Session session, string messageString, MessageFactory messageFactory) { BeginString beginString = new BeginString(GetStringField(messageString, BeginString.FIELD)); string msgType = GetMessageType(messageString); ApplVerID applVerID = null; //String customApplVerID = null; if (BEGINSTRING_FIXT11 == beginString.getValue()) { applVerID = GetApplVerID(session, messageString); //customApplVerID = GetStringField(messageString, CstmApplVerID.FIELD); } else { applVerID = ToApplVerID(beginString.getValue()); } //MessageFactory messageFactory = session.getMessageFactory(); DataDictionaryProvider ddProvider = session.getDataDictionaryProvider(); DataDictionary sessionDataDictionary = ddProvider == null ? null : ddProvider.getSessionDataDictionary(beginString); DataDictionary applicationDataDictionary = ddProvider == null ? null : ddProvider.getApplicationDataDictionary(applVerID); Message message = messageFactory.create(beginString.getValue(), msgType); //DataDictionary payloadDictionary = MessageUtils.IsAdminMessage(msgType) ? sessionDataDictionary : applicationDataDictionary; message.setString(messageString, sessionDataDictionary != null, sessionDataDictionary);//Closest .net version //message.parse(messageString, sessionDataDictionary, payloadDictionary, payloadDictionary != null); return message; } /** * Convert a begin string to an ApplVerID * @param beginString * @return the ApplVerID for the specified begin string. * @throws QFJException if conversion fails. * @see FixVersions */ public static ApplVerID ToApplVerID(string beginString) { ApplVerID applVerID = BeginStringToApplVerID[beginString]; if (applVerID == null) { throw new Exception("Can't convert to ApplVerID: " + beginString); } return applVerID; } } } abaraff wrote: > > If a message is cloned using the .setString(string) method, calling crack > on it fails. As you can see from my example below, crack is successful on > the original message but throws an exception when called on the clone: > > public void fromApp(Message msg, SessionID sessionID) > { > try > { > > string message = msg.ToString(); > > Message newMessage = new Message(); > newMessage.setString(msg.ToString(), true); > > crack(msg, sessionID); > try > { > crack(newMessage, sessionID); > } > catch (Exception e2) > { > System.Diagnostics.Debug.WriteLine(e2.ToString()); > System.Diagnostics.Debug.WriteLine(msg.ToString() == > newMessage.ToString()); > System.Diagnostics.Debug.WriteLine("orig: " + > msg.ToString()); > System.Diagnostics.Debug.WriteLine("new: " + > newMessage.ToString()); > System.Diagnostics.Debug.WriteLine("orig: " + > msg.ToXML()); > System.Diagnostics.Debug.WriteLine("new: " + > newMessage.ToXML()); > System.Diagnostics.Debug.WriteLine("round trip > failed"); > } > } > catch (Exception e) > { > System.Diagnostics.Debug.WriteLine(e.ToString()); > } > } > > public override void onMessage(QuickFix42.NewOrderSingle message, > SessionID session) > { > System.Diagnostics.Debug.WriteLine("New Order Single"); > } > > Output: > New Order Single > A first chance exception of type 'QuickFix.UnsupportedMessageType' > occurred in quickfix_net_messages.dll > QuickFix.UnsupportedMessageType: Exception of type > 'QuickFix.UnsupportedMessageType' was thrown. > at QuickFix42.MessageCracker.onMessage(Message message, SessionID > session) > at QuickFix42.MessageCracker.crack(Message message, SessionID > sessionID) > at FIXServer.FIXServerApp.fromApp(Message msg, SessionID sessionID) in > C:\Dev\Abaraff\FIXServer\FIXServer\FIXServerApp.cs:line 244 > True > orig: > 8=FIX.4.29=18035=D34=249=SCT152=20110520-14:38:23.52356=SCTC11=SCT20110520-103823_0000818=121=138=20040=154=155=IBM58=SCT20110520-103823_0000859=060=20110520-10:38:23100=DB-SMART10=239 > new: > 8=FIX.4.29=18035=D34=249=SCT152=20110520-14:38:23.52356=SCTC11=SCT20110520-103823_0000818=121=138=20040=154=155=IBM58=SCT20110520-103823_0000859=060=20110520-10:38:23100=DB-SMART10=239 > orig: <message> > <header> > <field number="8"><![CDATA[FIX.4.2]]></field> > <field number="9"><![CDATA[180]]></field> > <field number="35"><![CDATA[D]]></field> > <field number="34"><![CDATA[2]]></field> > <field number="49"><![CDATA[SCT1]]></field> > <field number="52"><![CDATA[20110520-14:38:23.523]]></field> > <field number="56"><![CDATA[SCTC]]></field> > </header> > <body> > <field number="11"><![CDATA[SCT20110520-103823_00008]]></field> > <field number="18"><![CDATA[1]]></field> > <field number="21"><![CDATA[1]]></field> > <field number="38"><![CDATA[200]]></field> > <field number="40"><![CDATA[1]]></field> > <field number="54"><![CDATA[1]]></field> > <field number="55"><![CDATA[IBM]]></field> > <field number="58"><![CDATA[SCT20110520-103823_00008]]></field> > <field number="59"><![CDATA[0]]></field> > <field number="60"><![CDATA[20110520-10:38:23]]></field> > <field number="100"><![CDATA[DB-SMART]]></field> > </body> > <trailer> > <field number="10"><![CDATA[239]]></field> > </trailer> > </message> > new: <message> > <header> > <field number="8"><![CDATA[FIX.4.2]]></field> > <field number="9"><![CDATA[180]]></field> > <field number="35"><![CDATA[D]]></field> > <field number="34"><![CDATA[2]]></field> > <field number="49"><![CDATA[SCT1]]></field> > <field number="52"><![CDATA[20110520-14:38:23.523]]></field> > <field number="56"><![CDATA[SCTC]]></field> > </header> > <body> > <field number="11"><![CDATA[SCT20110520-103823_00008]]></field> > <field number="18"><![CDATA[1]]></field> > <field number="21"><![CDATA[1]]></field> > <field number="38"><![CDATA[200]]></field> > <field number="40"><![CDATA[1]]></field> > <field number="54"><![CDATA[1]]></field> > <field number="55"><![CDATA[IBM]]></field> > <field number="58"><![CDATA[SCT20110520-103823_00008]]></field> > <field number="59"><![CDATA[0]]></field> > <field number="60"><![CDATA[20110520-10:38:23]]></field> > <field number="100"><![CDATA[DB-SMART]]></field> > </body> > <trailer> > <field number="10"><![CDATA[239]]></field> > </trailer> > </message> > round trip failed > -- View this message in context: http://old.nabble.com/Message-with-contents-set-through-Message.setString%28string%29-can%27t-be-cracked-in-.Net-tp31664717p31698166.html Sent from the QuickFIX - User mailing list archive at Nabble.com. |