109 #include <sys/ioctl.h> 
  121 #ifdef FIX8_HAVE_GETOPT_H 
  136 using namespace FIX8;
 
  140 const string GETARGLIST(
"hl:svqc:R:S:rdomN:D:");
 
  150    { { 
'r', 
"New Order Single Recycled - 1st use send as normal then will send recycled message" },
 
  181 int main(
int argc, 
char **argv)
 
  184    bool server(
false), reliable(
false), once(
false), dump(
false), multi(
false);
 
  185    string clcf, session;
 
  187 #ifdef FIX8_HAVE_GETOPT_LONG 
  188    option long_options[]
 
  190       { 
"help",      0, 0, 
'h' },
 
  191       { 
"version",   0, 0, 
'v' },
 
  192       { 
"log",       1, 0, 
'l' },
 
  193       { 
"delimiter", 1, 0, 
'D' },
 
  194       { 
"config",    1, 0, 
'c' },
 
  195       { 
"session",   1, 0, 
'N' },
 
  196       { 
"once",      0, 0, 
'o' },
 
  197       { 
"server",    0, 0, 
's' },
 
  198       { 
"multi",     0, 0, 
'm' },
 
  199       { 
"send",      1, 0, 
'S' },
 
  200       { 
"receive",   1, 0, 
'R' },
 
  201       { 
"quiet",     0, 0, 
'q' },
 
  202       { 
"reliable",  0, 0, 
'r' },
 
  203       { 
"dump",      0, 0, 
'd' },
 
  207    while ((val = getopt_long (argc, argv, 
GETARGLIST.c_str(), long_options, 0)) != -1)
 
  209    while ((val = getopt (argc, argv, 
GETARGLIST.c_str())) != -1)
 
  216          cout << 
"Released under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3. See <http://fsf.org/> for details." << endl;
 
  218       case ':': 
case '?': 
return 1;
 
  220       case 'l': GlobalLogger::set_global_filename(optarg); 
break;
 
  221       case 'D': GlobalLogger::set_delimiter(optarg); 
break;
 
  222       case 'c': clcf = optarg; 
break;
 
  223       case 's': server = 
true; 
break;
 
  224       case 'N': session = optarg; 
break;
 
  225       case 'm': multi = 
true; 
break;
 
  226       case 'o': once = 
true; 
break;
 
  227       case 'S': 
next_send = stoul(optarg); 
break;
 
  229       case 'q': 
quiet = 
true; 
break;
 
  230       case 'r': reliable = 
true; 
break;
 
  231       case 'd': dump = 
true; 
break;
 
  244    bool restore_tty(
false);
 
  248       const string conf_file(server ? clcf.empty() ? 
"myfix_server.xml" : clcf : clcf.empty() ? 
"myfix_client.xml" : clcf);
 
  255             cout << *root << endl;
 
  257             cerr << 
"Failed to parse " << conf_file << endl;
 
  269             vector<thread> thrds;
 
  275                   thrds.push_back(thread ([&]() { 
server_process(srv, ++scnt, 
true); }));
 
  279             for_each(thrds.begin(), thrds.end(), [](thread& tt) { 
if (tt.joinable()) tt.join(); });
 
  299             const f8String cl1(
"DLD1"), cl2(
"DLD2");
 
  309                   pp->session_ptr()->control() |= Session::printnohb;
 
  310                pp->start(false, next_send, next_receive, pp->session_ptr()->get_login_parameters()._davi());
 
  312                return reliable ? true : States::is_live(pp->session_ptr()->get_session_state());
 
  318             vector<thread> thrds;
 
  323                thrds.push_back(thread ([=]()    
 
  327                   mymenu.new_order_single(); 
 
  333             for_each(thrds.begin(), thrds.end(), [](thread& tt) { 
if (tt.joinable()) tt.join(); });
 
  337             const string my_session(session.empty() ? 
"DLD1" : session);
 
  338             unique_ptr<ClientSessionBase>
 
  342                mc->session_ptr()->control() |= Session::printnohb;
 
  350       cerr << 
"exception: " << e.
what() << endl;
 
  356       cerr << 
"std::exception: " << e.what() << endl;
 
  362       cerr << 
"unknown exception" << endl;
 
  367    if (restore_tty && !server)
 
  371       cout << endl << 
"terminated." << endl;
 
  379    cout << endl << 
"Menu started. Press '?' for help..." << endl << endl;
 
  381    mymenu.get_tty().set_raw_mode();
 
  390    mymenu.get_tty().unset_raw_mode();
 
  398       inst->session_ptr()->control() |= Session::print;
 
  399    glout_info << 
"client(" << scnt << 
") connection established.";
 
  401    cout << (pm == 
pm_pipeline ? 
"Pipelined" : 
"Threaded") << 
" mode." << endl;
 
  403    if (inst->session_ptr()->get_connection()->is_secure())
 
  404       cout << 
"Session is secure (SSL)" << endl;
 
  405    if (!ismulti && !
quiet) 
 
  408       inst->session_ptr()->get_timer().schedule(sample_callback, 60000); 
 
  411       while (!inst->session_ptr()->is_shutdown())
 
  413    cout << 
"Session(" << scnt << 
") finished." << endl;
 
  420    return enforce(seqnum, msg) || msg->
process(_router);
 
  426    cout << get_session_state_string(before) << 
" => " << get_session_state_string(after) << endl;
 
  432    if (enforce(seqnum, msg))
 
  443    cout << get_session_state_string(before) << 
" => " << get_session_state_string(after) << endl;
 
  449    cout << 
"myfix_session_server::sample_scheduler_callback Hello!" << endl;
 
  456    static unsigned oid(0);
 
  458    oistr << 
"ord" << ++oid;
 
  496    static const char *secIDs[] { 
"Reverera", 
"Orlanda", 
"Withroon", 
"Longweed", 
"Blechnod" };
 
  498    for (
size_t ii(0); ii < 
sizeof(secIDs)/
sizeof(
char *); ++ii)
 
  529    static unsigned oid(0);
 
  531    oistr << 
"ord" << ++oid;
 
  569    static const char *secIDs[] { 
"Reverera", 
"Orlanda", 
"Withroon", 
"Longweed", 
"Blechnod" };
 
  571    for (
size_t ii(0); ii < 
sizeof(secIDs)/
sizeof(
char *); ++ii)
 
  602    _session.send(generate_new_order_single_alternate());
 
  609    _session.send(generate_new_order_single());
 
  619    static bool first(
true);
 
  623       cout << 
"Sending new new_order_single" << endl;
 
  624       _session.send(msg = generate_new_order_single(), first = 
false);
 
  629       cout << 
"Sending recycled new_order_single" << endl;
 
  630       _session.send(msg, 
false);
 
  632 #if defined FIX8_RAW_MSG_SUPPORT 
  634    cout << msg->get_rawmsg() << endl;
 
  635    copy(msg->begin_payload(), msg->end_payload(), ostream_iterator<char>(cout, 
""));
 
  637    cout << 
"payload begin=" << msg->get_payload_begin() << 
" payload len=" << msg->get_payload_len() << endl;
 
  645 #if defined FIX8_HAVE_EXTENDED_METADATA 
  646    (cout << 
"Enter message tag:").flush();
 
  649    if (!get_string(result).empty() && (tbme = _session.get_ctx()._bme.find_ptr(result.c_str())))
 
  651         function<void( const TraitHelper&, int )> print_traits;
 
  652       print_traits = ([&print_traits, 
this](
const TraitHelper& tr, 
int depth)
 
  654          const string spacer(depth * MessageBase::get_tabsize(), 
' ');
 
  655          for (F8MetaCntx::const_iterator itr(F8MetaCntx::begin(tr)); itr != F8MetaCntx::end(tr); ++itr)
 
  657             const BaseEntry *be(_session.get_ctx().find_be(itr->_fnum));
 
  658             cout << spacer << be->
_name;
 
  660                cout << 
" Realm:" << (be->_rlm->_dtype == RealmBase::dt_range ? 
"range" : 
"set")
 
  661                   << 
'(' << be->_rlm->_sz << 
") ";
 
  662             cout << *itr << endl;
 
  663             if (itr->_field_traits.has(FieldTrait::group))
 
  664                print_traits(itr->_group, depth + 1);
 
  668       cout << tbme->
_name << endl;
 
  669       print_traits(tbme->
_create._get_traits(), 1);
 
  672       cout << 
"Unknown message tag: " << result << endl;
 
  674    cout << 
"Extended metadata not available (try ./configure --enable-extended-metadata=yes)." << endl;
 
  683    vector<Message *> msgs;
 
  684    for (
auto ii(0); ii < 50; ++ii)
 
  685       msgs.push_back(generate_new_order_single());
 
  687    _session.send_batch(msgs);
 
  694    vector<Message *> msgs;
 
  695    for (
auto ii(0); ii < 1000; ++ii)
 
  696       msgs.push_back(generate_new_order_single());
 
  698    _session.send_batch(msgs);
 
  706    get_ostr() << 
"Key\tCommand" << endl;
 
  707    get_ostr() << 
"===\t=======" << endl;
 
  708    for (
const auto& pp : _handlers)
 
  709       get_ostr() << pp.first._key << 
'\t' << pp.first._help << endl;
 
  717    if (!_session.is_shutdown())
 
  720       get_ostr() << 
"logout..." << endl;
 
  729    if (!_session.is_shutdown())
 
  731       unsigned bnum(0), bend(0);
 
  732       cout << 
"Enter BeginSeqNo:" << flush;
 
  733       _tty.unset_raw_mode();
 
  735       cout << 
"Enter EndSeqNo(0=all):" << flush;
 
  738       _session.send(_session.generate_resend_request(bnum, bend));
 
  747    um.
setdesc(
"f8test -- f8 test client/server");
 
  748    um.
add(
's', 
"server", 
"run in server mode (default client mode)");
 
  749    um.
add(
'm', 
"multi", 
"run in multiple server or client mode (default serial server or single client session at a time)");
 
  750    um.
add(
'h', 
"help", 
"help, this screen");
 
  751    um.
add(
'v', 
"version", 
"print version, exit");
 
  752    um.
add(
'l', 
"log", 
"global log filename");
 
  753    um.
add(
'o', 
"once", 
"for server, allow one client session then exit");
 
  754    um.
add(
'c', 
"config", 
"xml config (default: myfix_client.xml or myfix_server.xml)");
 
  755    um.
add(
'q', 
"quiet", 
"do not print fix output");
 
  756    um.
add(
'R', 
"receive", 
"set next expected receive sequence number");
 
  757    um.
add(
'S', 
"send", 
"set next send sequence number");
 
  758    um.
add(
'D', 
"delimiter", 
"set GlobalLogger field delimiter (default ' ')");
 
  759    um.
add(
'N', 
"session", 
"for client, select session to use from configuration (default DLD1)");
 
  760    um.
add(
'r', 
"reliable", 
"start in reliable mode");
 
  761    um.
add(
'd', 
"dump", 
"dump parsed XML config file, exit");
 
  763    um.
add(
"@f8test -sml server_log");
 
  764    um.
add(
"@f8test -rl client_log");
 
  765    um.
add(
"@f8test -rl server -S 124");
 
  772 #if defined FIX8_RAW_MSG_SUPPORT 
  774    cout << msg->get_rawmsg() << endl;
 
  775    copy(msg->begin_payload(), msg->end_payload(), ostream_iterator<char>(cout, 
""));
 
  777    cout << 
"payload begin=" << msg->get_payload_begin() << 
" payload len=" << msg->get_payload_len() << endl;
 
  784       cout << itr->first << 
" is ";
 
  785       if (FieldTrait::is_int(trait))
 
  787       else if (FieldTrait::is_char(trait))
 
  789       else if (FieldTrait::is_string(trait))
 
  791       else if (FieldTrait::is_float(trait))
 
  795       cout << 
'\t' << _session.get_ctx().find_be(itr->first)->_name << 
'\t' << *itr->second << endl;
 
  799    static unsigned oid(0), eoid(0);
 
  808          cout << 
"Order qty (copy):" << qty() << endl;
 
  812          cout << 
"Order qty (in place):" << msg->
get<
TEX::OrderQty>()->get() << endl;
 
  815          cout << 
"price:" << 
price() << endl;
 
  821          for (
size_t cnt(0); cnt < grnoul->size(); ++cnt)
 
  824             MessageBase *me(grnoul->get_element(static_cast<unsigned>(cnt)));
 
  826             cout << 
"Underlying symbol:" << unsym() << endl;
 
  831                for (
size_t cnt(0); cnt < nus->size(); ++cnt)
 
  834                   MessageBase *me(nus->get_element(static_cast<unsigned>(cnt)));
 
  836                   cout << 
"Underlying StipType:" << stipType() << endl;
 
  845          for (
size_t cnt(0); cnt < grallocs->size(); ++cnt)
 
  848             MessageBase *me(grallocs->get_element(static_cast<unsigned>(cnt)));
 
  850             cout << 
"TEX::NewOrderSingle::NoAllocs Account:" << acc() << endl;
 
  855                for (
size_t cnt(0); cnt < nnpi->size(); ++cnt)
 
  858                   MessageBase *me(nnpi->get_element(static_cast<unsigned>(cnt)));
 
  860                   cout << 
"TEX::NewOrderSingle::NoAllocs::NoNestedPartyIDs NestedPartyID:" << npi() << endl;
 
  865                      for (
size_t cnt(0); cnt < nnpsi->size(); ++cnt)
 
  868                         MessageBase *me(nnpsi->get_element(static_cast<unsigned>(cnt)));
 
  870                         cout << 
"TEX::NewOrderSingle::NoAllocs::NoNestedPartyIDs::NoNestedPartySubIDs NestedPartySubID:" << npsi() << endl;
 
  885    oistr << 
"ord" << ++oid;
 
  898    unsigned remaining_qty(qty()), cum_qty(0);
 
  899    while (remaining_qty > 0)
 
  907       eistr << 
"exec" << ++eoid;
 
  908       remaining_qty -= trdqty;
 
  928    if (msg->
get(lastCap))
 
  931       if (!
quiet && !lastCap.is_valid())
 
  932          cout << 
"TEX::LastCapacity(" << lastCap << 
") is not a valid value" << endl;
 
static F8API XmlElement * Factory(std::istream &istr, const char *docpath=nullptr)
Field< NumInGroup, 453 > NoPartyIDs
static void init()
Initialise the random number generator. 
Field< NumInGroup, 711 > NoUnderlyings
Field< f8String, 524 > NestedPartyID
Field< Qty, 879 > UnderlyingQty
NoAllocs (78), application, 6 fields, 1 group, shares static data, hash: 0x210f1ab6. 
virtual bool operator()(const FIX8::TEX::ExecutionReport *msg)
Fix8 Base Session. User sessions are derived from this class. 
Field< f8String, 545 > NestedPartySubID
const char TimeInForce_FILL_OR_KILL('4')
Field< NumInGroup, 78 > NoAllocs
Field< char, 59 > TimeInForce
Message instantiation table entry. 
FIX8::tty_save_state save_tty(0)
static T getrandom(const T range=0)
Field< NumInGroup, 804 > NoNestedPartySubIDs
bool add(const char sw, const std::string &lsw, const std::string &help)
Field< f8String, 79 > AllocAccount
GroupBase * find_group() const 
Field< char, 39 > OrdStatus
ExecutionReport (8), application, 326 fields, 16 groups. 
Field< Boolean, 113 > ReportToExch
F8API unsigned copy_legal(MessageBase *to, bool force=false) const 
Logout (5), admin, 3 fields, 0 groups. 
Field< char, 40 > OrdType
const Presence & get_presence() const 
Field< NumInGroup, 539 > NoNestedPartyIDs
ProcessModel
Supported session process models. 
void push_unknown(Message *to) const 
const char OrdStatus_FILLED('2')
void state_change(const FIX8::States::SessionStates before, const FIX8::States::SessionStates after)
Abstract base class for all repeating groups. 
virtual MessageBase * create_group(bool deepctor=true) const =0
f8_atomic< bool > term_received(false)
const F8MetaCntx & ctx()
Compiler generated metadata object, accessed through this function. 
T * for_each_if(std::function< bool(T *)> func)
NewOrderSingle (D), application, 243 fields, 11 groups. 
void setdesc(const std::string &desc)
A simple xml parser with Xpath style lookup. 
void print(std::ostream &os) const 
F8API void stop()
stop the session. 
int hypersleep< h_milliseconds >(unsigned amt)
const char OrdType_LIMIT('2')
bool handle_application(const unsigned seqnum, const FIX8::Message *&msg)
Field< f8String, 11 > ClOrdID
virtual bool operator()(const FIX8::TEX::NewOrderSingle *msg)
virtual bool process(Router &rt) const 
void server_process(ServerSessionBase *srv, int scnt, bool ismulti=false)
A complete Fix message with header, body and trailer. 
std::atomic< T > f8_atomic
void state_change(const FIX8::States::SessionStates before, const FIX8::States::SessionStates after)
Field< f8String, 458 > UnderlyingSecurityAltID
Fields::const_iterator fields_end() const 
Field template. There will ONLY be partial template specialisations of this template. 
int hypersleep< h_seconds >(unsigned amt)
Field< char, 29 > LastCapacity
const char OrdStatus_PARTIALLY_FILLED('1')
bool handle_application(const unsigned seqnum, const FIX8::Message *&msg)
GroupBase * find_add_group(GroupBase *grpbase=nullptr)
Field< f8String, 37 > OrderID
Field< NumInGroup, 887 > NoUnderlyingStips
const std::string _session_name
const FieldTraits & get_fp() const 
Field< Qty, 38 > OrderQty
void sig_handler(int sig)
virtual bool has_given_up() const 
const string GETARGLIST("hl:svqc:R:S:rdomN:D:")
virtual SessionInstanceBase * create_server_instance()=0
const char OrdStatus_NEW('0')
Field< f8String, 311 > UnderlyingSymbol
NoUnderlyings (711), application, 72 fields, 3 groups, shares static data, hash: 0xb078f5a8. 
bool add(const f8String &name, T *what)
const char * what() const 
Base class for all fix messages. 
const char ExecType_NEW('0')
int main(int argc, char **argv)
Field< NumInGroup, 457 > NoUnderlyingSecurityAltID
Fields::const_iterator fields_begin() const 
F8API ProcessModel get_process_model(const XmlElement *from) const 
Field< Qty, 151 > LeavesQty
Convenient program help/usage wrapper. Generates a standardised usage message. 
Reliable Client wrapper. This client attempts to recover from disconnects and login rejects...
void client_process(ClientSessionBase *mc)
bool sample_scheduler_callback()
Field< f8String, 888 > UnderlyingStipType
Field< f8String, 17 > ExecID
virtual Session * session_ptr()=0