Skip to content

Commit

Permalink
Allow HeartBtInt=0, which is valid
Browse files Browse the repository at this point in the history
  • Loading branch information
gbirchmeier committed Jun 12, 2020
1 parent 01c6838 commit 2d3b99a
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 24 deletions.
23 changes: 17 additions & 6 deletions QuickFIXn/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,20 @@ public TimeStampPrecision TimeStampPrecision

#endregion

/// <summary>
/// Don't use this. It decides the connection is an initiator if heartBtInt=0,
/// which is bad because 0 is actually a valid (though not-often-used) setting.
/// </summary>
[System.Obsolete("Use the constructor that takes the isInitiator parameter.")]
public Session(
IApplication app, IMessageStoreFactory storeFactory, SessionID sessID, DataDictionaryProvider dataDictProvider,
SessionSchedule sessionSchedule, int heartBtInt, ILogFactory logFactory, IMessageFactory msgFactory, string senderDefaultApplVerID)
: this(0 == heartBtInt, app, storeFactory, sessID, dataDictProvider, sessionSchedule, heartBtInt, logFactory, msgFactory, senderDefaultApplVerID)
{ }

public Session(
bool isInitiator, IApplication app, IMessageStoreFactory storeFactory, SessionID sessID, DataDictionaryProvider dataDictProvider,
SessionSchedule sessionSchedule, int heartBtInt, ILogFactory logFactory, IMessageFactory msgFactory, string senderDefaultApplVerID)
{
this.Application = app;
this.SessionID = sessID;
Expand All @@ -265,7 +276,7 @@ public Session(
else
log = new NullLog();

state_ = new SessionState(log, heartBtInt)
state_ = new SessionState(isInitiator, log, heartBtInt)
{
MessageStore = storeFactory.Create(sessID)
};
Expand Down Expand Up @@ -462,10 +473,10 @@ public void Next()

if (!IsSessionTime)
{
if(IsInitiator==false)
Reset("Out of SessionTime (Session.Next())", "Message received outside of session time");
else
if(IsInitiator)
Reset("Out of SessionTime (Session.Next())");
else
Reset("Out of SessionTime (Session.Next())", "Message received outside of session time");
return;
}

Expand Down Expand Up @@ -720,7 +731,7 @@ protected void NextLogon(Message logon)
}
}

if (!state_.IsInitiator && this.ResetOnLogon)
if (IsAcceptor && this.ResetOnLogon)
state_.Reset("ResetOnLogon");
if (this.RefreshOnLogon)
Refresh();
Expand All @@ -737,7 +748,7 @@ protected void NextLogon(Message logon)

