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