Session.cpp
Go to the documentation of this file.
1/****************************************************************************
2** Copyright (c) 2001-2014
3**
4** This file is part of the QuickFIX FIX Engine
5**
6** This file may be distributed under the terms of the quickfixengine.org
7** license as defined by quickfixengine.org and appearing in the file
8** LICENSE included in the packaging of this file.
9**
10** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12**
13** See http://www.quickfixengine.org/LICENSE for licensing information.
14**
15** Contact ask@quickfixengine.org if any conditions of this licensing are
16** not clear to you.
17**
18****************************************************************************/
19
20#ifdef _MSC_VER
21#include "stdafx.h"
22#else
23#include "config.h"
24#endif
25
26#include "Session.h"
27#include "Values.h"
28#include <algorithm>
29#include <iostream>
30
31namespace FIX
32{
37
38#define LOGEX( method ) try { method; } catch( std::exception& e ) \
39 { m_state.onEvent( e.what() ); }
40
42 MessageStoreFactory& messageStoreFactory,
43 const SessionID& sessionID,
44 const DataDictionaryProvider& dataDictionaryProvider,
45 const TimeRange& sessionTime,
46 int heartBtInt, LogFactory* pLogFactory )
47: m_application( application ),
48 m_sessionID( sessionID ),
49 m_sessionTime( sessionTime ),
50 m_logonTime( sessionTime ),
51 m_senderDefaultApplVerID(ApplVerID_FIX50),
52 m_targetDefaultApplVerID(ApplVerID_FIX50),
53 m_sendRedundantResendRequests( false ),
54 m_checkCompId( true ),
55 m_checkLatency( true ),
56 m_maxLatency( 120 ),
57 m_resetOnLogon( false ),
58 m_resetOnLogout( false ),
59 m_resetOnDisconnect( false ),
60 m_refreshOnLogon( false ),
61 m_timestampPrecision( 3 ),
62 m_persistMessages( true ),
63 m_validateLengthAndChecksum( true ),
64 m_dataDictionaryProvider( dataDictionaryProvider ),
65 m_messageStoreFactory( messageStoreFactory ),
66 m_pLogFactory( pLogFactory ),
67 m_pResponder( 0 )
68{
69 m_state.heartBtInt( heartBtInt );
70 m_state.initiate( heartBtInt != 0 );
72 if ( m_pLogFactory )
74
76 reset();
77
78 addSession( *this );
80 m_state.onEvent( "Created session" );
81}
82
90
102
113
114void Session::fill( Header& header )
115{
122 insertSendingTime( header );
123}
124
126{
127 next( UtcTimeStamp() );
128}
129
130void Session::next( const UtcTimeStamp& timeStamp )
131{
132 try
133 {
135 { reset(); return; }
136
137 if( !isEnabled() || !isLogonTime(timeStamp) )
138 {
139 if( isLoggedOn() )
140 {
141 if( !m_state.sentLogout() )
142 {
143 m_state.onEvent( "Initiated logout request" );
145 }
146 }
147 else
148 return;
149 }
150
151 if ( !m_state.receivedLogon() )
152 {
154 {
156 m_state.onEvent( "Initiated logon request" );
157 }
159 {
160 m_state.onEvent( "Timed out waiting for logon response" );
161 disconnect();
162 }
163 return ;
164 }
165
166 if ( m_state.heartBtInt() == 0 ) return ;
167
168 if ( m_state.logoutTimedOut() )
169 {
170 m_state.onEvent( "Timed out waiting for logout response" );
171 disconnect();
172 }
173
175
176 if ( m_state.timedOut() )
177 {
178 m_state.onEvent( "Timed out waiting for heartbeat" );
179 disconnect();
180 }
181 else
182 {
183 if ( m_state.needTestRequest() )
184 {
185 generateTestRequest( "TEST" );
187 m_state.onEvent( "Sent test request TEST" );
188 }
189 else if ( m_state.needHeartbeat() )
190 {
192 }
193 }
194 }
195 catch ( FIX::IOException& e )
196 {
197 m_state.onEvent( e.what() );
198 disconnect();
199 }
200}
201
202void Session::nextLogon( const Message& logon, const UtcTimeStamp& timeStamp )
203{
206 logon.getHeader().getField( senderCompID );
207 logon.getHeader().getField( targetCompID );
208
209 if( m_refreshOnLogon )
210 refresh();
211
212 if( !isEnabled() )
213 {
214 m_state.onEvent( "Session is not enabled for logon" );
215 disconnect();
216 return;
217 }
218
219 if( !isLogonTime(timeStamp) )
220 {
221 m_state.onEvent( "Received logon outside of valid logon time" );
222 disconnect();
223 return;
224 }
225
227 logon.getFieldIfSet(resetSeqNumFlag);
229
230 if( m_state.receivedReset() )
231 {
232 m_state.onEvent( "Logon contains ResetSeqNumFlag=Y, reseting sequence numbers to 1" );
233 if( !m_state.sentReset() ) m_state.reset();
234 }
235
237 {
238 m_state.onEvent( "Received logon response before sending request" );
239 disconnect();
240 return;
241 }
242
244 m_state.reset();
245
246 if( !verify( logon, false, true ) )
247 return;
248 m_state.receivedLogon( true );
249
250 if ( !m_state.initiate()
252 {
253 logon.getFieldIfSet(m_state.heartBtInt());
254 m_state.onEvent( "Received logon request" );
256 m_state.onEvent( "Responding to logon request" );
257 }
258 else
259 m_state.onEvent( "Received logon response" );
260
261 m_state.sentReset( false );
262 m_state.receivedReset( false );
263
265 logon.getHeader().getField( msgSeqNum );
267 {
269 }
270 else
271 {
274 }
275
276 if ( isLoggedOn() )
278}
279
280void Session::nextHeartbeat( const Message& heartbeat, const UtcTimeStamp& timeStamp )
281{
282 if ( !verify( heartbeat ) ) return ;
285}
286
287void Session::nextTestRequest( const Message& testRequest, const UtcTimeStamp& timeStamp )
288{
289 if ( !verify( testRequest ) ) return ;
290 generateHeartbeat( testRequest );
293}
294
295void Session::nextLogout( const Message& logout, const UtcTimeStamp& timeStamp )
296{
297 if ( !verify( logout, false, false ) ) return ;
298 if ( !m_state.sentLogout() )
299 {
300 m_state.onEvent( "Received logout request" );
302 m_state.onEvent( "Sending logout response" );
303 }
304 else
305 m_state.onEvent( "Received logout response" );
306
309 disconnect();
310}
311
312void Session::nextReject( const Message& reject, const UtcTimeStamp& timeStamp )
313{
314 if ( !verify( reject, false, true ) ) return ;
317}
318
319void Session::nextSequenceReset( const Message& sequenceReset, const UtcTimeStamp& timeStamp )
320{
321 bool isGapFill = false;
323 if ( sequenceReset.getFieldIfSet( gapFillFlag ) )
324 {
326 }
327
329
331 if ( sequenceReset.getFieldIfSet( newSeqNo ) )
332 {
333 m_state.onEvent( "Received SequenceReset FROM: "
335 " TO: " + IntConvertor::convert( newSeqNo ) );
336
339 else if ( newSeqNo < getExpectedTargetNum() )
341 }
342}
343
344void Session::nextResendRequest( const Message& resendRequest, const UtcTimeStamp& timeStamp )
345{
346 if ( !verify( resendRequest, false, false ) ) return ;
347
348 Locker l( m_mutex );
349
352 resendRequest.getField( beginSeqNo );
353 resendRequest.getField( endSeqNo );
354
355 m_state.onEvent( "Received ResendRequest FROM: "
357 " TO: " + IntConvertor::convert( endSeqNo ) );
358
359 std::string beginString = m_sessionID.getBeginString();
360 if ( (beginString >= FIX::BeginString_FIX42 && endSeqNo == 0) ||
361 (beginString <= FIX::BeginString_FIX42 && endSeqNo == 999999) ||
363 { endSeqNo = getExpectedSenderNum() - 1; }
364
365 if ( !m_persistMessages )
366 {
369 if( endSeqNo > next )
372 return;
373 }
374
375 std::vector < std::string > messages;
377
378 std::vector < std::string > ::iterator i;
381 int begin = 0;
382 int current = beginSeqNo;
383 std::string messageString;
384
385 for ( i = messages.begin(); i != messages.end(); ++i )
386 {
388 std::string strMsgType;
391 if (sessionDD.isMessageFieldsOrderPreserved())
392 {
393 std::string::size_type equalSign = (*i).find("\00135=");
394 equalSign += 4;
395 std::string::size_type soh = (*i).find_first_of('\001', equalSign);
396 strMsgType = (*i).substr(equalSign, soh - equalSign);
397#ifdef HAVE_EMX
399 {
400 equalSign = (*i).find("\0019426=", soh);
401 if (equalSign == std::string::npos)
402 throw FIX::IOException("EMX message type (9426) not found");
403
404 equalSign += 6;
405 soh = (*i).find_first_of('\001', equalSign);
406 if (soh == std::string::npos)
407 throw FIX::IOException("EMX message type (9426) soh char not found");
408 strMsgType.assign((*i).substr(equalSign, soh - equalSign));
409 }
410#endif
411 }
412
413 if( m_sessionID.isFIXT() )
414 {
415 Message msg;
418 if( !msg.getHeader().getFieldIfSet(applVerID) )
420
423 if (strMsgType.empty())
425 else
426 {
427 const message_order & hdrOrder = sessionDD.getHeaderOrderedFields();
428 const message_order & trlOrder = sessionDD.getTrailerOrderedFields();
429 const message_order & msgOrder = applicationDD.getMessageOrderedFields(strMsgType);
431 }
432 }
433 else
434 {
435 if (strMsgType.empty())
437 else
438 {
439 const message_order & hdrOrder = sessionDD.getHeaderOrderedFields();
440 const message_order & trlOrder = sessionDD.getTrailerOrderedFields();
441 const message_order & msgOrder = sessionDD.getMessageOrderedFields(strMsgType);
443 }
444 }
445
446 Message & msg = *pMsg;
447
449 msg.getHeader().getField( msgType );
450
451 if( (current != msgSeqNum) && !begin )
452 begin = current;
453
455 {
456 if ( !begin ) begin = msgSeqNum;
457 }
458 else
459 {
460 if ( resend( msg ) )
461 {
462 if ( begin ) generateSequenceReset( begin, msgSeqNum );
463 send( msg.toString(messageString) );
464 m_state.onEvent( "Resending Message: "
466 begin = 0;
467 }
468 else
469 { if ( !begin ) begin = msgSeqNum; }
470 }
471 current = msgSeqNum + 1;
472 }
473 if ( begin )
474 {
475 generateSequenceReset( begin, msgSeqNum + 1 );
476 }
477
478 if ( endSeqNo > msgSeqNum )
479 {
482 if( endSeqNo > next )
485 }
486
487 resendRequest.getHeader().getField( msgSeqNum );
490}
491
492Message * Session::newMessage(const std::string & msgType) const
493{
494 Message * msg = 0;
495
498 if (!sessionDD.isMessageFieldsOrderPreserved())
499 {
500 msg = new Message();
501 }
502 else
503 {
504 const message_order & hdrOrder = sessionDD.getHeaderOrderedFields();
505 const message_order & trlOrder = sessionDD.getTrailerOrderedFields();
507 {
508 const message_order & msgOrder = sessionDD.getMessageOrderedFields(msgType);
510 }
511 else
512 {
515 const message_order & msgOrder = applicationDD.getMessageOrderedFields(msgType);
517 }
518 }
519
520 return msg;
521}
522
523bool Session::send( Message& message )
524{
525 message.getHeader().removeField( FIELD::PossDupFlag );
526 message.getHeader().removeField( FIELD::OrigSendingTime );
527 return sendRaw( message );
528}
529
530bool Session::sendRaw( Message& message, int num )
531{
532 Locker l( m_mutex );
533
534 try
535 {
536 Header& header = message.getHeader();
537
539 header.getFieldIfSet(msgType);
540
541 fill( header );
542 std::string messageString;
543
544 if ( num )
545 header.setField( MsgSeqNum( num ) );
546
548 {
550
551 if( msgType == "A" && !m_state.receivedReset() )
552 {
554 message.getFieldIfSet(resetSeqNumFlag);
555
556 if( resetSeqNumFlag )
557 {
558 m_state.reset();
559 message.getHeader().setField( MsgSeqNum(getExpectedSenderNum()) );
560 }
562 }
563
564 message.toString( messageString );
565
566 if( !num )
568
569 if (
570 msgType == "A" || msgType == "5"
571 || msgType == "2" || msgType == "4"
572 || isLoggedOn() )
573 {
575 }
576 }
577 else
578 {
579 // do not send application messages if they will just be cleared
580 if( !isLoggedOn() && shouldSendReset() )
581 return false;
582
583 try
584 {
586 message.toString( messageString );
587
588 if( !num )
590
591 if ( isLoggedOn() )
593 }
594 catch ( DoNotSend& ) { return false; }
595 }
596
597 return true;
598 }
599 catch ( IOException& e )
600 {
601 m_state.onEvent( e.what() );
602 return false;
603 }
604}
605
606bool Session::send( const std::string& string )
607{
608 if ( !m_pResponder ) return false;
609 m_state.onOutgoing( string );
610 return m_pResponder->send( string );
611}
612
614{
616
617 if ( m_pResponder )
618 {
619 m_state.onEvent( "Disconnecting" );
620
622 m_pResponder = 0;
623 }
624
626 {
627 m_state.receivedLogon( false );
628 m_state.sentLogon( false );
630 }
631
632 m_state.sentLogout( false );
633 m_state.receivedReset( false );
634 m_state.sentReset( false );
638 m_state.reset();
639
640 m_state.resendRange( 0, 0 );
641}
642
643bool Session::resend( Message& message )
644{
647 Header& header = message.getHeader();
648 header.getField( sendingTime );
649 header.getField( msgSeqNum );
651 header.setField( PossDupFlag( true ) );
652 insertSendingTime( header );
653
654 try
655 {
657 return true;
658 }
659 catch ( DoNotSend& )
660 { return false; }
661}
662
663void Session::persist( const Message& message, const std::string& messageString )
664throw ( IOException )
665{
666 MsgSeqNum msgSeqNum;
667 message.getHeader().getField( msgSeqNum );
668 if( m_persistMessages )
669 m_state.set( msgSeqNum, messageString );
670 m_state.incrNextSenderMsgSeqNum();
671}
672
674{
676 Message & logon = *pMsg;
677
678 logon.getHeader().setField( MsgType( "A" ) );
679 logon.setField( EncryptMethod( 0 ) );
680 logon.setField( m_state.heartBtInt() );
681 if( m_sessionID.isFIXT() )
683 if( m_refreshOnLogon )
684 refresh();
685 if( m_resetOnLogon )
686 m_state.reset();
687 if( shouldSendReset() )
688 logon.setField( ResetSeqNumFlag(true) );
689
690 fill( logon.getHeader() );
693 m_state.testRequest( 0 );
694 m_state.sentLogon( true );
695 sendRaw( logon );
696}
697
698void Session::generateLogon( const Message& aLogon )
699{
701 Message & logon = *pMsg;
702
704 HeartBtInt heartBtInt;
706 if( m_sessionID.isFIXT() )
708 if( m_state.receivedReset() )
709 logon.setField( ResetSeqNumFlag(true) );
710 aLogon.getField( heartBtInt );
711 logon.getHeader().setField( MsgType( "A" ) );
712 logon.setField( heartBtInt );
713 fill( logon.getHeader() );
714 sendRaw( logon );
715 m_state.sentLogon( true );
716}
717
718void Session::generateResendRequest( const BeginString& beginString, const MsgSeqNum& msgSeqNum )
719{
722
726 endSeqNo = 0;
728 endSeqNo = 999999;
729 resendRequest.getHeader().setField( MsgType( "2" ) );
730 resendRequest.setField( beginSeqNo );
731 resendRequest.setField( endSeqNo );
732 fill( resendRequest.getHeader() );
734
735 m_state.onEvent( "Sent ResendRequest FROM: "
737 " TO: " + IntConvertor::convert( endSeqNo ) );
738
740}
741
743( int beginSeqNo, int endSeqNo )
744{
747
749 sequenceReset.getHeader().setField( MsgType( "4" ) );
750 sequenceReset.getHeader().setField( PossDupFlag( true ) );
751 sequenceReset.setField( newSeqNo );
752 fill( sequenceReset.getHeader() );
753
755 sequenceReset.getHeader().getField( sendingTime );
757 sequenceReset.getHeader().setField( MsgSeqNum( beginSeqNo ) );
758 sequenceReset.setField( GapFillFlag( true ) );
760 m_state.onEvent( "Sent SequenceReset TO: "
762}
763
765{
768
770 fill( heartbeat.getHeader() );
772}
773
774void Session::generateHeartbeat( const Message& testRequest )
775{
778
780 fill( heartbeat.getHeader() );
781 try
782 {
784 testRequest.getField( testReqID );
786 }
787 catch ( FieldNotFound& ) {}
788
790}
791
792void Session::generateTestRequest( const std::string& id )
793{
795 Message & testRequest = *pMsg;
796
797 testRequest.getHeader().setField( MsgType( "1" ) );
798 fill( testRequest.getHeader() );
799 TestReqID testReqID( id );
800 testRequest.setField( testReqID );
801
802 sendRaw( testRequest );
803}
804
805void Session::generateReject( const Message& message, int err, int field )
806{
807 std::string beginString = m_sessionID.getBeginString();
808
810 Message & reject = *pMsg;
811
812 reject.getHeader().setField( MsgType( "3" ) );
813 reject.reverseRoute( message.getHeader() );
814 fill( reject.getHeader() );
815
818
819 message.getHeader().getField( msgType );
820 if( message.getHeader().getFieldIfSet( msgSeqNum ) )
821 {
822 if( msgSeqNum.getString() != "" )
823 reject.setField( RefSeqNum( msgSeqNum ) );
824 }
825
827 {
828 if( msgType.getString() != "" )
829 reject.setField( RefMsgType( msgType ) );
833 {
834 reject.setField( SessionRejectReason( err ) );
835 }
836 }
840
841 const char* reason = 0;
842 switch ( err )
843 {
846 break;
849 break;
852 break;
855 break;
858 break;
861 break;
864 break;
867 break;
870 break;
873 break;
876 break;
879 };
880
881 if ( reason && ( field || err == SessionRejectReason_INVALID_TAG_NUMBER ) )
882 {
884 m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected: "
885 + reason + ":" + IntConvertor::convert( field ) );
886 }
887 else if ( reason )
888 {
890 m_state.onEvent( "Message " + msgSeqNum.getString()
891 + " Rejected: " + reason );
892 }
893 else
894 m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected" );
895
896 if ( !m_state.receivedLogon() )
897 throw std::runtime_error( "Tried to send a reject while not logged on" );
898
899 sendRaw( reject );
900}
901
902void Session::generateReject( const Message& message, const std::string& str )
903{
904 std::string beginString = m_sessionID.getBeginString();
905
907 Message & reject = *pMsg;
908
909 reject.getHeader().setField( MsgType( "3" ) );
910 reject.reverseRoute( message.getHeader() );
911 fill( reject.getHeader() );
912
915
916 message.getHeader().getField( msgType );
917 message.getHeader().getField( msgSeqNum );
919 reject.setField( RefMsgType( msgType ) );
920 reject.setField( RefSeqNum( msgSeqNum ) );
921
924
925 reject.setField( Text( str ) );
926 sendRaw( reject );
927 m_state.onEvent( "Message " + msgSeqNum.getString()
928 + " Rejected: " + str );
929}
930
931void Session::generateBusinessReject( const Message& message, int err, int field )
932{
934 Message & reject = *pMsg;
935
937 if( m_sessionID.isFIXT() )
939 fill( reject.getHeader() );
942 message.getHeader().getField( msgType );
943 message.getHeader().getField( msgSeqNum );
944 reject.setField( RefMsgType( msgType ) );
945 reject.setField( RefSeqNum( msgSeqNum ) );
946 reject.setField( BusinessRejectReason( err ) );
948
949 const char* reason = 0;
950 switch ( err )
951 {
954 break;
957 break;
960 break;
963 break;
966 break;
969 break;
972 break;
975 break;
976 };
977
978 if ( reason && field )
979 {
981 m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected: "
982 + reason + ":" + IntConvertor::convert( field ) );
983 }
984 else if ( reason )
985 {
987 m_state.onEvent( "Message " + msgSeqNum.getString()
988 + " Rejected: " + reason );
989 }
990 else
991 m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected" );
992
993 sendRaw( reject );
994}
995
996void Session::generateLogout( const std::string& text )
997{
999 Message & logout = *pMsg;
1000
1002 fill( logout.getHeader() );
1003 if ( text.length() )
1004 logout.setField( Text( text ) );
1005 sendRaw( logout );
1006 m_state.sentLogout( true );
1007}
1008
1010 const std::string& text )
1011{
1013 reject.getHeader().getField( msgType );
1014
1015 if ( msgType == MsgType_Reject
1017 {
1018 reject.setField( RefTagID( field ) );
1019 reject.setField( Text( text ) );
1020 }
1021 else
1022 {
1023 std::stringstream stream;
1024 stream << text << " (" << field << ")";
1025 reject.setField( Text( stream.str() ) );
1026 }
1027}
1028
1029void Session::populateRejectReason( Message& reject, const std::string& text )
1030{
1031 reject.setField( Text( text ) );
1032}
1033
1034bool Session::verify( const Message& msg, bool checkTooHigh,
1035 bool checkTooLow )
1036{
1037 const MsgType* pMsgType = 0;
1038 const MsgSeqNum* pMsgSeqNum = 0;
1039
1040 try
1041 {
1042 const Header& header = msg.getHeader();
1043
1044 pMsgType = FIELD_GET_PTR( header, MsgType );
1048
1049 if( checkTooHigh || checkTooLow )
1050 pMsgSeqNum = FIELD_GET_PTR( header, MsgSeqNum );
1051
1052 if ( !validLogonState( *pMsgType ) )
1053 throw std::logic_error( "Logon state is not valid for message" );
1054
1055 if ( !isGoodTime( sendingTime ) )
1056 {
1057 doBadTime( msg );
1058 return false;
1059 }
1061 {
1062 doBadCompID( msg );
1063 return false;
1064 }
1065
1067 {
1069 return false;
1070 }
1071 else if ( checkTooLow && isTargetTooLow( *pMsgSeqNum ) )
1072 {
1074 return false;
1075 }
1076
1078 {
1080
1081 if ( *pMsgSeqNum >= range.second )
1082 {
1083 m_state.onEvent ("ResendRequest for messages FROM: " +
1084 IntConvertor::convert (range.first) + " TO: " +
1085 IntConvertor::convert (range.second) +
1086 " has been satisfied.");
1087 m_state.resendRange (0, 0);
1088 }
1089 }
1090 }
1091 catch ( std::exception& e )
1092 {
1093 m_state.onEvent( e.what() );
1094 disconnect();
1095 return false;
1096 }
1097
1100 m_state.testRequest( 0 );
1101
1103 return true;
1104}
1105
1107{
1108 std::string beginString = m_sessionID.getBeginString();
1110 && ( m_resetOnLogon ||
1111 m_resetOnLogout ||
1113 && ( getExpectedSenderNum() == 1 )
1114 && ( getExpectedTargetNum() == 1 );
1115}
1116
1117bool Session::validLogonState( const MsgType& msgType )
1118{
1119 if ( (msgType == MsgType_Logon && m_state.sentReset())
1120 || (m_state.receivedReset()) )
1121 return true;
1124 return true;
1126 return true;
1128 return true;
1130 return true;
1131 if ( msgType == MsgType_Reject )
1132 return true;
1133
1134 return false;
1135}
1136
1137void Session::fromCallback( const MsgType& msgType, const Message& msg,
1138 const SessionID& sessionID )
1139{
1142 else
1144}
1145
1151
1157
1158bool Session::doPossDup( const Message& msg )
1159{
1160 const Header & header = msg.getHeader();
1164
1165 header.getField( msgType );
1166 header.getField( sendingTime );
1167
1169 {
1170 if ( !header.getFieldIfSet( origSendingTime ) )
1171 {
1173 return false;
1174 }
1175
1177 {
1180 return false;
1181 }
1182 }
1183 return true;
1184}
1185
1187{
1188 const Header & header = msg.getHeader();
1189 PossDupFlag possDupFlag(false);
1191 header.getFieldIfSet(possDupFlag);
1192 header.getField( msgSeqNum );
1193
1194 if ( !possDupFlag )
1195 {
1196 std::stringstream stream;
1197 stream << "MsgSeqNum too low, expecting " << getExpectedTargetNum()
1198 << " but received " << msgSeqNum;
1199 generateLogout( stream.str() );
1200 throw std::logic_error( stream.str() );
1201 }
1202
1203 return doPossDup( msg );
1204}
1205
1207{
1208 const Header & header = msg.getHeader();
1211 header.getField( beginString );
1212 header.getField( msgSeqNum );
1213
1214 m_state.onEvent( "MsgSeqNum too high, expecting "
1216 + " but received "
1218
1220
1221 if( m_state.resendRequested() )
1222 {
1224
1226 {
1227 m_state.onEvent ("Already sent ResendRequest FROM: " +
1228 IntConvertor::convert (range.first) + " TO: " +
1229 IntConvertor::convert (range.second) +
1230 ". Not sending another.");
1231 return;
1232 }
1233 }
1234
1236}
1237
1238void Session::nextQueued( const UtcTimeStamp& timeStamp )
1239{
1240 while ( nextQueued( getExpectedTargetNum(), timeStamp ) ) {}
1241}
1242
1243bool Session::nextQueued( int num, const UtcTimeStamp& timeStamp )
1244{
1245 Message msg;
1247
1248 if( m_state.retrieve( num, msg ) )
1249 {
1250 m_state.onEvent( "Processing QUEUED message: "
1252 msg.getHeader().getField( msgType );
1253 if( msgType == MsgType_Logon
1255 {
1257 }
1258 else
1259 {
1260 next( msg, timeStamp, true );
1261 }
1262 return true;
1263 }
1264 return false;
1265}
1266
1267void Session::next( const std::string& msg, const UtcTimeStamp& timeStamp, bool queued )
1268{
1269 try
1270 {
1272 const DataDictionary& sessionDD =
1274 if( m_sessionID.isFIXT() )
1275 {
1279 }
1280 else
1281 {
1283 }
1284 }
1285 catch( InvalidMessage& e )
1286 {
1287 m_state.onEvent( e.what() );
1288
1289 try
1290 {
1292 {
1293 m_state.onEvent( "Logon message is not valid" );
1294 disconnect();
1295 }
1296 } catch( MessageParseError& ) {}
1297 throw e;
1298 }
1299}
1300
1301void Session::next( const Message& message, const UtcTimeStamp& timeStamp, bool queued )
1302{
1303 const Header& header = message.getHeader();
1304
1305 try
1306 {
1308 { reset(); return; }
1309
1310 const MsgType& msgType = FIELD_GET_REF( header, MsgType );
1312 // make sure these fields are present
1315
1317 throw UnsupportedVersion();
1318
1319 if( msgType == MsgType_Logon )
1320 {
1321 if( m_sessionID.isFIXT() )
1322 {
1325 }
1326 else
1327 {
1329 }
1330 }
1331
1334
1335 if( m_sessionID.isFIXT() && message.isApp() )
1336 {
1338 header.getFieldIfSet(applVerID);
1342 }
1343 else
1344 {
1345 sessionDataDictionary.validate( message );
1346 }
1347
1348 if ( msgType == MsgType_Logon )
1350 else if ( msgType == MsgType_Heartbeat )
1352 else if ( msgType == MsgType_TestRequest )
1354 else if ( msgType == MsgType_SequenceReset )
1356 else if ( msgType == MsgType_Logout )
1358 else if ( msgType == MsgType_ResendRequest )
1360 else if ( msgType == MsgType_Reject )
1362 else
1363 {
1364 if ( !verify( message ) ) return ;
1366 }
1367 }
1368 catch ( MessageParseError& e )
1369 { m_state.onEvent( e.what() ); }
1370 catch ( RequiredTagMissing & e )
1372 catch ( FieldNotFound & e )
1373 {
1374 if( header.getField(FIELD::BeginString) >= FIX::BeginString_FIX42 && message.isApp() )
1375 {
1377 }
1378 else
1379 {
1381 if ( header.getField(FIELD::MsgType) == MsgType_Logon )
1382 {
1383 m_state.onEvent( "Required field missing from logon" );
1384 disconnect();
1385 }
1386 }
1387 }
1388 catch ( InvalidTagNumber & e )
1390 catch ( NoTagValue & e )
1392 catch ( TagNotDefinedForMessage & e )
1394 catch ( InvalidMessageType& )
1396 catch ( UnsupportedMessageType& )
1397 {
1398 if ( header.getField(FIELD::BeginString) >= FIX::BeginString_FIX42 )
1400 else
1401 { LOGEX( generateReject( message, "Unsupported message type" ) ); }
1402 }
1403 catch ( TagOutOfOrder & e )
1405 catch ( IncorrectDataFormat & e )
1407 catch ( IncorrectTagValue & e )
1409 catch ( RepeatedTag & e )
1411 catch ( RepeatingGroupCountMismatch & e )
1413 catch ( InvalidMessage& e )
1414 { m_state.onEvent( e.what() ); }
1415 catch ( RejectLogon& e )
1416 {
1417 m_state.onEvent( e.what() );
1418 generateLogout( e.what() );
1419 disconnect();
1420 }
1421 catch ( UnsupportedVersion& )
1422 {
1423 if ( header.getField(FIELD::MsgType) == MsgType_Logout )
1425 else
1426 {
1427 generateLogout( "Incorrect BeginString" );
1429 }
1430 }
1431 catch ( IOException& e )
1432 {
1433 m_state.onEvent( e.what() );
1434 disconnect();
1435 }
1436
1437 if( !queued )
1439
1440 if( isLoggedOn() )
1441 next();
1442}
1443
1444bool Session::sendToTarget( Message& message, const std::string& qualifier )
1445throw( SessionNotFound )
1446{
1447 try
1448 {
1449 SessionID sessionID = message.getSessionID( qualifier );
1450 return sendToTarget( message, sessionID );
1451 }
1452 catch ( FieldNotFound& ) { throw SessionNotFound(); }
1453}
1454
1455bool Session::sendToTarget( Message& message, const SessionID& sessionID )
1456throw( SessionNotFound )
1457{
1458 message.setSessionID( sessionID );
1459 Session* pSession = lookupSession( sessionID );
1460 if ( !pSession ) throw SessionNotFound();
1461 return pSession->send( message );
1462}
1463
1465( Message& message,
1466 const SenderCompID& senderCompID,
1467 const TargetCompID& targetCompID,
1468 const std::string& qualifier )
1469throw( SessionNotFound )
1470{
1471 message.getHeader().setField( senderCompID );
1472 message.getHeader().setField( targetCompID );
1473 return sendToTarget( message, qualifier );
1474}
1475
1477( Message& message, const std::string& sender, const std::string& target,
1478 const std::string& qualifier )
1479throw( SessionNotFound )
1480{
1481 return sendToTarget( message, SenderCompID( sender ),
1482 TargetCompID( target ), qualifier );
1483}
1484
1485std::set<SessionID> Session::getSessions()
1486{
1487 return s_sessionIDs;
1488}
1489
1490bool Session::doesSessionExist( const SessionID& sessionID )
1491{
1493 return s_sessions.end() != s_sessions.find( sessionID );
1494}
1495
1497{
1499 Sessions::iterator find = s_sessions.find( sessionID );
1500 if ( find != s_sessions.end() )
1501 return find->second;
1502 else
1503 return 0;
1504}
1505
1506Session* Session::lookupSession( const std::string& string, bool reverse )
1507{
1509 if ( !message.setStringHeader( string ) )
1510 return 0;
1511
1512 try
1513 {
1514 const Header& header = message.getHeader();
1518
1519 if ( reverse )
1520 {
1523 }
1524
1526 targetCompID ) );
1527 }
1528 catch ( FieldNotFound& ) { return 0; }
1529}
1530
1532{
1534 return s_registered.end() != s_registered.find( sessionID );
1535}
1536
1538{
1541 if ( pSession == 0 ) return 0;
1542 if ( isSessionRegistered( sessionID ) ) return 0;
1544 return pSession;
1545}
1546
1548{
1550 s_registered.erase( sessionID );
1551}
1552
1554{
1556 return s_sessions.size();
1557}
1558
1560{
1562 Sessions::iterator it = s_sessions.find( s.m_sessionID );
1563 if ( it == s_sessions.end() )
1564 {
1565 s_sessions[ s.m_sessionID ] = &s;
1566 s_sessionIDs.insert( s.m_sessionID );
1567 return true;
1568 }
1569 else
1570 return false;
1571}
1572
1574{
1576 s_sessions.erase( s.m_sessionID );
1577 s_sessionIDs.erase( s.m_sessionID );
1578 s_registered.erase( s.m_sessionID );
1579}
1580}
#define FIELD_GET_REF(MAP, FLD)
Definition FieldMap.h:376
#define FIELD_GET_PTR(MAP, FLD)
Definition FieldMap.h:374
#define FIELD_THROW_IF_NOT_FOUND(MAP, FLD)
Definition FieldMap.h:378
#define LOGEX(method)
Definition Session.cpp:38
This interface must be implemented to define what your FIX application does.
Definition Application.h:44
virtual void fromApp(const Message &, const SessionID &)=0
Notification of app message being received from target.
virtual void onCreate(const SessionID &)=0
Notification of a session begin created.
virtual void fromAdmin(const Message &, const SessionID &)=0
Notification of admin message being received from target.
virtual void toAdmin(Message &, const SessionID &)=0
Notification of admin message being sent to target.
virtual void onLogout(const SessionID &)=0
Notification of a session logging off or disconnecting.
virtual void toApp(Message &, const SessionID &)=0
Notification of app message being sent to target.
virtual void onLogon(const SessionID &)=0
Notification of a session successfully logging on.
Represents a data dictionary for a version of FIX.
static void validate(const Message &message, const DataDictionary *const pSessionDD, const DataDictionary *const pAppID)
Validate a message.
Queries for DataDictionary based on appropriate version of FIX.
const DataDictionary & getApplicationDataDictionary(const ApplVerID &applVerID) const
const DataDictionary & getSessionDataDictionary(const BeginString &beginString) const
void setField(int field)
Definition Field.h:131
int getField() const
Definition Field.h:148
void setField(const FieldBase &field, bool overwrite=true)
Set a field without type checking.
Definition FieldMap.h:116
FieldBase & getField(FieldBase &field) const
Get a field without type checking.
Definition FieldMap.h:156
bool getFieldIfSet(FieldBase &field) const
Get a field if set.
Definition FieldMap.h:146
Locks/Unlocks a mutex using RAII.
Definition Mutex.h:96
This interface must be implemented to create a Log.
Definition Log.h:43
virtual void destroy(Log *)=0
virtual Log * create()=0
Base class for all FIX messages.
Definition Message.h:118
bool setStringHeader(const std::string &string)
Set a messages header from a string This is an optimization that can be used to get useful informatio...
Definition Message.cpp:475
static ApplVerID toApplVerID(const BeginString &value)
Definition Message.h:307
static bool isAdminMsgType(const MsgType &msgType)
Definition Message.h:300
const Header & getHeader() const
Getter for the message header.
Definition Message.h:245
This interface must be implemented to create a MessageStore.
virtual MessageStore * create(const SessionID &)=0
virtual void destroy(MessageStore *)=0
virtual bool send(const std::string &)=0
virtual void disconnect()=0
Maintains the state and implements the logic of a FIX session.
Definition Session.h:46
MessageStoreFactory & m_messageStoreFactory
Definition Session.h:339
void fromCallback(const MsgType &msgType, const Message &msg, const SessionID &sessionID)
Definition Session.cpp:1137
bool m_resetOnLogout
Definition Session.h:330
static Session * registerSession(const SessionID &)
Definition Session.cpp:1537
void nextQueued(const UtcTimeStamp &timeStamp)
Definition Session.cpp:1238
LogFactory * m_pLogFactory
Definition Session.h:340
bool isTargetTooHigh(const MsgSeqNum &msgSeqNum)
Definition Session.h:260
bool isGoodTime(const SendingTime &sendingTime)
Definition Session.h:249
void nextHeartbeat(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:280
void insertSendingTime(Header &)
Definition Session.cpp:91
static Mutex s_mutex
Definition Session.h:347
void nextSequenceReset(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:319
Application & m_application
Definition Session.h:318
void nextLogout(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:295
void populateRejectReason(Message &, int field, const std::string &)
Definition Session.cpp:1009
bool isTargetTooLow(const MsgSeqNum &msgSeqNum)
Definition Session.h:262
SessionState m_state
Definition Session.h:337
bool m_refreshOnLogon
Definition Session.h:332
static void unregisterSession(const SessionID &)
Definition Session.cpp:1547
bool m_persistMessages
Definition Session.h:334
void fill(Header &)
Definition Session.cpp:114
bool send(Message &)
Definition Session.cpp:523
bool resend(Message &message)
Definition Session.cpp:643
void insertOrigSendingTime(Header &, const UtcTimeStamp &when=UtcTimeStamp())
Definition Session.cpp:103
bool isCorrectCompID(const SenderCompID &senderCompID, const TargetCompID &targetCompID)
Definition Session.h:264
void logout(const std::string &reason="")
Definition Session.h:57
void generateHeartbeat()
Definition Session.cpp:764
Responder * m_pResponder
Definition Session.h:341
DataDictionaryProvider m_dataDictionaryProvider
Definition Session.h:338
bool checkSessionTime(const UtcTimeStamp &timeStamp)
Definition Session.h:255
static bool doesSessionExist(const SessionID &)
Definition Session.cpp:1490
bool m_sendRedundantResendRequests
Definition Session.h:325
void setTargetDefaultApplVerID(const std::string &targetDefaultApplVerID)
Definition Session.h:129
bool validLogonState(const MsgType &msgType)
Definition Session.cpp:1117
static void removeSession(Session &)
Definition Session.cpp:1573
SessionID m_sessionID
Definition Session.h:319
bool doTargetTooLow(const Message &msg)
Definition Session.cpp:1186
void reset()
Definition Session.h:66
void generateLogon()
Definition Session.cpp:673
Mutex m_mutex
Definition Session.h:342
bool isEnabled()
Definition Session.h:59
void generateResendRequest(const BeginString &, const MsgSeqNum &)
Definition Session.cpp:718
int getExpectedTargetNum()
Definition Session.h:225
bool verify(const Message &msg, bool checkTooHigh=true, bool checkTooLow=true)
Definition Session.cpp:1034
void nextReject(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:312
static Session * lookupSession(const SessionID &)
Definition Session.cpp:1496
void generateBusinessReject(const Message &, int err, int field=0)
Definition Session.cpp:931
void nextTestRequest(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:287
bool shouldSendReset()
Definition Session.cpp:1106
void nextLogon(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:202
std::string m_targetDefaultApplVerID
Definition Session.h:324
void refresh()
Definition Session.h:68
void nextResendRequest(const Message &, const UtcTimeStamp &timeStamp)
Definition Session.cpp:344
void generateTestRequest(const std::string &)
Definition Session.cpp:792
std::string m_senderDefaultApplVerID
Definition Session.h:323
void next()
Definition Session.cpp:125
bool doPossDup(const Message &msg)
Definition Session.cpp:1158
int m_timestampPrecision
Definition Session.h:333
std::set< SessionID > SessionIDs
Definition Session.h:234
void disconnect()
Definition Session.cpp:613
static Sessions s_registered
Definition Session.h:346
void doBadTime(const Message &msg)
Definition Session.cpp:1146
static SessionIDs s_sessionIDs
Definition Session.h:345
void doTargetTooHigh(const Message &msg)
Definition Session.cpp:1206
void logon()
Definition Session.h:55
static bool addSession(Session &)
Definition Session.cpp:1559
void generateLogout(const std::string &text="")
Definition Session.cpp:996
bool isLogonTime(const UtcTimeStamp &time)
Definition Session.h:110
void generateReject(const Message &, int err, int field=0)
Definition Session.cpp:805
bool m_resetOnDisconnect
Definition Session.h:331
int getExpectedSenderNum()
Definition Session.h:224
bool sendRaw(Message &, int msgSeqNum=0)
Definition Session.cpp:530
void doBadCompID(const Message &msg)
Definition Session.cpp:1152
bool m_validateLengthAndChecksum
Definition Session.h:335
std::map< SessionID, Session * > Sessions
Definition Session.h:233
bool m_resetOnLogon
Definition Session.h:329
virtual ~Session()
Definition Session.cpp:83
static std::set< SessionID > getSessions()
Definition Session.cpp:1485
static Sessions s_sessions
Definition Session.h:344
static bool isSessionRegistered(const SessionID &)
Definition Session.cpp:1531
Message * newMessage(const std::string &msgType) const
Definition Session.cpp:492
void generateSequenceReset(int, int)
Definition Session.cpp:743
static bool sendToTarget(Message &message, const std::string &qualifier="")
Definition Session.cpp:1444
Session(Application &, MessageStoreFactory &, const SessionID &, const DataDictionaryProvider &, const TimeRange &, int heartBtInt, LogFactory *pLogFactory)
Definition Session.cpp:41
bool isLoggedOn()
Definition Session.h:65
static size_t numSessions()
Definition Session.cpp:1553
bool set(int s, const Message &m)
void persist(const Message &, const std::string &)
Definition Session.cpp:663
Unique session id consists of BeginString, SenderCompID and TargetCompID.
Definition SessionID.h:31
const SenderCompID & getSenderCompID() const
Definition SessionID.h:55
const BeginString & getBeginString() const
Definition SessionID.h:53
const bool isFIXT() const
Definition SessionID.h:61
const TargetCompID & getTargetCompID() const
Definition SessionID.h:57
MessageStore * store()
int getNextSenderMsgSeqNum() const
void lastSentTime(const UtcTimeStamp &value)
int testRequest() const
bool sentLogon() const
bool logoutTimedOut() const
void onIncoming(const std::string &string)
void setNextTargetMsgSeqNum(int n)
bool resendRequested() const
std::pair< int, int > ResendRange
bool sentReset() const
bool shouldSendLogon() const
bool sentLogout() const
bool logonTimedOut() const
bool retrieve(int msgSeqNum, Message &message)
void lastReceivedTime(const UtcTimeStamp &value)
bool receivedLogon() const
std::string logoutReason() const
bool withinHeartBeat() const
bool needTestRequest() const
void incrNextTargetMsgSeqNum()
bool timedOut() const
bool needHeartbeat() const
void onOutgoing(const std::string &string)
bool initiate() const
void queue(int msgSeqNum, const Message &message)
bool receivedReset() const
void onEvent(const std::string &string)
void heartBtInt(const HeartBtInt &value)
ResendRange resendRange() const
void get(int b, int e, std::vector< std::string > &m) const
bool alreadySentLogon() const
Keeps track of when session is active.
Definition TimeRange.h:35
Date and Time represented in UTC.
Definition FieldTypes.h:583
const char SessionRejectReason_INCORRECT_DATA_FORMAT_FOR_VALUE_TEXT[]
Definition Values.h:44
const char BeginString_FIX41[]
Definition Values.h:35
const char BusinessRejectReason_CONDITIONALLY_REQUIRED_FIELD_MISSING_TEXT[]
Definition Values.h:58
const char BusinessRejectReason_NOT_AUTHORIZED_TEXT[]
Definition Values.h:59
const char BusinessRejectReason_APPLICATION_NOT_AVAILABLE_TEXT[]
Definition Values.h:57
const char SessionRejectReason_COMPID_PROBLEM_TEXT[]
Definition Values.h:47
const char BusinessRejectReason_UNSUPPORTED_MESSAGE_TYPE_TEXT[]
Definition Values.h:56
const char SessionRejectReason_INCORRECT_NUMINGROUP_COUNT_FOR_REPEATING_GROUP_TEXT[]
Definition Values.h:52
const char BeginString_FIX42[]
Definition Values.h:34
const char SessionRejectReason_TAG_SPECIFIED_WITHOUT_A_VALUE_TEXT[]
Definition Values.h:42
const char BusinessRejectReason_DELIVERTO_FIRM_NOT_AVAILABLE_AT_THIS_TIME_TEXT[]
Definition Values.h:60
const char BusinessRejectReason_UNKNOWN_ID_TEXT[]
Definition Values.h:54
const char SessionRejectReason_REQUIRED_TAG_MISSING_TEXT[]
Definition Values.h:39
const char SessionRejectReason_INVALID_TAG_NUMBER_TEXT[]
Definition Values.h:38
const char BeginString_FIXT11[]
Definition Values.h:30
const char SessionRejectReason_TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER_TEXT[]
Definition Values.h:51
const char BusinessRejectReason_OTHER_TEXT[]
Definition Values.h:53
const char BusinessRejectReason_UNKNOWN_SECURITY_TEXT[]
Definition Values.h:55
const char SessionRejectReason_INVALID_MSGTYPE_TEXT[]
Definition Values.h:49
const char SessionRejectReason_VALUE_IS_INCORRECT_TEXT[]
Definition Values.h:43
const char SessionRejectReason_TAG_APPEARS_MORE_THAN_ONCE_TEXT[]
Definition Values.h:50
const char SessionRejectReason_TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE_TEXT[]
Definition Values.h:40
const char SessionRejectReason_SENDINGTIME_ACCURACY_PROBLEM_TEXT[]
Definition Values.h:48
MsgType identifyType(const std::string &message)
Parse the type of a message from a string.
Definition Message.h:417
void reverse(I begin, I end)
Definition pugixml.cpp:6009
Indicates user does not want to send a message.
Definition Exceptions.h:218
Field not found inside a message.
Definition Exceptions.h:58
Field has a badly formatted value.
Definition Exceptions.h:147
Field has a value that is out of range.
Definition Exceptions.h:138
static std::string convert(signed_int value)
Not a recognizable message.
Definition Exceptions.h:81
Not a known message type.
Definition Exceptions.h:170
Tag number does not exist in specification.
Definition Exceptions.h:102
Unable to parse message.
Definition Exceptions.h:74
Field exists in message without a value.
Definition Exceptions.h:129
User wants to reject permission to logon.
Definition Exceptions.h:225
Repeated tag not part of repeating group.
Definition Exceptions.h:200
Repeated group count not equal to actual count.
Definition Exceptions.h:209
Required field is not in message.
Definition Exceptions.h:111
Session cannot be found for specified action.
Definition Exceptions.h:232
Field does not belong to message.
Definition Exceptions.h:120
Tag is not in the correct order.
Definition Exceptions.h:191
Message type not supported by application.
Definition Exceptions.h:177
Version of FIX is not supported.
Definition Exceptions.h:184
Sorts fields in header, normal, or trailer order.

Generated on Mon Mar 4 2024 21:10:02 for QuickFIX by doxygen 1.9.8 written by Dimitri van Heesch, © 1997-2001