fix8  version 1.4.0
Open Source C++ FIX Framework
myfix.cpp File Reference
#include <iostream>
#include <memory>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <iterator>
#include <algorithm>
#include <typeinfo>
#include <thread>
#include <sys/ioctl.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <fix8/f8includes.hpp>
#include <fix8/usage.hpp>
#include <fix8/consolemenu.hpp>
#include <fix8/multisession.hpp>
#include "Myfix_types.hpp"
#include "Myfix_router.hpp"
#include "Myfix_classes.hpp"
#include "myfix.hpp"

Go to the source code of this file.

Namespaces

 FIX8
 
 FIX8::TEX
 

Functions

void print_usage ()
 
const string GETARGLIST ("hl:svqc:R:S:rdomN:D:")
 
f8_atomic< bool > term_received (false)
 
void server_process (ServerSessionBase *srv, int scnt, bool ismulti=false)
 
void client_process (ClientSessionBase *mc)
 
bool quiet (false)
 
unsigned next_send (0)
 
unsigned next_receive (0)
 
void sig_handler (int sig)
 
int main (int argc, char **argv)
 

Variables

FIX8::tty_save_state save_tty (0)
 

Detailed Description


This is a complete working example of a FIX client/server using FIX8.

Usage: f8test [-NRScdhlmoqrsv]
-N,–session for client, select session to use from configuration (default none)
-R,–receive set next expected receive sequence number
-S,–send set next send sequence number
-c,–config xml config (default: myfix_client.xml or myfix_server.xml)
-d,–dump dump parsed XML config file, exit
-h,–help help, this screen
-l,–log global log filename
-m,–multi run multiple server mode (default single server session at a time)
-o,–once for server, allow one client session then exit
-q,–quiet do not print fix output
-r,–reliable start in reliable mode
-s,–server run in server mode (default client mode)
-v,–version print version, exit


To use start the server:

% f8test -sl server

In another terminal session, start the client:

% f8test -l client

Notes

  1. The client has a simple menu. Press ? to see options.
  2. The server will wait for the client to logout before exiting.
  3. The server uses myfix_client.xml and the client uses myfix_server.xml for configuration settings.
  4. The example uses the files FIX50SP2.xml and FIXT11.xml in ./schema

Definition in file myfix.cpp.

Function Documentation

void client_process ( ClientSessionBase mc)

Definition at line 376 of file myfix.cpp.

References FIX8::ClientSessionBase::has_given_up(), FIX8::Session::is_shutdown(), save_tty, FIX8::ClientSessionBase::session_ptr(), FIX8::Session::stop(), and term_received().

Referenced by main().

377 {
378  MyMenu mymenu(*mc->session_ptr(), 0, cout);
379  cout << endl << "Menu started. Press '?' for help..." << endl << endl;
380  char ch(0);
381  mymenu.get_tty().set_raw_mode();
382  save_tty = mymenu.get_tty();
383  while(!mymenu.get_istr().get(ch).bad() && !mc->has_given_up() && !term_received && ch != 0x3 && mymenu.process(ch))
384  ;
385  // don't explicitly call mc->session_ptr()->stop() with reliable sessions
386  // before checking if the session is already shutdown - the framework will generally do this for you
387  if (!mc->session_ptr()->is_shutdown())
388  mc->session_ptr()->stop();
389 
390  mymenu.get_tty().unset_raw_mode();
391 }
FIX8::tty_save_state save_tty(0)
f8_atomic< bool > term_received(false)
F8API void stop()
stop the session.
Definition: session.cpp:230
Simple menu system that will work with most term types.
Definition: hftest.hpp:151
virtual bool has_given_up() const
bool is_shutdown()
Definition: session.hpp:778
virtual Session * session_ptr()=0
const string GETARGLIST ( "hl:svqc:R:S:rdomN:D:"  )

Referenced by main(), and print_usage().

int main ( int  argc,
char **  argv 
)

Definition at line 181 of file myfix.cpp.

References FIX8::SessionConfig::_session_name, FIX8::SessionManager< T >::add(), client_process(), FIX8::TEX::ctx(), XmlElement::Factory(), FIX8_PACKAGE, FIX8_VERSION, FIX8::SessionManager< T >::for_each_if(), GETARGLIST(), RandDev::getrandom(), glout_error, FIX8::hypersleep< h_seconds >(), RandDev::init(), next_receive(), next_send(), print_usage(), quiet(), save_tty, server_process(), FIX8::ClientSessionBase::session_ptr(), sig_handler(), term_received(), FIX8::tty_save_state::unset_raw_mode(), and FIX8::f8Exception::what().

