I need to implement an acceptor using QuickFix/n. The way to create and run an acceptor is as follows:
public FixAcceptorManager(FixOptions options,ILogFactory logFactory,IApplication acceptor,SessionSettings sessionSettings)
{
_options = options;
_acceptor = acceptor;
_logFactory = logFactory;
_settings = sessionSettings;
_soketAcceptor = CreateSocketAcceptor();
_server = new HttpServer(_options.Url, _settings);
_isRunning = false;
}
private ThreadedSocketAcceptor CreateAcceptor()
{
var storeFactory = new FileStoreFactory(_settings);
var threadSocketAcceptor = new ThreadedSocketAcceptor(_acceptor, storeFactory, _settings, _logFactory);
return threadSocketAcceptor;
}
public void StartAcceptor()
{
if (_soketAcceptor is not null && !_isRunning)
{
_soketAcceptor.Start();
_server.Start();
_isRunning = true;
}
}
I create sessions dynamically as follows:
public void AddSession(string targetCompId, string password)
{
var dictionarySettings = new Dictionary();
dictionarySettings.SetString("Password", password);
var sessionId = new SessionID("FIXT.1.1", "TEST", targetCompId);
_soketAcceptor.AddSession(sessionId, dictionarySettings);
}
Everything starts, sessions are added. Active sessions are displayed on the panel. I also created a simple initiator for the test:
SessionSettings settings = new SessionSettings(file);
MyClientApp application = new MyClientApp();
IMessageStoreFactory storeFactory = new FileStoreFactory(settings);
ILogFactory logFactory = new ScreenLogFactory(settings);
SocketInitiator initiator = new SocketInitiator(application, storeFactory, settings, logFactory);
application.MyInitiator = initiator;
initiator.Start();
Console.ReadLine();
initiator.Stop();
The initiator connects to the acceptor, Logon is successful.
The acceptor has the following configuration:
[DEFAULT]
BeginString=FIXT.1.1
DefaultApplVerID=FIX.5.0SP2
HeartBtInt=20
AppDataDictionary=FIXRTv1.xml
TransportDataDictionary=FIXT11.xml
#EncryptMethod = 6
FileLogPath=log
SocketAcceptPort=9823
ConnectionType=acceptor
UseDataDictionary=Y
ResetOnLogon=Y
ResetOnLogout=Y
ResetOnDisconnect=Y
#ValidateUserDefinedFields = N
SenderCompID=MyAcceptor
StartTime=00:00:00
EndTime=23:59:00
FileStorePath=store
#AllowUnknownMsgFields = Y
And the initiator configuration:
[DEFAULT]
BeginString=FIXT.1.1
DefaultApplVerID=FIX.5.0SP2
ConnectionType=initiator
HeartBtInt=20
AppDataDictionary=FIXRTv1.xml
TransportDataDictionary=FIXT11.xml
UseDataDictionary=Y
ResetOnLogon=Y
ResetOnLogout=Y
ResetOnDisconnect=Y
FileStorePath=store
FileLogPath=log
ValidateUserDefinedFields = N
EncryptMethod = 6
[SESSION]
SenderCompID=MyInitiator
TargetCompID=MyAcceptor
Password=testtest
SocketConnectHost=127.0.0.1
SocketConnectPort=9823
StartTime=00:00:00
EndTime=23:59:00
I pass a Password to the acceptor to set up a new session. This Password is different from the one defined in the initiator configuration.
Then I start the initiator. And it connects with its own password. Although the password the acceptor expects from this initiator is different. Moreover, in the FromAdmin method of the acceptor I can't see the Password field in any way. I also tried to use Crack:
public void FromAdmin(Message message, SessionID sessionID)
{
Crack(message, sessionID);
}
public void OnMessage(QuickFix.FIXT11.Logon logon, SessionID s)
{
try
{
var p = logon.GetString(554); // Password field in FIXT11.xml tag = 554
}
catch (Exception)
{
}
}
Attempting to remove Password from the message results in an exception. Also in Debug mode in VisualStudio, when hovering over a message for the Password field, I see the following message:
"((QuickFix.FIXT11.Logon)message).Password" threw an exception like "QuickFix.FieldNotFoundException"
The FIXRTv1.xml and FIXT11.xml files are the same. The Logon message section looks like this:
<message msgcat='admin' msgtype='A' name='Logon'>
<field name='EncryptMethod' required='Y'/>
<field name='HeartBtInt' required='Y'/>
<field name='RawDataLength' required='N'/>
<field name='RawData' required='N'/>
<field name='ResetSeqNumFlag' required='N'/>
<field name='NextExpectedMsgSeqNum' required='N'/>
<field name='MaxMessageSize' required='N'/>
<field name='TestMessageIndicator' required='N'/>
<field name='Username' required='N'/>
<field name='Password' required='N'/>
<field name='NewPassword' required='N' />
<field name='DefaultApplVerID' required='N'/>
<component name='MsgTypeGrp' required='N'/>
</message>
Could you please tell me what I am doing wrong? I need to extract the Password field in the acceptor, validate and reject the initiator's Logon if the passwords do not match.
You have a lot going on in this question, so I'll try to break it up:
"Password" is not a QF/n config setting
This page shows the list of supported settings. "Password" isn't one of them. Your app is ignoring it.
Likewise, your dictionarySettings.SetString("Password", password);
line is also doing nothing.
Let's focus on the initiator-- do you see a password in its outbound Logon message?
And by "log", I mean the raw message transmissions log. I see you are using a ScreenLogFactory; I suggest you switch over to a FileLogFactory. After you run the initiator, look in the message log and find the 35=A outbound logon message. Does you see a password 554=xxx field?
I suspect you aren't seeing it, because you aren't actually setting it (as described above).
Try doing it via the ToAdmin callback instead:
public void ToAdmin(Message msg, SessionID sessionID) {
if (msg.Header.GetString(Tags.MsgType) == "A") {
msg.SetField(new Password("mypassword");
}
}
Now you should see, in your logs, that the Initiator is sending a password.
One last bit: You should check for the password's presence before reading it
Like this:
if (login.IsSetField(554)) {
var p = logon.GetString(554);
}
Give all of that a try, and see how it goes.