OnixS C++ FIX Engine  4.10.1
API Documentation
Accepting FIX Session Without a Prior Creation of Session Object

Sometimes there is a requirement to accept an incoming FIX session 'on the fly', without the prior creation of the OnixS::FIX::Session object. This often happens when an unknown session-initiator is trying to connect to the Engine. For this reason, OnixS C++ FIX Engine exposes an ability to accept such a connection by creating a temporary session-acceptor and to respond to the counterparty. To take advantage of this feature, it is necessary to inherit from the OnixS::FIX::IEngineListener class, to overwrite the OnixS::FIX::IEngineListener::onUnknownIncomingConnection method, and register instance of inherited listener with the OnixS::FIX::Engine instance, using the OnixS::FIX::Engine::registerListener method.

To accept the incoming connection, create the new OnixS::FIX::Session object, and call the OnixS::FIX::Session::logonAsAcceptor method to establish the connection. The required OnixS::FIX::Session constructor parameters can be filled from the incomingLogon message.

To decline the incoming connection, no action is needed. One thing, that you can do, is to set the rejectReason parameter and the Engine will use it as a text in the logout message.

Also, there is an ability to validate an incoming FIX connection even if the corresponding acceptor session is present. It can be done in the OnixS::FIX::IEngineListener::onIncomingConnection callback that is called when an incoming logon message is received but before the corresponding acceptor session is found. To decline the incoming connection, you need to set the rejectReason parameter, and the Engine will use it as a text in the logout message.

Additionally, there is an ability to validate incoming TCP connections before receiving any messages to reject unwanted ones by IP address and port. It can be done in the OnixS::FIX::IEngineListener::onIncomingTelecommunicationLink callback that is called when an incoming TCP connection is detected. To decline the incoming TCP connection, you need to set the rejectReason parameter, and the Engine will reject it.

Example

using namespace OnixS::FIX;
using namespace OnixS::FIX::FIX42;
struct AcceptorBehavior
{
enum Enum
{
AcceptConnection,
RejectInOnUnknownIncomingConnection,
RejectInOnIncomingConnection,
RejectInOnIncomingTelecommunicationLink,
};
};
class UnknownSessionAcceptor : public IEngineListener, public ISessionListener
{
public:
UnknownSessionAcceptor(AcceptorBehavior::Enum acceptorBehavior, const std::string & rejectReason)
: acceptorBehavior_(acceptorBehavior)
, rejectReason_(rejectReason)
, session_(ONIXS_FIXENGINE_NULLPTR)
{
}
virtual ~UnknownSessionAcceptor()
{
delete session_;
}
void onUnknownIncomingConnection(const FlatMessage & incomingLogon, const int /*listenPort*/, const int /*counterpartyPort*/, const std::string & /*counterpartyIpAddress*/, std::string * rejectReason) ONIXS_FIXENGINE_OVERRIDE
{
if(acceptorBehavior_ == AcceptorBehavior::AcceptConnection)
{
const FlatFieldRef TargetCompIdRef = incomingLogon.find(Tags::TargetCompID);
const FlatFieldRef SenderCompIdRef = incomingLogon.find(Tags::SenderCompID);
const std::string TargetCompId(incomingLogon[TargetCompIdRef].data(), incomingLogon[TargetCompIdRef].size());
const std::string SenderCompId(incomingLogon[SenderCompIdRef].data(), incomingLogon[SenderCompIdRef].size());
session_ = new Session(TargetCompId, SenderCompId, incomingLogon.version(), this);
session_->logonAsAcceptor();
}
else if(acceptorBehavior_ == AcceptorBehavior::RejectInOnUnknownIncomingConnection)
{
// Once the session is rejected, the Engine will send the logout message.
// The Engine will use the reject reason as a text in the logout message.
if(!rejectReason_.empty())
*rejectReason = rejectReason_;
}
}
void onIncomingConnection(const FlatMessage & /*incomingLogon*/, const int /*listenPort*/, const int /*counterpartyPort*/, const std::string & /*counterpartyIpAddress*/, std::string * rejectReason) ONIXS_FIXENGINE_OVERRIDE
{
if(acceptorBehavior_ == AcceptorBehavior::AcceptConnection)
{
// No actions are needed to accept the FIX connection.
}
else if(acceptorBehavior_ == AcceptorBehavior::RejectInOnIncomingConnection)
{
// Once the session is rejected, the Engine will send the logout message.
// The Engine will use the reject reason as a text in the logout message.
if(!rejectReason_.empty())
*rejectReason = rejectReason_;
}
}
void onIncomingTelecommunicationLink(const int /*listenPort*/, const int /*counterpartyPort*/, const std::string & /*counterpartyIpAddress*/, std::string * rejectReason) ONIXS_FIXENGINE_OVERRIDE
{
if(acceptorBehavior_ == AcceptorBehavior::AcceptConnection)
{
// No actions are needed to accept the TCP connection.
}
else if(acceptorBehavior_ == AcceptorBehavior::RejectInOnIncomingTelecommunicationLink)
{
// Once the TCP connection is rejected, the Engine will close it.
if(!rejectReason_.empty())
*rejectReason = rejectReason_;
}
}
void onInboundApplicationMsg(Message&, Session*) ONIXS_FIXENGINE_OVERRIDE
{
// Process incoming messages in the same way as working with usual sessions.
}
void onError(EngineErrorReason::Enum, const std::string& description) ONIXS_FIXENGINE_OVERRIDE
{
std::clog << "Engine ERROR: " << description << std::endl;
}
void onWarning(EngineWarningReason::Enum, const std::string& description) ONIXS_FIXENGINE_OVERRIDE
{
std::clog << "Engine WARNING: " << description << std::endl;
}
void onError(ErrorReason::Enum, const std::string & description, Session *) ONIXS_FIXENGINE_OVERRIDE
{
std::clog << "Session ERROR: " << description << std::endl;
}
void onWarning(WarningReason::Enum, const std::string & description, Session *) ONIXS_FIXENGINE_OVERRIDE
{
std::clog << "Session WARNING: " << description << std::endl;
}
private:
AcceptorBehavior::Enum acceptorBehavior_;
std::string rejectReason_;
OnixS::FIX::Session * session_;
};
UnknownSessionAcceptor unknownSessionAcceptor(AcceptorBehavior::AcceptConnection, std::string());
Engine::instance()->registerListener(&unknownSessionAcceptor);