182 {
183  int val;
184  bool server(false), reliable(false), once(false), dump(false), multi(false);
185  string clcf, session;
186 
187 #ifdef FIX8_HAVE_GETOPT_LONG
188  option long_options[]
189  {
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' },
204  { 0 },
205  };
206 
207  while ((val = getopt_long (argc, argv, GETARGLIST.c_str(), long_options, 0)) != -1)
208 #else
209  while ((val = getopt (argc, argv, GETARGLIST.c_str())) != -1)
210 #endif
211  {
212  switch (val)
213  {
214  case 'v':
215  cout << argv[0] << " for " FIX8_PACKAGE " version " FIX8_VERSION << endl;
216  cout << "Released under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3. See <http://fsf.org/> for details." << endl;
217  return 0;
218  case ':': case '?': return 1;
219  case 'h': print_usage(); return 0;
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;
228  case 'R': next_receive = stoul(optarg); break;
229  case 'q': quiet = true; break;
230  case 'r': reliable = true; break;
231  case 'd': dump = true; break;
232  default: break;
233  }
234  }
235 
236  RandDev::init();
237 
238  signal(SIGTERM, sig_handler);
239  signal(SIGINT, sig_handler);
240 #ifndef _MSC_VER
241  signal(SIGQUIT, sig_handler);
242 #endif
243 
244  bool restore_tty(false);
245 
246  try
247  {
248  const string conf_file(server ? clcf.empty() ? "myfix_server.xml" : clcf : clcf.empty() ? "myfix_client.xml" : clcf);
249  f8_atomic<unsigned> scnt(0);
250 
251  if (dump)
252  {
253  XmlElement *root(XmlElement::Factory(conf_file));
254  if (root)
255  cout << *root << endl;
256  else
257  cerr << "Failed to parse " << conf_file << endl;
258  return 0;
259  }
260 
261  if (server)
262  {
263  if (multi) // demonstrate use of multi session server manager
264  {
265  unique_ptr<ServerManager> sm(new ServerManager);
266  sm->add(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX1"));
267  sm->add(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX2"));
268 
269  vector<thread> thrds;
270  while (!term_received)
271  {
272  ServerSessionBase *srv(sm->select());
273  if (srv)
274  {
275  thrds.push_back(thread ([&]() { server_process(srv, ++scnt, true); }));
277  }
278  }
279  for_each(thrds.begin(), thrds.end(), [](thread& tt) { if (tt.joinable()) tt.join(); });
280  }
281  else // serial server instances only
282  {
283  unique_ptr<ServerSessionBase> srv(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX"));
284 
285  while (!term_received)
286  {
287  if (!srv->poll())
288  continue;
289  server_process(srv.get(), ++scnt);
290  if (once)
291  break;
292  }
293  }
294  }
295  else
296  {
297  if (multi) // demonstrate use of multi session client manager
298  {
299  const f8String cl1("DLD1"), cl2("DLD2");
300  ClientManager cm;
301  cm.add(cl1, reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl1)
302  : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl1));
303  cm.add(cl2, reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl2)
304  : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, cl2));
305 
307  {
308  if (!quiet)
309  pp->session_ptr()->control() |= Session::printnohb;
310  pp->start(false, next_send, next_receive, pp->session_ptr()->get_login_parameters()._davi());
311  // if you use ReliableClientSession, you need to return true here always
312  return reliable ? true : States::is_live(pp->session_ptr()->get_session_state());
313  }));
314 
315  if (csb)
316  cerr << csb->_session_name << " failed to start" << endl;
317 
318  vector<thread> thrds;
319  cm.for_each_if([&](ClientSessionBase *pp)
320  {
321  // we should be running client_process however this won't work
322  // since two threads can't share the same console
323  thrds.push_back(thread ([=]() // use copy closure
324  {
325  MyMenu mymenu(*pp->session_ptr(), 0, cout);
327  mymenu.new_order_single(); // send an order and then logout
328  mymenu.do_logout();
329  }));
330  return true;
331  });
332 
333  for_each(thrds.begin(), thrds.end(), [](thread& tt) { if (tt.joinable()) tt.join(); });
334  }
335  else // single client only
336  {
337  const string my_session(session.empty() ? "DLD1" : session);
338  unique_ptr<ClientSessionBase>
339  mc(reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, my_session)
340  : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, my_session));
341  if (!quiet)
342  mc->session_ptr()->control() |= Session::printnohb;
343  mc->start(false, next_send, next_receive, mc->session_ptr()->get_login_parameters()._davi());
344  client_process(mc.get());
345  }
346  }
347  }
348  catch (f8Exception& e)
349  {
350  cerr << "exception: " << e.what() << endl;
351  restore_tty = true;
352  glout_error << e.what();
353  }
354  catch (exception& e) // also catches Poco::Net::NetException
355  {
356  cerr << "std::exception: " << e.what() << endl;
357  restore_tty = true;
358  glout_error << e.what();
359  }
360  catch (...)
361  {
362  cerr << "unknown exception" << endl;
363  restore_tty = true;
364  glout_error << "unknown exception";
365  }
366 
367  if (restore_tty && !server)
369 
370  if (term_received)
371  cout << endl << "terminated." << endl;
372  return 0;
373 }
static F8API XmlElement * Factory(std::istream &istr, const char *docpath=nullptr)
static void init()
Initialise the random number generator.
Definition: hftest.hpp:205
Session Manager.
Multi Server Manager.
FIX8::tty_save_state save_tty(0)
static T getrandom(const T range=0)
Definition: hftest.hpp:219
#define FIX8_PACKAGE
Definition: f8config.h:601
Client wrapper.
unsigned next_receive(0)
#define glout_error
Definition: logger.hpp:606
Base Client wrapper.
unsigned next_send(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)
Base exception class.
Definition: f8exception.hpp:49
A simple xml parser with Xpath style lookup.
Definition: xml.hpp:48
void print_usage()
Definition: myfix.cpp:744
Base Server Session.
void server_process(ServerSessionBase *srv, int scnt, bool ismulti=false)
Definition: myfix.cpp:394
Simple menu system that will work with most term types.
Definition: hftest.hpp:151
bool quiet(false)
std::atomic< T > f8_atomic
Definition: thread.hpp:55
int hypersleep< h_seconds >(unsigned amt)
Definition: hypersleep.hpp:83
const std::string _session_name
void sig_handler(int sig)
Definition: myfix.cpp:165
#define FIX8_VERSION
Definition: f8config.h:742
const string GETARGLIST("hl:svqc:R:S:rdomN:D:")
bool add(const f8String &name, T *what)
const char * what() const
Definition: f8exception.hpp:85
std::string f8String
Definition: f8types.hpp:47
Reliable Client wrapper. This client attempts to recover from disconnects and login rejects...
void client_process(ClientSessionBase *mc)
Definition: myfix.cpp:376
virtual Session * session_ptr()=0
unsigned next_receive ( )

