OnixS C++ ICE Binary Order Entry Handler 1.0.0
API Documentation
Loading...
Searching...
No Matches
TCPDirect Getting Started Sample

This sample shows how to connect TCPDirect session to the pre-defined host and port.

When the session is established, the NewOrderSngle message is sent to the counterparty.

Using TCPDirect Network Stack

TCPDirect is part of Solarflare's suite of network acceleration technologies.

The TCP loopback is not supported by TCPDirect technology, so the emulator should be started on a remote host (or on a different physically connected card with a configured route to it).

For developing/debugging purposes OnixS provides TCPDirect emulation for Windows over OS sockets, so TCPDirectGettingStarted sample can be run in loopback mode under Windows.

Source code

#include "../Settings/Defaults.h"
#include "../Common/Helpers.h"
#include "../Common/Listener.h"
#include "../Common/Settings.h"
#include "../Common/Signal.h"
#include "../Common/Emulator.h"
using namespace Samples;
using namespace Threading;
int main(int argc, char * argv[])
{
// `--help` to show options
const AppConfiguration<
SettingsConfiguration
, ConnectivityConfiguration
, LogonConfiguration
, NetworkInterfaceConfiguration
, StorageConfiguration<SessionStorageType::FileBased>
> cfg{"TCPDirectGettingStarted", argc, argv};
try
{
SignalHelper::manageSignals();
auto settings = fillSettings(cfg);
const auto emulator = createEmulator(settings, cfg, true);
// Request Binary Order Gateway credentials from Binary Utility Service Gateway (using OS sockets)
const auto bgwCredentials = receiveBgwCredentials(settings, cfg.host(), cfg.port());
class TcpDirectListener : public Listener
{
public:
explicit TcpDirectListener(const LogonConfiguration& cfg)
: traderLogonRequest_(Helper::createTraderLogonRequest(cfg.traderId(), cfg.traderPwd()))
, order_(Helper::createOrder(cfg.traderId()))
{
}
void onTraderLogonReport(const Messaging::TraderLogonReport msg, Session* session) override
{
Listener::onTraderLogonReport(msg, session);
try
{
traderLoggedOn.get_future().get();
}
catch(const std::exception& e)
{
onError(SessionErrorReason::UnsuccessfulLogonReportInReplyOnLogonRequest, e.what(), session, msg);
return;
}
session->send(order_);
}
void onStateChange(SessionStateId::Enum newState, SessionStateId::Enum prevState, Session * session) override
{
Listener::onStateChange(newState, prevState, session);
switch(newState)
{
case SessionStateId::Established:
{
session->send(traderLogonRequest_);
break;
}
case SessionStateId::Disconnected:
finished_ = true;
break;
default:
break;
}
}
void onError(
SessionErrorReason::Enum reason, const std::string & text, Session * session, Messaging::SbeMessage msg) override
{
Listener::onError(reason, text, session, msg);
finished_ = true;
}
bool finished() const noexcept {return finished_;}
private:
bool finished_ {false};
MessageHolder<TraderLogonRequest> traderLogonRequest_;
MessageHolder<NewOrderRequest> order_;
}
listener(cfg);
TcpDirectAttr attr;
// The default interface name could be provided by the environment variable
// ZF_ATTR="interface=<interface-name>", see TCPDirect specs,
attr.set("interface", cfg.nif());
TcpDirectStack stack{attr};
// A 'BGW' session
const auto bgwSession= createSession(stack, SessionType::BGW, settings, &listener, cfg.storage());
bgwSession->connectAsync(bgwCredentials.host, bgwCredentials.port);
std::clog << "\nPress <Ctrl+C> to disconnect the BGW session and terminate the application." << std::endl;
while(!listener.finished())
{
// The TCPDirect technology is NOT thread-safe.
// Therefore, the event dispatching and message sending should be performed from the same thread.
stack.dispatchEvents();
if(SignalHelper::interruptDetected())
break;
}
bgwSession->disconnectAsync();
while(!stack.isQuiescent())
stack.dispatchEvents();
}
catch(const std::exception & ex)
{
std::cerr << "\nEXCEPTION: " << ex.what() << std::endl;
return 1;
}
return 0;
}