quickfix_ruby 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/quickfix/Acceptor.cpp +248 -0
- data/ext/quickfix/Acceptor.h +127 -0
- data/ext/quickfix/Allocator.h +9 -0
- data/ext/quickfix/Application.h +127 -0
- data/ext/quickfix/AtomicCount.h +109 -0
- data/ext/quickfix/DOMDocument.h +74 -0
- data/ext/quickfix/DataDictionary.cpp +618 -0
- data/ext/quickfix/DataDictionary.h +539 -0
- data/ext/quickfix/DataDictionaryProvider.cpp +71 -0
- data/ext/quickfix/DataDictionaryProvider.h +70 -0
- data/ext/quickfix/DatabaseConnectionID.h +105 -0
- data/ext/quickfix/DatabaseConnectionPool.h +91 -0
- data/ext/quickfix/Dictionary.cpp +162 -0
- data/ext/quickfix/Dictionary.h +94 -0
- data/ext/quickfix/Event.h +95 -0
- data/ext/quickfix/Exceptions.h +299 -0
- data/ext/quickfix/Field.h +672 -0
- data/ext/quickfix/FieldConvertors.h +863 -0
- data/ext/quickfix/FieldMap.cpp +238 -0
- data/ext/quickfix/FieldMap.h +244 -0
- data/ext/quickfix/FieldNumbers.h +46 -0
- data/ext/quickfix/FieldTypes.cpp +64 -0
- data/ext/quickfix/FieldTypes.h +698 -0
- data/ext/quickfix/Fields.h +31 -0
- data/ext/quickfix/FileLog.cpp +200 -0
- data/ext/quickfix/FileLog.h +112 -0
- data/ext/quickfix/FileStore.cpp +332 -0
- data/ext/quickfix/FileStore.h +129 -0
- data/ext/quickfix/FixFieldNumbers.h +1537 -0
- data/ext/quickfix/FixFields.h +1538 -0
- data/ext/quickfix/FixValues.h +3281 -0
- data/ext/quickfix/FlexLexer.h +188 -0
- data/ext/quickfix/Group.cpp +64 -0
- data/ext/quickfix/Group.h +73 -0
- data/ext/quickfix/HtmlBuilder.h +186 -0
- data/ext/quickfix/HttpConnection.cpp +739 -0
- data/ext/quickfix/HttpConnection.h +78 -0
- data/ext/quickfix/HttpMessage.cpp +149 -0
- data/ext/quickfix/HttpMessage.h +133 -0
- data/ext/quickfix/HttpParser.cpp +49 -0
- data/ext/quickfix/HttpParser.h +54 -0
- data/ext/quickfix/HttpServer.cpp +169 -0
- data/ext/quickfix/HttpServer.h +78 -0
- data/ext/quickfix/Initiator.cpp +289 -0
- data/ext/quickfix/Initiator.h +149 -0
- data/ext/quickfix/Log.cpp +77 -0
- data/ext/quickfix/Log.h +179 -0
- data/ext/quickfix/Message.cpp +580 -0
- data/ext/quickfix/Message.h +370 -0
- data/ext/quickfix/MessageCracker.h +188 -0
- data/ext/quickfix/MessageSorters.cpp +105 -0
- data/ext/quickfix/MessageSorters.h +156 -0
- data/ext/quickfix/MessageStore.cpp +146 -0
- data/ext/quickfix/MessageStore.h +174 -0
- data/ext/quickfix/Mutex.h +131 -0
- data/ext/quickfix/MySQLConnection.h +194 -0
- data/ext/quickfix/MySQLLog.cpp +275 -0
- data/ext/quickfix/MySQLLog.h +145 -0
- data/ext/quickfix/MySQLStore.cpp +331 -0
- data/ext/quickfix/MySQLStore.h +142 -0
- data/ext/quickfix/NullStore.cpp +54 -0
- data/ext/quickfix/NullStore.h +99 -0
- data/ext/quickfix/OdbcConnection.h +266 -0
- data/ext/quickfix/OdbcLog.cpp +252 -0
- data/ext/quickfix/OdbcLog.h +117 -0
- data/ext/quickfix/OdbcStore.cpp +338 -0
- data/ext/quickfix/OdbcStore.h +113 -0
- data/ext/quickfix/PUGIXML_DOMDocument.cpp +112 -0
- data/ext/quickfix/PUGIXML_DOMDocument.h +81 -0
- data/ext/quickfix/Parser.cpp +103 -0
- data/ext/quickfix/Parser.h +57 -0
- data/ext/quickfix/PostgreSQLConnection.h +176 -0
- data/ext/quickfix/PostgreSQLLog.cpp +276 -0
- data/ext/quickfix/PostgreSQLLog.h +144 -0
- data/ext/quickfix/PostgreSQLStore.cpp +334 -0
- data/ext/quickfix/PostgreSQLStore.h +141 -0
- data/ext/quickfix/Queue.h +75 -0
- data/ext/quickfix/QuickfixRuby.cpp +252066 -0
- data/ext/quickfix/QuickfixRuby.h +34 -0
- data/ext/quickfix/Responder.h +43 -0
- data/ext/quickfix/Session.cpp +1487 -0
- data/ext/quickfix/Session.h +335 -0
- data/ext/quickfix/SessionFactory.cpp +274 -0
- data/ext/quickfix/SessionFactory.h +86 -0
- data/ext/quickfix/SessionID.h +170 -0
- data/ext/quickfix/SessionSettings.cpp +189 -0
- data/ext/quickfix/SessionSettings.h +171 -0
- data/ext/quickfix/SessionState.h +231 -0
- data/ext/quickfix/Settings.cpp +100 -0
- data/ext/quickfix/Settings.h +53 -0
- data/ext/quickfix/SharedArray.h +150 -0
- data/ext/quickfix/SocketAcceptor.cpp +222 -0
- data/ext/quickfix/SocketAcceptor.h +75 -0
- data/ext/quickfix/SocketConnection.cpp +238 -0
- data/ext/quickfix/SocketConnection.h +103 -0
- data/ext/quickfix/SocketConnector.cpp +116 -0
- data/ext/quickfix/SocketConnector.h +67 -0
- data/ext/quickfix/SocketInitiator.cpp +260 -0
- data/ext/quickfix/SocketInitiator.h +81 -0
- data/ext/quickfix/SocketMonitor.cpp +335 -0
- data/ext/quickfix/SocketMonitor.h +111 -0
- data/ext/quickfix/SocketServer.cpp +177 -0
- data/ext/quickfix/SocketServer.h +100 -0
- data/ext/quickfix/ThreadedSocketAcceptor.cpp +258 -0
- data/ext/quickfix/ThreadedSocketAcceptor.h +98 -0
- data/ext/quickfix/ThreadedSocketConnection.cpp +209 -0
- data/ext/quickfix/ThreadedSocketConnection.h +82 -0
- data/ext/quickfix/ThreadedSocketInitiator.cpp +268 -0
- data/ext/quickfix/ThreadedSocketInitiator.h +84 -0
- data/ext/quickfix/TimeRange.cpp +173 -0
- data/ext/quickfix/TimeRange.h +258 -0
- data/ext/quickfix/Utility.cpp +537 -0
- data/ext/quickfix/Utility.h +219 -0
- data/ext/quickfix/Values.h +62 -0
- data/ext/quickfix/config.h +0 -0
- data/ext/quickfix/config_windows.h +0 -0
- data/ext/quickfix/extconf.rb +12 -0
- data/ext/quickfix/index.h +37 -0
- data/ext/quickfix/pugiconfig.hpp +72 -0
- data/ext/quickfix/pugixml.cpp +10765 -0
- data/ext/quickfix/pugixml.hpp +1341 -0
- data/ext/quickfix/strptime.h +7 -0
- data/lib/quickfix40.rb +274 -0
- data/lib/quickfix41.rb +351 -0
- data/lib/quickfix42.rb +1184 -0
- data/lib/quickfix43.rb +3504 -0
- data/lib/quickfix44.rb +10721 -0
- data/lib/quickfix50.rb +13426 -0
- data/lib/quickfix50sp1.rb +15629 -0
- data/lib/quickfix50sp2.rb +17068 -0
- data/lib/quickfix_fields.rb +19853 -0
- data/lib/quickfix_ruby.rb +82 -0
- data/lib/quickfixt11.rb +70 -0
- data/spec/FIX40.xml +862 -0
- data/spec/FIX41.xml +1285 -0
- data/spec/FIX42.xml +2746 -0
- data/spec/FIX43.xml +4229 -0
- data/spec/FIX44.xml +6596 -0
- data/spec/FIX50.xml +8137 -0
- data/spec/FIX50SP1.xml +9496 -0
- data/spec/FIX50SP2.xml +10011 -0
- data/spec/FIXT11.xml +313 -0
- data/test/test_DataDictionaryTestCase.rb +268 -0
- data/test/test_DictionaryTestCase.rb +112 -0
- data/test/test_FieldBaseTestCase.rb +24 -0
- data/test/test_MessageTestCase.rb +368 -0
- data/test/test_SessionSettingsTestCase.rb +41 -0
- metadata +193 -0
|
@@ -0,0 +1,1487 @@
|
|
|
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
|
+
|
|
31
|
+
namespace FIX
|
|
32
|
+
{
|
|
33
|
+
Session::Sessions Session::s_sessions;
|
|
34
|
+
Session::SessionIDs Session::s_sessionIDs;
|
|
35
|
+
Session::Sessions Session::s_registered;
|
|
36
|
+
Mutex Session::s_mutex;
|
|
37
|
+
|
|
38
|
+
#define LOGEX( method ) try { method; } catch( std::exception& e ) \
|
|
39
|
+
{ m_state.onEvent( e.what() ); }
|
|
40
|
+
|
|
41
|
+
Session::Session( Application& application,
|
|
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_millisecondsInTimeStamp( true ),
|
|
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 );
|
|
71
|
+
m_state.store( m_messageStoreFactory.create( m_sessionID ) );
|
|
72
|
+
if ( m_pLogFactory )
|
|
73
|
+
m_state.log( m_pLogFactory->create( m_sessionID ) );
|
|
74
|
+
|
|
75
|
+
if( !checkSessionTime(UtcTimeStamp()) )
|
|
76
|
+
reset();
|
|
77
|
+
|
|
78
|
+
addSession( *this );
|
|
79
|
+
m_application.onCreate( m_sessionID );
|
|
80
|
+
m_state.onEvent( "Created session" );
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Session::~Session()
|
|
84
|
+
{
|
|
85
|
+
removeSession( *this );
|
|
86
|
+
m_messageStoreFactory.destroy( m_state.store() );
|
|
87
|
+
if ( m_pLogFactory && m_state.log() )
|
|
88
|
+
m_pLogFactory->destroy( m_state.log() );
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void Session::insertSendingTime( Header& header )
|
|
92
|
+
{
|
|
93
|
+
UtcTimeStamp now;
|
|
94
|
+
bool showMilliseconds = false;
|
|
95
|
+
if( m_sessionID.getBeginString() == BeginString_FIXT11 )
|
|
96
|
+
showMilliseconds = true;
|
|
97
|
+
else
|
|
98
|
+
showMilliseconds = m_sessionID.getBeginString() >= BeginString_FIX42;
|
|
99
|
+
|
|
100
|
+
header.setField( SendingTime(now, showMilliseconds && m_millisecondsInTimeStamp) );
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void Session::insertOrigSendingTime( Header& header, const UtcTimeStamp& when )
|
|
104
|
+
{
|
|
105
|
+
bool showMilliseconds = false;
|
|
106
|
+
if( m_sessionID.getBeginString() == BeginString_FIXT11 )
|
|
107
|
+
showMilliseconds = true;
|
|
108
|
+
else
|
|
109
|
+
showMilliseconds = m_sessionID.getBeginString() >= BeginString_FIX42;
|
|
110
|
+
|
|
111
|
+
header.setField( OrigSendingTime(when, showMilliseconds && m_millisecondsInTimeStamp) );
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void Session::fill( Header& header )
|
|
115
|
+
{
|
|
116
|
+
UtcTimeStamp now;
|
|
117
|
+
m_state.lastSentTime( now );
|
|
118
|
+
header.setField( m_sessionID.getBeginString() );
|
|
119
|
+
header.setField( m_sessionID.getSenderCompID() );
|
|
120
|
+
header.setField( m_sessionID.getTargetCompID() );
|
|
121
|
+
header.setField( MsgSeqNum( getExpectedSenderNum() ) );
|
|
122
|
+
insertSendingTime( header );
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
void Session::next()
|
|
126
|
+
{
|
|
127
|
+
next( UtcTimeStamp() );
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
void Session::next( const UtcTimeStamp& timeStamp )
|
|
131
|
+
{
|
|
132
|
+
try
|
|
133
|
+
{
|
|
134
|
+
if ( !checkSessionTime(timeStamp) )
|
|
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" );
|
|
144
|
+
generateLogout( m_state.logoutReason() );
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if ( !m_state.receivedLogon() )
|
|
152
|
+
{
|
|
153
|
+
if ( m_state.shouldSendLogon() && isLogonTime(timeStamp) )
|
|
154
|
+
{
|
|
155
|
+
generateLogon();
|
|
156
|
+
m_state.onEvent( "Initiated logon request" );
|
|
157
|
+
}
|
|
158
|
+
else if ( m_state.alreadySentLogon() && m_state.logonTimedOut() )
|
|
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
|
+
|
|
174
|
+
if ( m_state.withinHeartBeat() ) return ;
|
|
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" );
|
|
186
|
+
m_state.testRequest( m_state.testRequest() + 1 );
|
|
187
|
+
m_state.onEvent( "Sent test request TEST" );
|
|
188
|
+
}
|
|
189
|
+
else if ( m_state.needHeartbeat() )
|
|
190
|
+
{
|
|
191
|
+
generateHeartbeat();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch ( FIX::IOException& e )
|
|
196
|
+
{
|
|
197
|
+
m_state.onEvent( e.what() );
|
|
198
|
+
disconnect();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void Session::nextLogon( const Message& logon, const UtcTimeStamp& timeStamp )
|
|
203
|
+
{
|
|
204
|
+
SenderCompID senderCompID;
|
|
205
|
+
TargetCompID targetCompID;
|
|
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
|
+
|
|
226
|
+
ResetSeqNumFlag resetSeqNumFlag(false);
|
|
227
|
+
logon.getFieldIfSet(resetSeqNumFlag);
|
|
228
|
+
m_state.receivedReset( 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
|
+
|
|
236
|
+
if( m_state.shouldSendLogon() && !m_state.receivedReset() )
|
|
237
|
+
{
|
|
238
|
+
m_state.onEvent( "Received logon response before sending request" );
|
|
239
|
+
disconnect();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if( !m_state.initiate() && m_resetOnLogon )
|
|
244
|
+
m_state.reset();
|
|
245
|
+
|
|
246
|
+
if( !verify( logon, false, true ) )
|
|
247
|
+
return;
|
|
248
|
+
m_state.receivedLogon( true );
|
|
249
|
+
|
|
250
|
+
if ( !m_state.initiate()
|
|
251
|
+
|| (m_state.receivedReset() && !m_state.sentReset()) )
|
|
252
|
+
{
|
|
253
|
+
logon.getFieldIfSet(m_state.heartBtInt());
|
|
254
|
+
m_state.onEvent( "Received logon request" );
|
|
255
|
+
generateLogon( logon );
|
|
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
|
+
|
|
264
|
+
MsgSeqNum msgSeqNum;
|
|
265
|
+
logon.getHeader().getField( msgSeqNum );
|
|
266
|
+
if ( isTargetTooHigh( msgSeqNum ) && !resetSeqNumFlag )
|
|
267
|
+
{
|
|
268
|
+
doTargetTooHigh( logon );
|
|
269
|
+
}
|
|
270
|
+
else
|
|
271
|
+
{
|
|
272
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
273
|
+
nextQueued( timeStamp );
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if ( isLoggedOn() )
|
|
277
|
+
m_application.onLogon( m_sessionID );
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void Session::nextHeartbeat( const Message& heartbeat, const UtcTimeStamp& timeStamp )
|
|
281
|
+
{
|
|
282
|
+
if ( !verify( heartbeat ) ) return ;
|
|
283
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
284
|
+
nextQueued( timeStamp );
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
void Session::nextTestRequest( const Message& testRequest, const UtcTimeStamp& timeStamp )
|
|
288
|
+
{
|
|
289
|
+
if ( !verify( testRequest ) ) return ;
|
|
290
|
+
generateHeartbeat( testRequest );
|
|
291
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
292
|
+
nextQueued( timeStamp );
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
void 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" );
|
|
301
|
+
generateLogout();
|
|
302
|
+
m_state.onEvent( "Sending logout response" );
|
|
303
|
+
}
|
|
304
|
+
else
|
|
305
|
+
m_state.onEvent( "Received logout response" );
|
|
306
|
+
|
|
307
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
308
|
+
if ( m_resetOnLogout ) m_state.reset();
|
|
309
|
+
disconnect();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
void Session::nextReject( const Message& reject, const UtcTimeStamp& timeStamp )
|
|
313
|
+
{
|
|
314
|
+
if ( !verify( reject, false, true ) ) return ;
|
|
315
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
316
|
+
nextQueued( timeStamp );
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
void Session::nextSequenceReset( const Message& sequenceReset, const UtcTimeStamp& timeStamp )
|
|
320
|
+
{
|
|
321
|
+
bool isGapFill = false;
|
|
322
|
+
GapFillFlag gapFillFlag;
|
|
323
|
+
if ( sequenceReset.getFieldIfSet( gapFillFlag ) )
|
|
324
|
+
{
|
|
325
|
+
isGapFill = gapFillFlag;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if ( !verify( sequenceReset, isGapFill, isGapFill ) ) return ;
|
|
329
|
+
|
|
330
|
+
NewSeqNo newSeqNo;
|
|
331
|
+
if ( sequenceReset.getFieldIfSet( newSeqNo ) )
|
|
332
|
+
{
|
|
333
|
+
m_state.onEvent( "Received SequenceReset FROM: "
|
|
334
|
+
+ IntConvertor::convert( getExpectedTargetNum() ) +
|
|
335
|
+
" TO: " + IntConvertor::convert( newSeqNo ) );
|
|
336
|
+
|
|
337
|
+
if ( newSeqNo > getExpectedTargetNum() )
|
|
338
|
+
m_state.setNextTargetMsgSeqNum( MsgSeqNum( newSeqNo ) );
|
|
339
|
+
else if ( newSeqNo < getExpectedTargetNum() )
|
|
340
|
+
generateReject( sequenceReset, SessionRejectReason_VALUE_IS_INCORRECT );
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
void Session::nextResendRequest( const Message& resendRequest, const UtcTimeStamp& timeStamp )
|
|
345
|
+
{
|
|
346
|
+
if ( !verify( resendRequest, false, false ) ) return ;
|
|
347
|
+
|
|
348
|
+
Locker l( m_mutex );
|
|
349
|
+
|
|
350
|
+
BeginSeqNo beginSeqNo;
|
|
351
|
+
EndSeqNo endSeqNo;
|
|
352
|
+
resendRequest.getField( beginSeqNo );
|
|
353
|
+
resendRequest.getField( endSeqNo );
|
|
354
|
+
|
|
355
|
+
m_state.onEvent( "Received ResendRequest FROM: "
|
|
356
|
+
+ IntConvertor::convert( beginSeqNo ) +
|
|
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) ||
|
|
362
|
+
(endSeqNo >= getExpectedSenderNum()) )
|
|
363
|
+
{ endSeqNo = getExpectedSenderNum() - 1; }
|
|
364
|
+
|
|
365
|
+
if ( !m_persistMessages )
|
|
366
|
+
{
|
|
367
|
+
endSeqNo = EndSeqNo(endSeqNo + 1);
|
|
368
|
+
int next = m_state.getNextSenderMsgSeqNum();
|
|
369
|
+
if( endSeqNo > next )
|
|
370
|
+
endSeqNo = EndSeqNo(next);
|
|
371
|
+
generateSequenceReset( beginSeqNo, endSeqNo );
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
std::vector < std::string > messages;
|
|
376
|
+
m_state.get( beginSeqNo, endSeqNo, messages );
|
|
377
|
+
|
|
378
|
+
std::vector < std::string > ::iterator i;
|
|
379
|
+
MsgSeqNum msgSeqNum(0);
|
|
380
|
+
MsgType msgType;
|
|
381
|
+
int begin = 0;
|
|
382
|
+
int current = beginSeqNo;
|
|
383
|
+
std::string messageString;
|
|
384
|
+
Message msg;
|
|
385
|
+
|
|
386
|
+
for ( i = messages.begin(); i != messages.end(); ++i )
|
|
387
|
+
{
|
|
388
|
+
const DataDictionary& sessionDD =
|
|
389
|
+
m_dataDictionaryProvider.getSessionDataDictionary(m_sessionID.getBeginString());
|
|
390
|
+
|
|
391
|
+
if( m_sessionID.isFIXT() )
|
|
392
|
+
{
|
|
393
|
+
msg.setStringHeader(*i);
|
|
394
|
+
ApplVerID applVerID;
|
|
395
|
+
if( !msg.getHeader().getFieldIfSet(applVerID) )
|
|
396
|
+
applVerID = m_senderDefaultApplVerID;
|
|
397
|
+
|
|
398
|
+
const DataDictionary& applicationDD =
|
|
399
|
+
m_dataDictionaryProvider.getApplicationDataDictionary(applVerID);
|
|
400
|
+
msg = Message( *i, sessionDD, applicationDD, m_validateLengthAndChecksum );
|
|
401
|
+
}
|
|
402
|
+
else
|
|
403
|
+
{
|
|
404
|
+
msg = Message( *i, sessionDD, m_validateLengthAndChecksum );
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
msg.getHeader().getField( msgSeqNum );
|
|
409
|
+
msg.getHeader().getField( msgType );
|
|
410
|
+
|
|
411
|
+
if( (current != msgSeqNum) && !begin )
|
|
412
|
+
begin = current;
|
|
413
|
+
|
|
414
|
+
if ( Message::isAdminMsgType( msgType ) )
|
|
415
|
+
{
|
|
416
|
+
if ( !begin ) begin = msgSeqNum;
|
|
417
|
+
}
|
|
418
|
+
else
|
|
419
|
+
{
|
|
420
|
+
if ( resend( msg ) )
|
|
421
|
+
{
|
|
422
|
+
if ( begin ) generateSequenceReset( begin, msgSeqNum );
|
|
423
|
+
send( msg.toString(messageString) );
|
|
424
|
+
m_state.onEvent( "Resending Message: "
|
|
425
|
+
+ IntConvertor::convert( msgSeqNum ) );
|
|
426
|
+
begin = 0;
|
|
427
|
+
}
|
|
428
|
+
else
|
|
429
|
+
{ if ( !begin ) begin = msgSeqNum; }
|
|
430
|
+
}
|
|
431
|
+
current = msgSeqNum + 1;
|
|
432
|
+
}
|
|
433
|
+
if ( begin )
|
|
434
|
+
{
|
|
435
|
+
generateSequenceReset( begin, msgSeqNum + 1 );
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if ( endSeqNo > msgSeqNum )
|
|
439
|
+
{
|
|
440
|
+
endSeqNo = EndSeqNo(endSeqNo + 1);
|
|
441
|
+
int next = m_state.getNextSenderMsgSeqNum();
|
|
442
|
+
if( endSeqNo > next )
|
|
443
|
+
endSeqNo = EndSeqNo(next);
|
|
444
|
+
generateSequenceReset( beginSeqNo, endSeqNo );
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
resendRequest.getHeader().getField( msgSeqNum );
|
|
448
|
+
if( !isTargetTooHigh(msgSeqNum) && !isTargetTooLow(msgSeqNum) )
|
|
449
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
bool Session::send( Message& message )
|
|
453
|
+
{
|
|
454
|
+
message.getHeader().removeField( FIELD::PossDupFlag );
|
|
455
|
+
message.getHeader().removeField( FIELD::OrigSendingTime );
|
|
456
|
+
return sendRaw( message );
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
bool Session::sendRaw( Message& message, int num )
|
|
460
|
+
{
|
|
461
|
+
Locker l( m_mutex );
|
|
462
|
+
|
|
463
|
+
try
|
|
464
|
+
{
|
|
465
|
+
Header& header = message.getHeader();
|
|
466
|
+
|
|
467
|
+
MsgType msgType;
|
|
468
|
+
header.getFieldIfSet(msgType);
|
|
469
|
+
|
|
470
|
+
fill( header );
|
|
471
|
+
std::string messageString;
|
|
472
|
+
|
|
473
|
+
if ( num )
|
|
474
|
+
header.setField( MsgSeqNum( num ) );
|
|
475
|
+
|
|
476
|
+
if ( Message::isAdminMsgType( msgType ) )
|
|
477
|
+
{
|
|
478
|
+
m_application.toAdmin( message, m_sessionID );
|
|
479
|
+
|
|
480
|
+
if( msgType == "A" && !m_state.receivedReset() )
|
|
481
|
+
{
|
|
482
|
+
ResetSeqNumFlag resetSeqNumFlag( false );
|
|
483
|
+
message.getFieldIfSet(resetSeqNumFlag);
|
|
484
|
+
|
|
485
|
+
if( resetSeqNumFlag )
|
|
486
|
+
{
|
|
487
|
+
m_state.reset();
|
|
488
|
+
message.getHeader().setField( MsgSeqNum(getExpectedSenderNum()) );
|
|
489
|
+
}
|
|
490
|
+
m_state.sentReset( resetSeqNumFlag );
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
message.toString( messageString );
|
|
494
|
+
|
|
495
|
+
if( !num )
|
|
496
|
+
persist( message, messageString );
|
|
497
|
+
|
|
498
|
+
if (
|
|
499
|
+
msgType == "A" || msgType == "5"
|
|
500
|
+
|| msgType == "2" || msgType == "4"
|
|
501
|
+
|| isLoggedOn() )
|
|
502
|
+
{
|
|
503
|
+
send( messageString );
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
else
|
|
507
|
+
{
|
|
508
|
+
// do not send application messages if they will just be cleared
|
|
509
|
+
if( !isLoggedOn() && shouldSendReset() )
|
|
510
|
+
return false;
|
|
511
|
+
|
|
512
|
+
try
|
|
513
|
+
{
|
|
514
|
+
m_application.toApp( message, m_sessionID );
|
|
515
|
+
message.toString( messageString );
|
|
516
|
+
|
|
517
|
+
if( !num )
|
|
518
|
+
persist( message, messageString );
|
|
519
|
+
|
|
520
|
+
if ( isLoggedOn() )
|
|
521
|
+
send( messageString );
|
|
522
|
+
}
|
|
523
|
+
catch ( DoNotSend& ) { return false; }
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
catch ( IOException& e )
|
|
529
|
+
{
|
|
530
|
+
m_state.onEvent( e.what() );
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
bool Session::send( const std::string& string )
|
|
536
|
+
{
|
|
537
|
+
if ( !m_pResponder ) return false;
|
|
538
|
+
m_state.onOutgoing( string );
|
|
539
|
+
return m_pResponder->send( string );
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
void Session::disconnect()
|
|
543
|
+
{
|
|
544
|
+
Locker l(m_mutex);
|
|
545
|
+
|
|
546
|
+
if ( m_pResponder )
|
|
547
|
+
{
|
|
548
|
+
m_state.onEvent( "Disconnecting" );
|
|
549
|
+
|
|
550
|
+
m_pResponder->disconnect();
|
|
551
|
+
m_pResponder = 0;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if ( m_state.receivedLogon() || m_state.sentLogon() )
|
|
555
|
+
{
|
|
556
|
+
m_state.receivedLogon( false );
|
|
557
|
+
m_state.sentLogon( false );
|
|
558
|
+
m_application.onLogout( m_sessionID );
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
m_state.sentLogout( false );
|
|
562
|
+
m_state.receivedReset( false );
|
|
563
|
+
m_state.sentReset( false );
|
|
564
|
+
m_state.clearQueue();
|
|
565
|
+
m_state.logoutReason();
|
|
566
|
+
if ( m_resetOnDisconnect )
|
|
567
|
+
m_state.reset();
|
|
568
|
+
|
|
569
|
+
m_state.resendRange( 0, 0 );
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
bool Session::resend( Message& message )
|
|
573
|
+
{
|
|
574
|
+
SendingTime sendingTime;
|
|
575
|
+
MsgSeqNum msgSeqNum;
|
|
576
|
+
Header& header = message.getHeader();
|
|
577
|
+
header.getField( sendingTime );
|
|
578
|
+
header.getField( msgSeqNum );
|
|
579
|
+
insertOrigSendingTime( header, sendingTime );
|
|
580
|
+
header.setField( PossDupFlag( true ) );
|
|
581
|
+
insertSendingTime( header );
|
|
582
|
+
|
|
583
|
+
try
|
|
584
|
+
{
|
|
585
|
+
m_application.toApp( message, m_sessionID );
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
catch ( DoNotSend& )
|
|
589
|
+
{ return false; }
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
void Session::persist( const Message& message, const std::string& messageString )
|
|
593
|
+
throw ( IOException )
|
|
594
|
+
{
|
|
595
|
+
MsgSeqNum msgSeqNum;
|
|
596
|
+
message.getHeader().getField( msgSeqNum );
|
|
597
|
+
if( m_persistMessages )
|
|
598
|
+
m_state.set( msgSeqNum, messageString );
|
|
599
|
+
m_state.incrNextSenderMsgSeqNum();
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
void Session::generateLogon()
|
|
603
|
+
{
|
|
604
|
+
Message logon;
|
|
605
|
+
logon.getHeader().setField( MsgType( "A" ) );
|
|
606
|
+
logon.setField( EncryptMethod( 0 ) );
|
|
607
|
+
logon.setField( m_state.heartBtInt() );
|
|
608
|
+
if( m_sessionID.isFIXT() )
|
|
609
|
+
logon.setField( DefaultApplVerID(m_senderDefaultApplVerID) );
|
|
610
|
+
if( m_refreshOnLogon )
|
|
611
|
+
refresh();
|
|
612
|
+
if( m_resetOnLogon )
|
|
613
|
+
m_state.reset();
|
|
614
|
+
if( shouldSendReset() )
|
|
615
|
+
logon.setField( ResetSeqNumFlag(true) );
|
|
616
|
+
|
|
617
|
+
fill( logon.getHeader() );
|
|
618
|
+
UtcTimeStamp now;
|
|
619
|
+
m_state.lastReceivedTime( now );
|
|
620
|
+
m_state.testRequest( 0 );
|
|
621
|
+
m_state.sentLogon( true );
|
|
622
|
+
sendRaw( logon );
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
void Session::generateLogon( const Message& aLogon )
|
|
626
|
+
{
|
|
627
|
+
Message logon;
|
|
628
|
+
EncryptMethod encryptMethod;
|
|
629
|
+
HeartBtInt heartBtInt;
|
|
630
|
+
logon.setField( EncryptMethod( 0 ) );
|
|
631
|
+
if( m_sessionID.isFIXT() )
|
|
632
|
+
logon.setField( DefaultApplVerID(m_senderDefaultApplVerID) );
|
|
633
|
+
if( m_state.receivedReset() )
|
|
634
|
+
logon.setField( ResetSeqNumFlag(true) );
|
|
635
|
+
aLogon.getField( heartBtInt );
|
|
636
|
+
logon.getHeader().setField( MsgType( "A" ) );
|
|
637
|
+
logon.setField( heartBtInt );
|
|
638
|
+
fill( logon.getHeader() );
|
|
639
|
+
sendRaw( logon );
|
|
640
|
+
m_state.sentLogon( true );
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
void Session::generateResendRequest( const BeginString& beginString, const MsgSeqNum& msgSeqNum )
|
|
644
|
+
{
|
|
645
|
+
Message resendRequest;
|
|
646
|
+
BeginSeqNo beginSeqNo( ( int ) getExpectedTargetNum() );
|
|
647
|
+
EndSeqNo endSeqNo( msgSeqNum - 1 );
|
|
648
|
+
if ( beginString >= FIX::BeginString_FIX42 )
|
|
649
|
+
endSeqNo = 0;
|
|
650
|
+
else if( beginString <= FIX::BeginString_FIX41 )
|
|
651
|
+
endSeqNo = 999999;
|
|
652
|
+
resendRequest.getHeader().setField( MsgType( "2" ) );
|
|
653
|
+
resendRequest.setField( beginSeqNo );
|
|
654
|
+
resendRequest.setField( endSeqNo );
|
|
655
|
+
fill( resendRequest.getHeader() );
|
|
656
|
+
sendRaw( resendRequest );
|
|
657
|
+
|
|
658
|
+
m_state.onEvent( "Sent ResendRequest FROM: "
|
|
659
|
+
+ IntConvertor::convert( beginSeqNo ) +
|
|
660
|
+
" TO: " + IntConvertor::convert( endSeqNo ) );
|
|
661
|
+
|
|
662
|
+
m_state.resendRange( beginSeqNo, msgSeqNum - 1 );
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
void Session::generateSequenceReset
|
|
666
|
+
( int beginSeqNo, int endSeqNo )
|
|
667
|
+
{
|
|
668
|
+
Message sequenceReset;
|
|
669
|
+
NewSeqNo newSeqNo( endSeqNo );
|
|
670
|
+
sequenceReset.getHeader().setField( MsgType( "4" ) );
|
|
671
|
+
sequenceReset.getHeader().setField( PossDupFlag( true ) );
|
|
672
|
+
sequenceReset.setField( newSeqNo );
|
|
673
|
+
fill( sequenceReset.getHeader() );
|
|
674
|
+
|
|
675
|
+
SendingTime sendingTime;
|
|
676
|
+
sequenceReset.getHeader().getField( sendingTime );
|
|
677
|
+
insertOrigSendingTime( sequenceReset.getHeader(), sendingTime );
|
|
678
|
+
sequenceReset.getHeader().setField( MsgSeqNum( beginSeqNo ) );
|
|
679
|
+
sequenceReset.setField( GapFillFlag( true ) );
|
|
680
|
+
sendRaw( sequenceReset, beginSeqNo );
|
|
681
|
+
m_state.onEvent( "Sent SequenceReset TO: "
|
|
682
|
+
+ IntConvertor::convert( newSeqNo ) );
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
void Session::generateHeartbeat()
|
|
686
|
+
{
|
|
687
|
+
Message heartbeat;
|
|
688
|
+
heartbeat.getHeader().setField( MsgType( "0" ) );
|
|
689
|
+
fill( heartbeat.getHeader() );
|
|
690
|
+
sendRaw( heartbeat );
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
void Session::generateHeartbeat( const Message& testRequest )
|
|
694
|
+
{
|
|
695
|
+
Message heartbeat;
|
|
696
|
+
heartbeat.getHeader().setField( MsgType( "0" ) );
|
|
697
|
+
fill( heartbeat.getHeader() );
|
|
698
|
+
try
|
|
699
|
+
{
|
|
700
|
+
TestReqID testReqID;
|
|
701
|
+
testRequest.getField( testReqID );
|
|
702
|
+
heartbeat.setField( testReqID );
|
|
703
|
+
}
|
|
704
|
+
catch ( FieldNotFound& ) {}
|
|
705
|
+
|
|
706
|
+
sendRaw( heartbeat );
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
void Session::generateTestRequest( const std::string& id )
|
|
710
|
+
{
|
|
711
|
+
Message testRequest;
|
|
712
|
+
testRequest.getHeader().setField( MsgType( "1" ) );
|
|
713
|
+
fill( testRequest.getHeader() );
|
|
714
|
+
TestReqID testReqID( id );
|
|
715
|
+
testRequest.setField( testReqID );
|
|
716
|
+
|
|
717
|
+
sendRaw( testRequest );
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
void Session::generateReject( const Message& message, int err, int field )
|
|
721
|
+
{
|
|
722
|
+
std::string beginString = m_sessionID.getBeginString();
|
|
723
|
+
|
|
724
|
+
Message reject;
|
|
725
|
+
reject.getHeader().setField( MsgType( "3" ) );
|
|
726
|
+
reject.reverseRoute( message.getHeader() );
|
|
727
|
+
fill( reject.getHeader() );
|
|
728
|
+
|
|
729
|
+
MsgSeqNum msgSeqNum;
|
|
730
|
+
MsgType msgType;
|
|
731
|
+
|
|
732
|
+
message.getHeader().getField( msgType );
|
|
733
|
+
if( message.getHeader().getFieldIfSet( msgSeqNum ) )
|
|
734
|
+
{
|
|
735
|
+
if( msgSeqNum.getString() != "" )
|
|
736
|
+
reject.setField( RefSeqNum( msgSeqNum ) );
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
if ( beginString >= FIX::BeginString_FIX42 )
|
|
740
|
+
{
|
|
741
|
+
if( msgType.getString() != "" )
|
|
742
|
+
reject.setField( RefMsgType( msgType ) );
|
|
743
|
+
if ( (beginString == FIX::BeginString_FIX42
|
|
744
|
+
&& err <= SessionRejectReason_INVALID_MSGTYPE)
|
|
745
|
+
|| beginString > FIX::BeginString_FIX42 )
|
|
746
|
+
{
|
|
747
|
+
reject.setField( SessionRejectReason( err ) );
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if ( msgType != MsgType_Logon && msgType != MsgType_SequenceReset
|
|
751
|
+
&& msgSeqNum == getExpectedTargetNum() )
|
|
752
|
+
{ m_state.incrNextTargetMsgSeqNum(); }
|
|
753
|
+
|
|
754
|
+
const char* reason = 0;
|
|
755
|
+
switch ( err )
|
|
756
|
+
{
|
|
757
|
+
case SessionRejectReason_INVALID_TAG_NUMBER:
|
|
758
|
+
reason = SessionRejectReason_INVALID_TAG_NUMBER_TEXT;
|
|
759
|
+
break;
|
|
760
|
+
case SessionRejectReason_REQUIRED_TAG_MISSING:
|
|
761
|
+
reason = SessionRejectReason_REQUIRED_TAG_MISSING_TEXT;
|
|
762
|
+
break;
|
|
763
|
+
case SessionRejectReason_TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE:
|
|
764
|
+
reason = SessionRejectReason_TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE_TEXT;
|
|
765
|
+
break;
|
|
766
|
+
case SessionRejectReason_TAG_SPECIFIED_WITHOUT_A_VALUE:
|
|
767
|
+
reason = SessionRejectReason_TAG_SPECIFIED_WITHOUT_A_VALUE_TEXT;
|
|
768
|
+
break;
|
|
769
|
+
case SessionRejectReason_VALUE_IS_INCORRECT:
|
|
770
|
+
reason = SessionRejectReason_VALUE_IS_INCORRECT_TEXT;
|
|
771
|
+
break;
|
|
772
|
+
case SessionRejectReason_INCORRECT_DATA_FORMAT_FOR_VALUE:
|
|
773
|
+
reason = SessionRejectReason_INCORRECT_DATA_FORMAT_FOR_VALUE_TEXT;
|
|
774
|
+
break;
|
|
775
|
+
case SessionRejectReason_COMPID_PROBLEM:
|
|
776
|
+
reason = SessionRejectReason_COMPID_PROBLEM_TEXT;
|
|
777
|
+
break;
|
|
778
|
+
case SessionRejectReason_SENDINGTIME_ACCURACY_PROBLEM:
|
|
779
|
+
reason = SessionRejectReason_SENDINGTIME_ACCURACY_PROBLEM_TEXT;
|
|
780
|
+
break;
|
|
781
|
+
case SessionRejectReason_INVALID_MSGTYPE:
|
|
782
|
+
reason = SessionRejectReason_INVALID_MSGTYPE_TEXT;
|
|
783
|
+
break;
|
|
784
|
+
case SessionRejectReason_TAG_APPEARS_MORE_THAN_ONCE:
|
|
785
|
+
reason = SessionRejectReason_TAG_APPEARS_MORE_THAN_ONCE_TEXT;
|
|
786
|
+
break;
|
|
787
|
+
case SessionRejectReason_TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER:
|
|
788
|
+
reason = SessionRejectReason_TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER_TEXT;
|
|
789
|
+
break;
|
|
790
|
+
case SessionRejectReason_INCORRECT_NUMINGROUP_COUNT_FOR_REPEATING_GROUP:
|
|
791
|
+
reason = SessionRejectReason_INCORRECT_NUMINGROUP_COUNT_FOR_REPEATING_GROUP_TEXT;
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
if ( reason && ( field || err == SessionRejectReason_INVALID_TAG_NUMBER ) )
|
|
795
|
+
{
|
|
796
|
+
populateRejectReason( reject, field, reason );
|
|
797
|
+
m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected: "
|
|
798
|
+
+ reason + ":" + IntConvertor::convert( field ) );
|
|
799
|
+
}
|
|
800
|
+
else if ( reason )
|
|
801
|
+
{
|
|
802
|
+
populateRejectReason( reject, reason );
|
|
803
|
+
m_state.onEvent( "Message " + msgSeqNum.getString()
|
|
804
|
+
+ " Rejected: " + reason );
|
|
805
|
+
}
|
|
806
|
+
else
|
|
807
|
+
m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected" );
|
|
808
|
+
|
|
809
|
+
if ( !m_state.receivedLogon() )
|
|
810
|
+
throw std::runtime_error( "Tried to send a reject while not logged on" );
|
|
811
|
+
|
|
812
|
+
sendRaw( reject );
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
void Session::generateReject( const Message& message, const std::string& str )
|
|
816
|
+
{
|
|
817
|
+
std::string beginString = m_sessionID.getBeginString();
|
|
818
|
+
|
|
819
|
+
Message reject;
|
|
820
|
+
reject.getHeader().setField( MsgType( "3" ) );
|
|
821
|
+
reject.reverseRoute( message.getHeader() );
|
|
822
|
+
fill( reject.getHeader() );
|
|
823
|
+
|
|
824
|
+
MsgType msgType;
|
|
825
|
+
MsgSeqNum msgSeqNum;
|
|
826
|
+
|
|
827
|
+
message.getHeader().getField( msgType );
|
|
828
|
+
message.getHeader().getField( msgSeqNum );
|
|
829
|
+
if ( beginString >= FIX::BeginString_FIX42 )
|
|
830
|
+
reject.setField( RefMsgType( msgType ) );
|
|
831
|
+
reject.setField( RefSeqNum( msgSeqNum ) );
|
|
832
|
+
|
|
833
|
+
if ( msgType != MsgType_Logon && msgType != MsgType_SequenceReset )
|
|
834
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
835
|
+
|
|
836
|
+
reject.setField( Text( str ) );
|
|
837
|
+
sendRaw( reject );
|
|
838
|
+
m_state.onEvent( "Message " + msgSeqNum.getString()
|
|
839
|
+
+ " Rejected: " + str );
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
void Session::generateBusinessReject( const Message& message, int err, int field )
|
|
843
|
+
{
|
|
844
|
+
Message reject;
|
|
845
|
+
reject.getHeader().setField( MsgType( MsgType_BusinessMessageReject ) );
|
|
846
|
+
if( m_sessionID.isFIXT() )
|
|
847
|
+
reject.setField( DefaultApplVerID(m_senderDefaultApplVerID) );
|
|
848
|
+
fill( reject.getHeader() );
|
|
849
|
+
MsgType msgType;
|
|
850
|
+
MsgSeqNum msgSeqNum;
|
|
851
|
+
message.getHeader().getField( msgType );
|
|
852
|
+
message.getHeader().getField( msgSeqNum );
|
|
853
|
+
reject.setField( RefMsgType( msgType ) );
|
|
854
|
+
reject.setField( RefSeqNum( msgSeqNum ) );
|
|
855
|
+
reject.setField( BusinessRejectReason( err ) );
|
|
856
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
857
|
+
|
|
858
|
+
const char* reason = 0;
|
|
859
|
+
switch ( err )
|
|
860
|
+
{
|
|
861
|
+
case BusinessRejectReason_OTHER:
|
|
862
|
+
reason = BusinessRejectReason_OTHER_TEXT;
|
|
863
|
+
break;
|
|
864
|
+
case BusinessRejectReason_UNKNOWN_ID:
|
|
865
|
+
reason = BusinessRejectReason_UNKNOWN_ID_TEXT;
|
|
866
|
+
break;
|
|
867
|
+
case BusinessRejectReason_UNKNOWN_SECURITY:
|
|
868
|
+
reason = BusinessRejectReason_UNKNOWN_SECURITY_TEXT;
|
|
869
|
+
break;
|
|
870
|
+
case BusinessRejectReason_UNKNOWN_MESSAGE_TYPE:
|
|
871
|
+
reason = BusinessRejectReason_UNSUPPORTED_MESSAGE_TYPE_TEXT;
|
|
872
|
+
break;
|
|
873
|
+
case BusinessRejectReason_APPLICATION_NOT_AVAILABLE:
|
|
874
|
+
reason = BusinessRejectReason_APPLICATION_NOT_AVAILABLE_TEXT;
|
|
875
|
+
break;
|
|
876
|
+
case BusinessRejectReason_CONDITIONALLY_REQUIRED_FIELD_MISSING:
|
|
877
|
+
reason = BusinessRejectReason_CONDITIONALLY_REQUIRED_FIELD_MISSING_TEXT;
|
|
878
|
+
break;
|
|
879
|
+
case BusinessRejectReason_NOT_AUTHORIZED:
|
|
880
|
+
reason = BusinessRejectReason_NOT_AUTHORIZED_TEXT;
|
|
881
|
+
break;
|
|
882
|
+
case BusinessRejectReason_DELIVERTO_FIRM_NOT_AVAILABLE_AT_THIS_TIME:
|
|
883
|
+
reason = BusinessRejectReason_DELIVERTO_FIRM_NOT_AVAILABLE_AT_THIS_TIME_TEXT;
|
|
884
|
+
break;
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
if ( reason && field )
|
|
888
|
+
{
|
|
889
|
+
populateRejectReason( reject, field, reason );
|
|
890
|
+
m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected: "
|
|
891
|
+
+ reason + ":" + IntConvertor::convert( field ) );
|
|
892
|
+
}
|
|
893
|
+
else if ( reason )
|
|
894
|
+
{
|
|
895
|
+
populateRejectReason( reject, reason );
|
|
896
|
+
m_state.onEvent( "Message " + msgSeqNum.getString()
|
|
897
|
+
+ " Rejected: " + reason );
|
|
898
|
+
}
|
|
899
|
+
else
|
|
900
|
+
m_state.onEvent( "Message " + msgSeqNum.getString() + " Rejected" );
|
|
901
|
+
|
|
902
|
+
sendRaw( reject );
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
void Session::generateLogout( const std::string& text )
|
|
906
|
+
{
|
|
907
|
+
Message logout;
|
|
908
|
+
logout.getHeader().setField( MsgType( MsgType_Logout ) );
|
|
909
|
+
fill( logout.getHeader() );
|
|
910
|
+
if ( text.length() )
|
|
911
|
+
logout.setField( Text( text ) );
|
|
912
|
+
sendRaw( logout );
|
|
913
|
+
m_state.sentLogout( true );
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
void Session::populateRejectReason( Message& reject, int field,
|
|
917
|
+
const std::string& text )
|
|
918
|
+
{
|
|
919
|
+
MsgType msgType;
|
|
920
|
+
reject.getHeader().getField( msgType );
|
|
921
|
+
|
|
922
|
+
if ( msgType == MsgType_Reject
|
|
923
|
+
&& m_sessionID.getBeginString() >= FIX::BeginString_FIX42 )
|
|
924
|
+
{
|
|
925
|
+
reject.setField( RefTagID( field ) );
|
|
926
|
+
reject.setField( Text( text ) );
|
|
927
|
+
}
|
|
928
|
+
else
|
|
929
|
+
{
|
|
930
|
+
std::stringstream stream;
|
|
931
|
+
stream << text << " (" << field << ")";
|
|
932
|
+
reject.setField( Text( stream.str() ) );
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
void Session::populateRejectReason( Message& reject, const std::string& text )
|
|
937
|
+
{
|
|
938
|
+
reject.setField( Text( text ) );
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
bool Session::verify( const Message& msg, bool checkTooHigh,
|
|
942
|
+
bool checkTooLow )
|
|
943
|
+
{
|
|
944
|
+
const MsgType* pMsgType = 0;
|
|
945
|
+
const MsgSeqNum* pMsgSeqNum = 0;
|
|
946
|
+
|
|
947
|
+
try
|
|
948
|
+
{
|
|
949
|
+
const Header& header = msg.getHeader();
|
|
950
|
+
|
|
951
|
+
pMsgType = FIELD_GET_PTR( header, MsgType );
|
|
952
|
+
const SenderCompID& senderCompID = FIELD_GET_REF( header, SenderCompID );
|
|
953
|
+
const TargetCompID& targetCompID = FIELD_GET_REF( header, TargetCompID );
|
|
954
|
+
const SendingTime& sendingTime = FIELD_GET_REF( header, SendingTime );
|
|
955
|
+
|
|
956
|
+
if( checkTooHigh || checkTooLow )
|
|
957
|
+
pMsgSeqNum = FIELD_GET_PTR( header, MsgSeqNum );
|
|
958
|
+
|
|
959
|
+
if ( !validLogonState( *pMsgType ) )
|
|
960
|
+
throw std::logic_error( "Logon state is not valid for message" );
|
|
961
|
+
|
|
962
|
+
if ( !isGoodTime( sendingTime ) )
|
|
963
|
+
{
|
|
964
|
+
doBadTime( msg );
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
if ( !isCorrectCompID( senderCompID, targetCompID ) )
|
|
968
|
+
{
|
|
969
|
+
doBadCompID( msg );
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
if ( checkTooHigh && isTargetTooHigh( *pMsgSeqNum ) )
|
|
974
|
+
{
|
|
975
|
+
doTargetTooHigh( msg );
|
|
976
|
+
return false;
|
|
977
|
+
}
|
|
978
|
+
else if ( checkTooLow && isTargetTooLow( *pMsgSeqNum ) )
|
|
979
|
+
{
|
|
980
|
+
doTargetTooLow( msg );
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if ( (checkTooHigh || checkTooLow) && m_state.resendRequested() )
|
|
985
|
+
{
|
|
986
|
+
SessionState::ResendRange range = m_state.resendRange();
|
|
987
|
+
|
|
988
|
+
if ( *pMsgSeqNum >= range.second )
|
|
989
|
+
{
|
|
990
|
+
m_state.onEvent ("ResendRequest for messages FROM: " +
|
|
991
|
+
IntConvertor::convert (range.first) + " TO: " +
|
|
992
|
+
IntConvertor::convert (range.second) +
|
|
993
|
+
" has been satisfied.");
|
|
994
|
+
m_state.resendRange (0, 0);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
catch ( std::exception& e )
|
|
999
|
+
{
|
|
1000
|
+
m_state.onEvent( e.what() );
|
|
1001
|
+
disconnect();
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
UtcTimeStamp now;
|
|
1006
|
+
m_state.lastReceivedTime( now );
|
|
1007
|
+
m_state.testRequest( 0 );
|
|
1008
|
+
|
|
1009
|
+
fromCallback( pMsgType ? *pMsgType : MsgType(), msg, m_sessionID );
|
|
1010
|
+
return true;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
bool Session::shouldSendReset()
|
|
1014
|
+
{
|
|
1015
|
+
std::string beginString = m_sessionID.getBeginString();
|
|
1016
|
+
return beginString >= FIX::BeginString_FIX41
|
|
1017
|
+
&& ( m_resetOnLogon ||
|
|
1018
|
+
m_resetOnLogout ||
|
|
1019
|
+
m_resetOnDisconnect )
|
|
1020
|
+
&& ( getExpectedSenderNum() == 1 )
|
|
1021
|
+
&& ( getExpectedTargetNum() == 1 );
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
bool Session::validLogonState( const MsgType& msgType )
|
|
1025
|
+
{
|
|
1026
|
+
if ( (msgType == MsgType_Logon && m_state.sentReset())
|
|
1027
|
+
|| (m_state.receivedReset()) )
|
|
1028
|
+
return true;
|
|
1029
|
+
if ( (msgType == MsgType_Logon && !m_state.receivedLogon())
|
|
1030
|
+
|| (msgType != MsgType_Logon && m_state.receivedLogon()) )
|
|
1031
|
+
return true;
|
|
1032
|
+
if ( msgType == MsgType_Logout && m_state.sentLogon() )
|
|
1033
|
+
return true;
|
|
1034
|
+
if ( msgType != MsgType_Logout && m_state.sentLogout() )
|
|
1035
|
+
return true;
|
|
1036
|
+
if ( msgType == MsgType_SequenceReset )
|
|
1037
|
+
return true;
|
|
1038
|
+
if ( msgType == MsgType_Reject )
|
|
1039
|
+
return true;
|
|
1040
|
+
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
void Session::fromCallback( const MsgType& msgType, const Message& msg,
|
|
1045
|
+
const SessionID& sessionID )
|
|
1046
|
+
{
|
|
1047
|
+
if ( Message::isAdminMsgType( msgType ) )
|
|
1048
|
+
m_application.fromAdmin( msg, m_sessionID );
|
|
1049
|
+
else
|
|
1050
|
+
m_application.fromApp( msg, m_sessionID );
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
void Session::doBadTime( const Message& msg )
|
|
1054
|
+
{
|
|
1055
|
+
generateReject( msg, SessionRejectReason_SENDINGTIME_ACCURACY_PROBLEM );
|
|
1056
|
+
generateLogout();
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
void Session::doBadCompID( const Message& msg )
|
|
1060
|
+
{
|
|
1061
|
+
generateReject( msg, SessionRejectReason_COMPID_PROBLEM );
|
|
1062
|
+
generateLogout();
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
bool Session::doPossDup( const Message& msg )
|
|
1066
|
+
{
|
|
1067
|
+
const Header & header = msg.getHeader();
|
|
1068
|
+
OrigSendingTime origSendingTime;
|
|
1069
|
+
SendingTime sendingTime;
|
|
1070
|
+
MsgType msgType;
|
|
1071
|
+
|
|
1072
|
+
header.getField( msgType );
|
|
1073
|
+
header.getField( sendingTime );
|
|
1074
|
+
|
|
1075
|
+
if ( msgType != MsgType_SequenceReset )
|
|
1076
|
+
{
|
|
1077
|
+
if ( !header.getFieldIfSet( origSendingTime ) )
|
|
1078
|
+
{
|
|
1079
|
+
generateReject( msg, SessionRejectReason_REQUIRED_TAG_MISSING, origSendingTime.getField() );
|
|
1080
|
+
return false;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
if ( origSendingTime > sendingTime )
|
|
1084
|
+
{
|
|
1085
|
+
generateReject( msg, SessionRejectReason_SENDINGTIME_ACCURACY_PROBLEM );
|
|
1086
|
+
generateLogout();
|
|
1087
|
+
return false;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return true;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
bool Session::doTargetTooLow( const Message& msg )
|
|
1094
|
+
{
|
|
1095
|
+
const Header & header = msg.getHeader();
|
|
1096
|
+
PossDupFlag possDupFlag(false);
|
|
1097
|
+
MsgSeqNum msgSeqNum;
|
|
1098
|
+
header.getFieldIfSet(possDupFlag);
|
|
1099
|
+
header.getField( msgSeqNum );
|
|
1100
|
+
|
|
1101
|
+
if ( !possDupFlag )
|
|
1102
|
+
{
|
|
1103
|
+
std::stringstream stream;
|
|
1104
|
+
stream << "MsgSeqNum too low, expecting " << getExpectedTargetNum()
|
|
1105
|
+
<< " but received " << msgSeqNum;
|
|
1106
|
+
generateLogout( stream.str() );
|
|
1107
|
+
throw std::logic_error( stream.str() );
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
return doPossDup( msg );
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
void Session::doTargetTooHigh( const Message& msg )
|
|
1114
|
+
{
|
|
1115
|
+
const Header & header = msg.getHeader();
|
|
1116
|
+
BeginString beginString;
|
|
1117
|
+
MsgSeqNum msgSeqNum;
|
|
1118
|
+
header.getField( beginString );
|
|
1119
|
+
header.getField( msgSeqNum );
|
|
1120
|
+
|
|
1121
|
+
m_state.onEvent( "MsgSeqNum too high, expecting "
|
|
1122
|
+
+ IntConvertor::convert( getExpectedTargetNum() )
|
|
1123
|
+
+ " but received "
|
|
1124
|
+
+ IntConvertor::convert( msgSeqNum ) );
|
|
1125
|
+
|
|
1126
|
+
m_state.queue( msgSeqNum, msg );
|
|
1127
|
+
|
|
1128
|
+
if( m_state.resendRequested() )
|
|
1129
|
+
{
|
|
1130
|
+
SessionState::ResendRange range = m_state.resendRange();
|
|
1131
|
+
|
|
1132
|
+
if( !m_sendRedundantResendRequests && msgSeqNum >= range.first )
|
|
1133
|
+
{
|
|
1134
|
+
m_state.onEvent ("Already sent ResendRequest FROM: " +
|
|
1135
|
+
IntConvertor::convert (range.first) + " TO: " +
|
|
1136
|
+
IntConvertor::convert (range.second) +
|
|
1137
|
+
". Not sending another.");
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
generateResendRequest( beginString, msgSeqNum );
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
void Session::nextQueued( const UtcTimeStamp& timeStamp )
|
|
1146
|
+
{
|
|
1147
|
+
while ( nextQueued( getExpectedTargetNum(), timeStamp ) ) {}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
bool Session::nextQueued( int num, const UtcTimeStamp& timeStamp )
|
|
1151
|
+
{
|
|
1152
|
+
Message msg;
|
|
1153
|
+
MsgType msgType;
|
|
1154
|
+
|
|
1155
|
+
if( m_state.retrieve( num, msg ) )
|
|
1156
|
+
{
|
|
1157
|
+
m_state.onEvent( "Processing QUEUED message: "
|
|
1158
|
+
+ IntConvertor::convert( num ) );
|
|
1159
|
+
msg.getHeader().getField( msgType );
|
|
1160
|
+
if( msgType == MsgType_Logon
|
|
1161
|
+
|| msgType == MsgType_ResendRequest )
|
|
1162
|
+
{
|
|
1163
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
1164
|
+
}
|
|
1165
|
+
else
|
|
1166
|
+
{
|
|
1167
|
+
next( msg, timeStamp, true );
|
|
1168
|
+
}
|
|
1169
|
+
return true;
|
|
1170
|
+
}
|
|
1171
|
+
return false;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
void Session::next( const std::string& msg, const UtcTimeStamp& timeStamp, bool queued )
|
|
1175
|
+
{
|
|
1176
|
+
try
|
|
1177
|
+
{
|
|
1178
|
+
m_state.onIncoming( msg );
|
|
1179
|
+
const DataDictionary& sessionDD =
|
|
1180
|
+
m_dataDictionaryProvider.getSessionDataDictionary(m_sessionID.getBeginString());
|
|
1181
|
+
if( m_sessionID.isFIXT() )
|
|
1182
|
+
{
|
|
1183
|
+
const DataDictionary& applicationDD =
|
|
1184
|
+
m_dataDictionaryProvider.getApplicationDataDictionary(m_senderDefaultApplVerID);
|
|
1185
|
+
next( Message( msg, sessionDD, applicationDD, m_validateLengthAndChecksum ), timeStamp, queued );
|
|
1186
|
+
}
|
|
1187
|
+
else
|
|
1188
|
+
{
|
|
1189
|
+
next( Message( msg, sessionDD, m_validateLengthAndChecksum ), timeStamp, queued );
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
catch( InvalidMessage& e )
|
|
1193
|
+
{
|
|
1194
|
+
m_state.onEvent( e.what() );
|
|
1195
|
+
|
|
1196
|
+
try
|
|
1197
|
+
{
|
|
1198
|
+
if( identifyType(msg) == MsgType_Logon )
|
|
1199
|
+
{
|
|
1200
|
+
m_state.onEvent( "Logon message is not valid" );
|
|
1201
|
+
disconnect();
|
|
1202
|
+
}
|
|
1203
|
+
} catch( MessageParseError& ) {}
|
|
1204
|
+
throw e;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
void Session::next( const Message& message, const UtcTimeStamp& timeStamp, bool queued )
|
|
1209
|
+
{
|
|
1210
|
+
const Header& header = message.getHeader();
|
|
1211
|
+
|
|
1212
|
+
try
|
|
1213
|
+
{
|
|
1214
|
+
if ( !checkSessionTime(timeStamp) )
|
|
1215
|
+
{ reset(); return; }
|
|
1216
|
+
|
|
1217
|
+
const MsgType& msgType = FIELD_GET_REF( header, MsgType );
|
|
1218
|
+
const BeginString& beginString = FIELD_GET_REF( header, BeginString );
|
|
1219
|
+
// make sure these fields are present
|
|
1220
|
+
FIELD_THROW_IF_NOT_FOUND( header, SenderCompID );
|
|
1221
|
+
FIELD_THROW_IF_NOT_FOUND( header, TargetCompID );
|
|
1222
|
+
|
|
1223
|
+
if ( beginString != m_sessionID.getBeginString() )
|
|
1224
|
+
throw UnsupportedVersion();
|
|
1225
|
+
|
|
1226
|
+
if( msgType == MsgType_Logon )
|
|
1227
|
+
{
|
|
1228
|
+
if( m_sessionID.isFIXT() )
|
|
1229
|
+
{
|
|
1230
|
+
const DefaultApplVerID& applVerID = FIELD_GET_REF( message, DefaultApplVerID );
|
|
1231
|
+
setTargetDefaultApplVerID(applVerID);
|
|
1232
|
+
}
|
|
1233
|
+
else
|
|
1234
|
+
{
|
|
1235
|
+
setTargetDefaultApplVerID(Message::toApplVerID(beginString));
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
const DataDictionary& sessionDataDictionary =
|
|
1240
|
+
m_dataDictionaryProvider.getSessionDataDictionary(m_sessionID.getBeginString());
|
|
1241
|
+
|
|
1242
|
+
if( m_sessionID.isFIXT() && message.isApp() )
|
|
1243
|
+
{
|
|
1244
|
+
ApplVerID applVerID = m_targetDefaultApplVerID;
|
|
1245
|
+
header.getFieldIfSet(applVerID);
|
|
1246
|
+
const DataDictionary& applicationDataDictionary =
|
|
1247
|
+
m_dataDictionaryProvider.getApplicationDataDictionary(applVerID);
|
|
1248
|
+
DataDictionary::validate( message, &sessionDataDictionary, &applicationDataDictionary );
|
|
1249
|
+
}
|
|
1250
|
+
else
|
|
1251
|
+
{
|
|
1252
|
+
sessionDataDictionary.validate( message );
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
if ( msgType == MsgType_Logon )
|
|
1256
|
+
nextLogon( message, timeStamp );
|
|
1257
|
+
else if ( msgType == MsgType_Heartbeat )
|
|
1258
|
+
nextHeartbeat( message, timeStamp );
|
|
1259
|
+
else if ( msgType == MsgType_TestRequest )
|
|
1260
|
+
nextTestRequest( message, timeStamp );
|
|
1261
|
+
else if ( msgType == MsgType_SequenceReset )
|
|
1262
|
+
nextSequenceReset( message, timeStamp );
|
|
1263
|
+
else if ( msgType == MsgType_Logout )
|
|
1264
|
+
nextLogout( message, timeStamp );
|
|
1265
|
+
else if ( msgType == MsgType_ResendRequest )
|
|
1266
|
+
nextResendRequest( message,timeStamp );
|
|
1267
|
+
else if ( msgType == MsgType_Reject )
|
|
1268
|
+
nextReject( message, timeStamp );
|
|
1269
|
+
else
|
|
1270
|
+
{
|
|
1271
|
+
if ( !verify( message ) ) return ;
|
|
1272
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
catch ( MessageParseError& e )
|
|
1276
|
+
{ m_state.onEvent( e.what() ); }
|
|
1277
|
+
catch ( RequiredTagMissing & e )
|
|
1278
|
+
{ LOGEX( generateReject( message, SessionRejectReason_REQUIRED_TAG_MISSING, e.field ) ); }
|
|
1279
|
+
catch ( FieldNotFound & e )
|
|
1280
|
+
{
|
|
1281
|
+
if( header.getField(FIELD::BeginString) >= FIX::BeginString_FIX42 && message.isApp() )
|
|
1282
|
+
{
|
|
1283
|
+
LOGEX( generateBusinessReject( message, BusinessRejectReason_CONDITIONALLY_REQUIRED_FIELD_MISSING, e.field ) );
|
|
1284
|
+
}
|
|
1285
|
+
else
|
|
1286
|
+
{
|
|
1287
|
+
LOGEX( generateReject( message, SessionRejectReason_REQUIRED_TAG_MISSING, e.field ) );
|
|
1288
|
+
if ( header.getField(FIELD::MsgType) == MsgType_Logon )
|
|
1289
|
+
{
|
|
1290
|
+
m_state.onEvent( "Required field missing from logon" );
|
|
1291
|
+
disconnect();
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
catch ( InvalidTagNumber & e )
|
|
1296
|
+
{ LOGEX( generateReject( message, SessionRejectReason_INVALID_TAG_NUMBER, e.field ) ); }
|
|
1297
|
+
catch ( NoTagValue & e )
|
|
1298
|
+
{ LOGEX( generateReject( message, SessionRejectReason_TAG_SPECIFIED_WITHOUT_A_VALUE, e.field ) ); }
|
|
1299
|
+
catch ( TagNotDefinedForMessage & e )
|
|
1300
|
+
{ LOGEX( generateReject( message, SessionRejectReason_TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE, e.field ) ); }
|
|
1301
|
+
catch ( InvalidMessageType& )
|
|
1302
|
+
{ LOGEX( generateReject( message, SessionRejectReason_INVALID_MSGTYPE ) ); }
|
|
1303
|
+
catch ( UnsupportedMessageType& )
|
|
1304
|
+
{
|
|
1305
|
+
if ( header.getField(FIELD::BeginString) >= FIX::BeginString_FIX42 )
|
|
1306
|
+
{ LOGEX( generateBusinessReject( message, BusinessRejectReason_UNKNOWN_MESSAGE_TYPE ) ); }
|
|
1307
|
+
else
|
|
1308
|
+
{ LOGEX( generateReject( message, "Unsupported message type" ) ); }
|
|
1309
|
+
}
|
|
1310
|
+
catch ( TagOutOfOrder & e )
|
|
1311
|
+
{ LOGEX( generateReject( message, SessionRejectReason_TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER, e.field ) ); }
|
|
1312
|
+
catch ( IncorrectDataFormat & e )
|
|
1313
|
+
{ LOGEX( generateReject( message, SessionRejectReason_INCORRECT_DATA_FORMAT_FOR_VALUE, e.field ) ); }
|
|
1314
|
+
catch ( IncorrectTagValue & e )
|
|
1315
|
+
{ LOGEX( generateReject( message, SessionRejectReason_VALUE_IS_INCORRECT, e.field ) ); }
|
|
1316
|
+
catch ( RepeatedTag & e )
|
|
1317
|
+
{ LOGEX( generateReject( message, SessionRejectReason_TAG_APPEARS_MORE_THAN_ONCE, e.field ) ); }
|
|
1318
|
+
catch ( RepeatingGroupCountMismatch & e )
|
|
1319
|
+
{ LOGEX( generateReject( message, SessionRejectReason_INCORRECT_NUMINGROUP_COUNT_FOR_REPEATING_GROUP, e.field ) ); }
|
|
1320
|
+
catch ( InvalidMessage& e )
|
|
1321
|
+
{ m_state.onEvent( e.what() ); }
|
|
1322
|
+
catch ( RejectLogon& e )
|
|
1323
|
+
{
|
|
1324
|
+
m_state.onEvent( e.what() );
|
|
1325
|
+
generateLogout( e.what() );
|
|
1326
|
+
disconnect();
|
|
1327
|
+
}
|
|
1328
|
+
catch ( UnsupportedVersion& )
|
|
1329
|
+
{
|
|
1330
|
+
if ( header.getField(FIELD::MsgType) == MsgType_Logout )
|
|
1331
|
+
nextLogout( message, timeStamp );
|
|
1332
|
+
else
|
|
1333
|
+
{
|
|
1334
|
+
generateLogout( "Incorrect BeginString" );
|
|
1335
|
+
m_state.incrNextTargetMsgSeqNum();
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
catch ( IOException& e )
|
|
1339
|
+
{
|
|
1340
|
+
m_state.onEvent( e.what() );
|
|
1341
|
+
disconnect();
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
if( !queued )
|
|
1345
|
+
nextQueued( timeStamp );
|
|
1346
|
+
|
|
1347
|
+
if( isLoggedOn() )
|
|
1348
|
+
next();
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
bool Session::sendToTarget( Message& message, const std::string& qualifier )
|
|
1352
|
+
throw( SessionNotFound )
|
|
1353
|
+
{
|
|
1354
|
+
try
|
|
1355
|
+
{
|
|
1356
|
+
SessionID sessionID = message.getSessionID( qualifier );
|
|
1357
|
+
return sendToTarget( message, sessionID );
|
|
1358
|
+
}
|
|
1359
|
+
catch ( FieldNotFound& ) { throw SessionNotFound(); }
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
bool Session::sendToTarget( Message& message, const SessionID& sessionID )
|
|
1363
|
+
throw( SessionNotFound )
|
|
1364
|
+
{
|
|
1365
|
+
message.setSessionID( sessionID );
|
|
1366
|
+
Session* pSession = lookupSession( sessionID );
|
|
1367
|
+
if ( !pSession ) throw SessionNotFound();
|
|
1368
|
+
return pSession->send( message );
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
bool Session::sendToTarget
|
|
1372
|
+
( Message& message,
|
|
1373
|
+
const SenderCompID& senderCompID,
|
|
1374
|
+
const TargetCompID& targetCompID,
|
|
1375
|
+
const std::string& qualifier )
|
|
1376
|
+
throw( SessionNotFound )
|
|
1377
|
+
{
|
|
1378
|
+
message.getHeader().setField( senderCompID );
|
|
1379
|
+
message.getHeader().setField( targetCompID );
|
|
1380
|
+
return sendToTarget( message, qualifier );
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
bool Session::sendToTarget
|
|
1384
|
+
( Message& message, const std::string& sender, const std::string& target,
|
|
1385
|
+
const std::string& qualifier )
|
|
1386
|
+
throw( SessionNotFound )
|
|
1387
|
+
{
|
|
1388
|
+
return sendToTarget( message, SenderCompID( sender ),
|
|
1389
|
+
TargetCompID( target ), qualifier );
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
std::set<SessionID> Session::getSessions()
|
|
1393
|
+
{
|
|
1394
|
+
return s_sessionIDs;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
bool Session::doesSessionExist( const SessionID& sessionID )
|
|
1398
|
+
{
|
|
1399
|
+
Locker locker( s_mutex );
|
|
1400
|
+
return s_sessions.end() != s_sessions.find( sessionID );
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
Session* Session::lookupSession( const SessionID& sessionID )
|
|
1404
|
+
{
|
|
1405
|
+
Locker locker( s_mutex );
|
|
1406
|
+
Sessions::iterator find = s_sessions.find( sessionID );
|
|
1407
|
+
if ( find != s_sessions.end() )
|
|
1408
|
+
return find->second;
|
|
1409
|
+
else
|
|
1410
|
+
return 0;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
Session* Session::lookupSession( const std::string& string, bool reverse )
|
|
1414
|
+
{
|
|
1415
|
+
Message message;
|
|
1416
|
+
if ( !message.setStringHeader( string ) )
|
|
1417
|
+
return 0;
|
|
1418
|
+
|
|
1419
|
+
try
|
|
1420
|
+
{
|
|
1421
|
+
const Header& header = message.getHeader();
|
|
1422
|
+
const BeginString& beginString = FIELD_GET_REF( header, BeginString );
|
|
1423
|
+
const SenderCompID& senderCompID = FIELD_GET_REF( header, SenderCompID );
|
|
1424
|
+
const TargetCompID& targetCompID = FIELD_GET_REF( header, TargetCompID );
|
|
1425
|
+
|
|
1426
|
+
if ( reverse )
|
|
1427
|
+
{
|
|
1428
|
+
return lookupSession( SessionID( beginString, SenderCompID( targetCompID ),
|
|
1429
|
+
TargetCompID( senderCompID ) ) );
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
return lookupSession( SessionID( beginString, senderCompID,
|
|
1433
|
+
targetCompID ) );
|
|
1434
|
+
}
|
|
1435
|
+
catch ( FieldNotFound& ) { return 0; }
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
bool Session::isSessionRegistered( const SessionID& sessionID )
|
|
1439
|
+
{
|
|
1440
|
+
Locker locker( s_mutex );
|
|
1441
|
+
return s_registered.end() != s_registered.find( sessionID );
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
Session* Session::registerSession( const SessionID& sessionID )
|
|
1445
|
+
{
|
|
1446
|
+
Locker locker( s_mutex );
|
|
1447
|
+
Session* pSession = lookupSession( sessionID );
|
|
1448
|
+
if ( pSession == 0 ) return 0;
|
|
1449
|
+
if ( isSessionRegistered( sessionID ) ) return 0;
|
|
1450
|
+
s_registered[ sessionID ] = pSession;
|
|
1451
|
+
return pSession;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
void Session::unregisterSession( const SessionID& sessionID )
|
|
1455
|
+
{
|
|
1456
|
+
Locker locker( s_mutex );
|
|
1457
|
+
s_registered.erase( sessionID );
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
size_t Session::numSessions()
|
|
1461
|
+
{
|
|
1462
|
+
Locker locker( s_mutex );
|
|
1463
|
+
return s_sessions.size();
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
bool Session::addSession( Session& s )
|
|
1467
|
+
{
|
|
1468
|
+
Locker locker( s_mutex );
|
|
1469
|
+
Sessions::iterator it = s_sessions.find( s.m_sessionID );
|
|
1470
|
+
if ( it == s_sessions.end() )
|
|
1471
|
+
{
|
|
1472
|
+
s_sessions[ s.m_sessionID ] = &s;
|
|
1473
|
+
s_sessionIDs.insert( s.m_sessionID );
|
|
1474
|
+
return true;
|
|
1475
|
+
}
|
|
1476
|
+
else
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
void Session::removeSession( Session& s )
|
|
1481
|
+
{
|
|
1482
|
+
Locker locker( s_mutex );
|
|
1483
|
+
s_sessions.erase( s.m_sessionID );
|
|
1484
|
+
s_sessionIDs.erase( s.m_sessionID );
|
|
1485
|
+
s_registered.erase( s.m_sessionID );
|
|
1486
|
+
}
|
|
1487
|
+
}
|