Referenced by main(), and server_process().

unsigned next_send ( )

Referenced by main(), and server_process().

void print_usage ( )

Definition at line 744 of file myfix.cpp.

References UsageMan::add(), GETARGLIST(), UsageMan::print(), and UsageMan::setdesc().

Referenced by main().

745 {
746  UsageMan um("f8test", GETARGLIST, "");
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");
762  um.add("e.g.");
763  um.add("@f8test -sml server_log");
764  um.add("@f8test -rl client_log");
765  um.add("@f8test -rl server -S 124");
766  um.print(cerr);
767 }
const string GETARGLIST("hl:svqc:R:S:rdomN:D:")
Convenient program help/usage wrapper. Generates a standardised usage message.
Definition: usage.hpp:42
bool quiet ( false  )

Referenced by main(), and server_process().

void server_process ( ServerSessionBase srv,
int  scnt,
bool  ismulti = false 
)

Definition at line 394 of file myfix.cpp.

References FIX8::SessionConfig::_ses, FIX8::ServerSessionBase::create_server_instance(), FIX8::Configuration::get_process_model(), glout_info, FIX8::hypersleep< h_milliseconds >(), next_receive(), next_send(), FIX8::pm_pipeline, quiet(), and myfix_session_server::sample_scheduler_callback().

Referenced by main().

395 {
396  unique_ptr<SessionInstanceBase> inst(srv->create_server_instance());
397  if (!quiet)
398  inst->session_ptr()->control() |= Session::print;
399  glout_info << "client(" << scnt << ") connection established.";
400  const ProcessModel pm(srv->get_process_model(srv->_ses));
401  cout << (pm == pm_pipeline ? "Pipelined" : "Threaded") << " mode." << endl;
402  inst->start(pm == pm_pipeline, next_send, next_receive);
403  if (inst->session_ptr()->get_connection()->is_secure())
404  cout << "Session is secure (SSL)" << endl;
405  if (!ismulti && !quiet) // demonstrate use of timer events
406  {
407  TimerEvent<FIX8::Session> sample_callback(static_cast<bool (FIX8::Session::*)()>(&myfix_session_server::sample_scheduler_callback), true);
408  inst->session_ptr()->get_timer().schedule(sample_callback, 60000); // call sample_scheduler_callback every minute forever
409  }
410  if (pm != pm_pipeline)
411  while (!inst->session_ptr()->is_shutdown())
413  cout << "Session(" << scnt << ") finished." << endl;
414  inst->stop();
415 }
Fix8 Base Session. User sessions are derived from this class.
Definition: session.hpp:394
ProcessModel
Supported session process models.
Definition: f8types.hpp:56
unsigned next_receive(0)
unsigned next_send(0)
int hypersleep< h_milliseconds >(unsigned amt)
Definition: hypersleep.hpp:105
#define glout_info
Definition: logger.hpp:601
bool quiet(false)
const XmlElement * _ses
virtual SessionInstanceBase * create_server_instance()=0
F8API ProcessModel get_process_model(const XmlElement *from) const
bool sample_scheduler_callback()
Definition: myfix.cpp:447
void sig_handler ( int  sig)

Definition at line 165 of file myfix.cpp.

References term_received().

Referenced by main().

166 {
167  switch (sig)
168  {
169  case SIGTERM:
170  case SIGINT:
171 #ifndef _MSC_VER
172  case SIGQUIT:
173 #endif
174  term_received = true;
175  signal(sig, sig_handler);
176  break;
177  }
178 }
f8_atomic< bool > term_received(false)
void sig_handler(int sig)
Definition: myfix.cpp:165
f8_atomic<bool> term_received ( false  )

Referenced by client_process(), main(), and sig_handler().

Variable Documentation

FIX8::tty_save_state save_tty(0)

Referenced by client_process(), and main().