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.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/ext/quickfix/Acceptor.cpp +248 -0
  3. data/ext/quickfix/Acceptor.h +127 -0
  4. data/ext/quickfix/Allocator.h +9 -0
  5. data/ext/quickfix/Application.h +127 -0
  6. data/ext/quickfix/AtomicCount.h +109 -0
  7. data/ext/quickfix/DOMDocument.h +74 -0
  8. data/ext/quickfix/DataDictionary.cpp +618 -0
  9. data/ext/quickfix/DataDictionary.h +539 -0
  10. data/ext/quickfix/DataDictionaryProvider.cpp +71 -0
  11. data/ext/quickfix/DataDictionaryProvider.h +70 -0
  12. data/ext/quickfix/DatabaseConnectionID.h +105 -0
  13. data/ext/quickfix/DatabaseConnectionPool.h +91 -0
  14. data/ext/quickfix/Dictionary.cpp +162 -0
  15. data/ext/quickfix/Dictionary.h +94 -0
  16. data/ext/quickfix/Event.h +95 -0
  17. data/ext/quickfix/Exceptions.h +299 -0
  18. data/ext/quickfix/Field.h +672 -0
  19. data/ext/quickfix/FieldConvertors.h +863 -0
  20. data/ext/quickfix/FieldMap.cpp +238 -0
  21. data/ext/quickfix/FieldMap.h +244 -0
  22. data/ext/quickfix/FieldNumbers.h +46 -0
  23. data/ext/quickfix/FieldTypes.cpp +64 -0
  24. data/ext/quickfix/FieldTypes.h +698 -0
  25. data/ext/quickfix/Fields.h +31 -0
  26. data/ext/quickfix/FileLog.cpp +200 -0
  27. data/ext/quickfix/FileLog.h +112 -0
  28. data/ext/quickfix/FileStore.cpp +332 -0
  29. data/ext/quickfix/FileStore.h +129 -0
  30. data/ext/quickfix/FixFieldNumbers.h +1537 -0
  31. data/ext/quickfix/FixFields.h +1538 -0
  32. data/ext/quickfix/FixValues.h +3281 -0
  33. data/ext/quickfix/FlexLexer.h +188 -0
  34. data/ext/quickfix/Group.cpp +64 -0
  35. data/ext/quickfix/Group.h +73 -0
  36. data/ext/quickfix/HtmlBuilder.h +186 -0
  37. data/ext/quickfix/HttpConnection.cpp +739 -0
  38. data/ext/quickfix/HttpConnection.h +78 -0
  39. data/ext/quickfix/HttpMessage.cpp +149 -0
  40. data/ext/quickfix/HttpMessage.h +133 -0
  41. data/ext/quickfix/HttpParser.cpp +49 -0
  42. data/ext/quickfix/HttpParser.h +54 -0
  43. data/ext/quickfix/HttpServer.cpp +169 -0
  44. data/ext/quickfix/HttpServer.h +78 -0
  45. data/ext/quickfix/Initiator.cpp +289 -0
  46. data/ext/quickfix/Initiator.h +149 -0
  47. data/ext/quickfix/Log.cpp +77 -0
  48. data/ext/quickfix/Log.h +179 -0
  49. data/ext/quickfix/Message.cpp +580 -0
  50. data/ext/quickfix/Message.h +370 -0
  51. data/ext/quickfix/MessageCracker.h +188 -0
  52. data/ext/quickfix/MessageSorters.cpp +105 -0
  53. data/ext/quickfix/MessageSorters.h +156 -0
  54. data/ext/quickfix/MessageStore.cpp +146 -0
  55. data/ext/quickfix/MessageStore.h +174 -0
  56. data/ext/quickfix/Mutex.h +131 -0
  57. data/ext/quickfix/MySQLConnection.h +194 -0
  58. data/ext/quickfix/MySQLLog.cpp +275 -0
  59. data/ext/quickfix/MySQLLog.h +145 -0
  60. data/ext/quickfix/MySQLStore.cpp +331 -0
  61. data/ext/quickfix/MySQLStore.h +142 -0
  62. data/ext/quickfix/NullStore.cpp +54 -0
  63. data/ext/quickfix/NullStore.h +99 -0
  64. data/ext/quickfix/OdbcConnection.h +266 -0
  65. data/ext/quickfix/OdbcLog.cpp +252 -0
  66. data/ext/quickfix/OdbcLog.h +117 -0
  67. data/ext/quickfix/OdbcStore.cpp +338 -0
  68. data/ext/quickfix/OdbcStore.h +113 -0
  69. data/ext/quickfix/PUGIXML_DOMDocument.cpp +112 -0
  70. data/ext/quickfix/PUGIXML_DOMDocument.h +81 -0
  71. data/ext/quickfix/Parser.cpp +103 -0
  72. data/ext/quickfix/Parser.h +57 -0
  73. data/ext/quickfix/PostgreSQLConnection.h +176 -0
  74. data/ext/quickfix/PostgreSQLLog.cpp +276 -0
  75. data/ext/quickfix/PostgreSQLLog.h +144 -0
  76. data/ext/quickfix/PostgreSQLStore.cpp +334 -0
  77. data/ext/quickfix/PostgreSQLStore.h +141 -0
  78. data/ext/quickfix/Queue.h +75 -0
  79. data/ext/quickfix/QuickfixRuby.cpp +252066 -0
  80. data/ext/quickfix/QuickfixRuby.h +34 -0
  81. data/ext/quickfix/Responder.h +43 -0
  82. data/ext/quickfix/Session.cpp +1487 -0
  83. data/ext/quickfix/Session.h +335 -0
  84. data/ext/quickfix/SessionFactory.cpp +274 -0
  85. data/ext/quickfix/SessionFactory.h +86 -0
  86. data/ext/quickfix/SessionID.h +170 -0
  87. data/ext/quickfix/SessionSettings.cpp +189 -0
  88. data/ext/quickfix/SessionSettings.h +171 -0
  89. data/ext/quickfix/SessionState.h +231 -0
  90. data/ext/quickfix/Settings.cpp +100 -0
  91. data/ext/quickfix/Settings.h +53 -0
  92. data/ext/quickfix/SharedArray.h +150 -0
  93. data/ext/quickfix/SocketAcceptor.cpp +222 -0
  94. data/ext/quickfix/SocketAcceptor.h +75 -0
  95. data/ext/quickfix/SocketConnection.cpp +238 -0
  96. data/ext/quickfix/SocketConnection.h +103 -0
  97. data/ext/quickfix/SocketConnector.cpp +116 -0
  98. data/ext/quickfix/SocketConnector.h +67 -0
  99. data/ext/quickfix/SocketInitiator.cpp +260 -0
  100. data/ext/quickfix/SocketInitiator.h +81 -0
  101. data/ext/quickfix/SocketMonitor.cpp +335 -0
  102. data/ext/quickfix/SocketMonitor.h +111 -0
  103. data/ext/quickfix/SocketServer.cpp +177 -0
  104. data/ext/quickfix/SocketServer.h +100 -0
  105. data/ext/quickfix/ThreadedSocketAcceptor.cpp +258 -0
  106. data/ext/quickfix/ThreadedSocketAcceptor.h +98 -0
  107. data/ext/quickfix/ThreadedSocketConnection.cpp +209 -0
  108. data/ext/quickfix/ThreadedSocketConnection.h +82 -0
  109. data/ext/quickfix/ThreadedSocketInitiator.cpp +268 -0
  110. data/ext/quickfix/ThreadedSocketInitiator.h +84 -0
  111. data/ext/quickfix/TimeRange.cpp +173 -0
  112. data/ext/quickfix/TimeRange.h +258 -0
  113. data/ext/quickfix/Utility.cpp +537 -0
  114. data/ext/quickfix/Utility.h +219 -0
  115. data/ext/quickfix/Values.h +62 -0
  116. data/ext/quickfix/config.h +0 -0
  117. data/ext/quickfix/config_windows.h +0 -0
  118. data/ext/quickfix/extconf.rb +12 -0
  119. data/ext/quickfix/index.h +37 -0
  120. data/ext/quickfix/pugiconfig.hpp +72 -0
  121. data/ext/quickfix/pugixml.cpp +10765 -0
  122. data/ext/quickfix/pugixml.hpp +1341 -0
  123. data/ext/quickfix/strptime.h +7 -0
  124. data/lib/quickfix40.rb +274 -0
  125. data/lib/quickfix41.rb +351 -0
  126. data/lib/quickfix42.rb +1184 -0
  127. data/lib/quickfix43.rb +3504 -0
  128. data/lib/quickfix44.rb +10721 -0
  129. data/lib/quickfix50.rb +13426 -0
  130. data/lib/quickfix50sp1.rb +15629 -0
  131. data/lib/quickfix50sp2.rb +17068 -0
  132. data/lib/quickfix_fields.rb +19853 -0
  133. data/lib/quickfix_ruby.rb +82 -0
  134. data/lib/quickfixt11.rb +70 -0
  135. data/spec/FIX40.xml +862 -0
  136. data/spec/FIX41.xml +1285 -0
  137. data/spec/FIX42.xml +2746 -0
  138. data/spec/FIX43.xml +4229 -0
  139. data/spec/FIX44.xml +6596 -0
  140. data/spec/FIX50.xml +8137 -0
  141. data/spec/FIX50SP1.xml +9496 -0
  142. data/spec/FIX50SP2.xml +10011 -0
  143. data/spec/FIXT11.xml +313 -0
  144. data/test/test_DataDictionaryTestCase.rb +268 -0
  145. data/test/test_DictionaryTestCase.rb +112 -0
  146. data/test/test_FieldBaseTestCase.rb +24 -0
  147. data/test/test_MessageTestCase.rb +368 -0
  148. data/test/test_SessionSettingsTestCase.rb +41 -0
  149. 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
+ }