FIX8::f8String& get_string(FIX8::f8String& to) { char buff[128] {}; _tty.unset_raw_mode(); _istr.getline(buff, sizeof(buff)); _tty.set_raw_mode(); return to = buff; }
//----------------------------------------------------------------------------------------- int main(int argc, char **argv) { int val; bool server(false), reliable(false), once(false), dump(false), multi(false); string clcf, session; #ifdef FIX8_HAVE_GETOPT_LONG option long_options[] { { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { "log", 1, 0, 'l' }, { "delimiter", 1, 0, 'D' }, { "config", 1, 0, 'c' }, { "session", 1, 0, 'N' }, { "once", 0, 0, 'o' }, { "server", 0, 0, 's' }, { "multi", 0, 0, 'm' }, { "send", 1, 0, 'S' }, { "receive", 1, 0, 'R' }, { "quiet", 0, 0, 'q' }, { "reliable", 0, 0, 'r' }, { "dump", 0, 0, 'd' }, { 0 }, }; while ((val = getopt_long (argc, argv, GETARGLIST.c_str(), long_options, 0)) != -1) #else while ((val = getopt (argc, argv, GETARGLIST.c_str())) != -1) #endif { switch (val) { case 'v': cout << argv[0] << " for " FIX8_PACKAGE " version " FIX8_VERSION << endl; cout << "Released under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3. See <http://fsf.org/> for details." << endl; return 0; case ':': case '?': return 1; case 'h': print_usage(); return 0; case 'l': GlobalLogger::set_global_filename(optarg); break; case 'D': GlobalLogger::set_delimiter(optarg); break; case 'c': clcf = optarg; break; case 's': server = true; break; case 'N': session = optarg; break; case 'm': multi = true; break; case 'o': once = true; break; case 'S': next_send = stoul(optarg); break; case 'R': next_receive = stoul(optarg); break; case 'q': quiet = true; break; case 'r': reliable = true; break; case 'd': dump = true; break; default: break; } } RandDev::init(); signal(SIGTERM, sig_handler); signal(SIGINT, sig_handler); #ifndef _MSC_VER signal(SIGQUIT, sig_handler); #endif bool restore_tty(false); try { const string conf_file(server ? clcf.empty() ? "myfix_server.xml" : clcf : clcf.empty() ? "myfix_client.xml" : clcf); f8_atomic<unsigned> scnt(0); if (dump) { XmlElement *root(XmlElement::Factory(conf_file)); if (root) cout << *root << endl; else cerr << "Failed to parse " << conf_file << endl; return 0; } if (server) { if (multi) // demonstrate use of multi session server manager { unique_ptr<ServerManager> sm(new ServerManager); sm->add(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX1")); sm->add(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX2")); vector<thread> thrds; while (!term_received) { ServerSessionBase *srv(sm->select()); if (srv) { thrds.push_back(thread ([&]() { server_process(srv, ++scnt, true); })); hypersleep<h_seconds>(1); } } for_each(thrds.begin(), thrds.end(), [](thread& tt) { if (tt.joinable()) tt.join(); }); } else // serial server instances only { unique_ptr<ServerSessionBase> srv(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX")); while (!term_received) { if (!srv->poll()) continue; server_process(srv.get(), ++scnt); if (once) break; } } } else { if (multi) // demonstrate use of multi session client manager { const f8String cl1("DLD1"), cl2("DLD2"); ClientManager cm; cm.add(cl1, reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl1) : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl1)); cm.add(cl2, reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl2) : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl2)); ClientSessionBase *csb(cm.for_each_if([&](ClientSessionBase *pp) { if (!quiet) pp->session_ptr()->control() |= Session::printnohb; pp->start(false, next_send, next_receive, pp->session_ptr()->get_login_parameters()._davi()); // if you use ReliableClientSession, you need to return true here always return reliable ? true : States::is_live(pp->session_ptr()->get_session_state()); })); if (csb) cerr << csb->_session_name << " failed to start" << endl; vector<thread> thrds; cm.for_each_if([&](ClientSessionBase *pp) { // we should be running client_process however this won't work // since two threads can't share the same console thrds.push_back(thread ([=]() // use copy closure { MyMenu mymenu(*pp->session_ptr(), 0, cout); hypersleep<h_seconds>(1 + RandDev::getrandom(10)); mymenu.new_order_single(); // send an order and then logout mymenu.do_logout(); })); return true; }); for_each(thrds.begin(), thrds.end(), [](thread& tt) { if (tt.joinable()) tt.join(); }); } else // single client only { const string my_session(session.empty() ? "DLD1" : session); unique_ptr<ClientSessionBase> mc(reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, my_session) : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, my_session)); if (!quiet) mc->session_ptr()->control() |= Session::printnohb; mc->start(false, next_send, next_receive, mc->session_ptr()->get_login_parameters()._davi()); client_process(mc.get()); } } } catch (f8Exception& e) { cerr << "exception: " << e.what() << endl; restore_tty = true; glout_error << e.what(); } catch (exception& e) // also catches Poco::Net::NetException { cerr << "std::exception: " << e.what() << endl; restore_tty = true; glout_error << e.what(); } catch (...) { cerr << "unknown exception" << endl; restore_tty = true; glout_error << "unknown exception"; } if (restore_tty && !server) save_tty.unset_raw_mode(); if (term_received) cout << endl << "terminated." << endl; return 0; }