state_.ReceivedLogon = true;
this.Log.OnEvent("Received logon");
if (!state_.IsInitiator)
if (IsAcceptor)
{
int heartBtInt = logon.GetInt(Fields.Tags.HeartBtInt);
state_.HeartBtInt = heartBtInt;
Expand Down
25 changes: 17 additions & 8 deletions QuickFIXn/SessionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,21 @@ public SessionFactory(IApplication app, IMessageStoreFactory storeFactory, ILogF
System.Console.WriteLine("[SessionFactory] " + messageFactory_.GetType().FullName);
}

static private bool DetectIfInitiator(QuickFix.Dictionary settings)
{
switch (settings.GetString(SessionSettings.CONNECTION_TYPE))
{
case "acceptor": return false;
case "initiator": return true;
}
throw new ConfigError("Invalid ConnectionType");
}

public Session Create(SessionID sessionID, QuickFix.Dictionary settings)
{
string connectionType = settings.GetString(SessionSettings.CONNECTION_TYPE);
if (!"acceptor".Equals(connectionType) && !"initiator".Equals(connectionType))
throw new ConfigError("Invalid ConnectionType");
bool isInitiator = SessionFactory.DetectIfInitiator(settings);

if ("acceptor".Equals(connectionType) && settings.Has(SessionSettings.SESSION_QUALIFIER))
if (!isInitiator && settings.Has(SessionSettings.SESSION_QUALIFIER))
throw new ConfigError("SessionQualifier cannot be used with acceptor.");

bool useDataDictionary = true;
Expand Down Expand Up @@ -83,17 +91,18 @@ public Session Create(SessionID sessionID, QuickFix.Dictionary settings)
}

int heartBtInt = 0;
if ( connectionType == "initiator" )
if (isInitiator)
{
heartBtInt = System.Convert.ToInt32(settings.GetLong( SessionSettings.HEARTBTINT ));
if ( heartBtInt <= 0 )
throw new ConfigError( "Heartbeat must be greater than zero" );
heartBtInt = System.Convert.ToInt32(settings.GetLong(SessionSettings.HEARTBTINT));
if (heartBtInt < 0)
throw new ConfigError($"{SessionSettings.HEARTBTINT} must be greater or equal to zero");
}
string senderDefaultApplVerId = "";
if(defaultApplVerID != null)
senderDefaultApplVerId = defaultApplVerID.Obj;

Session session = new Session(
isInitiator,
application_,
messageStoreFactory_,
sessionID,
Expand Down
11 changes: 10 additions & 1 deletion QuickFIXn/SessionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,20 @@ private Dictionary<int, Message> MsgQueue

#endregion

/// <summary>
/// Don't use this. It decides the connection is an initiator if heartBtInt=0,
/// which is bad because 0 is actually a valid (though not-often-used) setting.
/// </summary>
[System.Obsolete("Use the constructor that takes the isInitiator parameter.")]
public SessionState(ILog log, int heartBtInt)
: this(0 != heartBtInt, log, heartBtInt)
{ }

public SessionState(bool isInitiator, ILog log, int heartBtInt)
{
log_ = log;
this.HeartBtInt = heartBtInt;
this.IsInitiator = (0 != heartBtInt);
this.IsInitiator = isInitiator;
lastReceivedTimeDT_ = DateTime.UtcNow;
lastSentTimeDT_ = DateTime.UtcNow;
}
Expand Down
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ What's New
* (patch) #606 - fix IDisposable implementations to follow MS general pattern (pavka1799)
* (patch) #566 - SSLValidateCertificates=N overrides SSLCheckCertificateRevocation (gbirchmeier, h/t to Mad-Lynx)
* (patch) #405 - CheckFieldsHaveValues needs to work for non-strings too (gbirchmeier)
* (minor) #596 - Support HeartBtInt=0 (gbirchmeier)

### v1.9.0:
* (minor) #469 - Add support for NET Standard 2.0 (jhickson)
Expand Down
2 changes: 1 addition & 1 deletion UnitTests/SessionStateTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public void ThreadSafeSetAndGet() {
NullLog log = new NullLog();

//Set up sessionstate
SessionState state = new SessionState(log, 1) {MessageStore = store};
SessionState state = new SessionState(true, log, 1) {MessageStore = store};

Hashtable errorsTable = Hashtable.Synchronized(new Hashtable());//used in more than 1 thread at a time
Hashtable setTable = new Hashtable(1000);//only used in 1 thread at a time
Expand Down
15 changes: 7 additions & 8 deletions UnitTests/SessionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public class SessionTest
Regex microsecondRegex = new Regex(@"\.[\d]{1,6}$");

[SetUp]
public void setup()
public void Setup()
{
responder = new MockResponder();
sessionID = new QuickFix.SessionID("FIX.4.2", "SENDER", "TARGET");
Expand All @@ -192,16 +192,15 @@ public void setup()
config.SetString(QuickFix.SessionSettings.END_TIME, "00:00:00");
settings.Set(sessionID, config);

session = new QuickFix.Session(application, new QuickFix.MemoryStoreFactory(), sessionID,
// acceptor
session = new QuickFix.Session(false, application, new QuickFix.MemoryStoreFactory(), sessionID,
new QuickFix.DataDictionaryProvider(),new QuickFix.SessionSchedule(config), 0, new QuickFix.ScreenLogFactory(settings), new QuickFix.DefaultMessageFactory(), "blah");
session.SetResponder(responder);
session.CheckLatency = false;

// must be set for an initiator
int heartBeatInterval = 10;

session2 = new QuickFix.Session(application, new QuickFix.MemoryStoreFactory(), new QuickFix.SessionID("FIX.4.2", "OTHER_SENDER", "OTHER_TARGET"),
new QuickFix.DataDictionaryProvider(), new QuickFix.SessionSchedule(config), heartBeatInterval, new QuickFix.ScreenLogFactory(settings), new QuickFix.DefaultMessageFactory(), "blah");
// initiator
session2 = new QuickFix.Session(true, application, new QuickFix.MemoryStoreFactory(), new QuickFix.SessionID("FIX.4.2", "OTHER_SENDER", "OTHER_TARGET"),
new QuickFix.DataDictionaryProvider(), new QuickFix.SessionSchedule(config), 0, new QuickFix.ScreenLogFactory(settings), new QuickFix.DefaultMessageFactory(), "blah");
session2.SetResponder(responder);
session2.CheckLatency = false;

Expand Down Expand Up @@ -916,7 +915,7 @@ public void TestToAppResendDoNotSend()
public void TestApplicationExtension()
{
var mockApp = new MockApplicationExt();
session = new QuickFix.Session(mockApp, new QuickFix.MemoryStoreFactory(), sessionID,
session = new QuickFix.Session(true, mockApp, new QuickFix.MemoryStoreFactory(), sessionID,
new QuickFix.DataDictionaryProvider(), new QuickFix.SessionSchedule(config), 0, new QuickFix.ScreenLogFactory(settings), new QuickFix.DefaultMessageFactory(), "blah");
session.SetResponder(responder);
session.CheckLatency = false;
Expand Down

0 comments on commit 2d3b99a

Please sign in to comment.