fix8  version 1.4.0
Open Source C++ FIX Framework
harness.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 <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 "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:rp:L:")
 
bool term_received (false)
 
bool quiet (false)
 
void sig_handler (int sig)
 
int main (int argc, char **argv)
 

Detailed Description


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

Usage: harness [-LRSchlpqrsv]
-L,–lines set number of screen lines in the console menu (default 50)
-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)
-h,–help help, this screen
-l,–log global log filename
-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 then exit


To use start the server:

% harness -sl server

In another terminal session, start the client:

% harness -l client

Notes

  1. If you have configured with –enable-msgrecycle, the example will reuse allocated messages.
  2. If you have configured with –enable-customfields, the example will add custom fields
    defined below.
  3. The client has a simple menu. Press ? to see options.
  4. The server will wait for the client to logout before exiting.
  5. The server uses myfix_client.xml and the client uses myfix_server.xml for configuration settings.
  6. The example uses the files FIX50SP2.xml and FIXT11.xml in ./schema

Definition in file harness.cpp.

Function Documentation

const string GETARGLIST ( "hl:svqc:R:S:rp:L:"  )

Referenced by main(), and print_usage().

int main ( int  argc,
char **  argv 
)

Definition at line 176 of file harness.cpp.

References FIX8::TEX::ctx(), FIX8_PACKAGE, FIX8_VERSION, MyMenu::get_tty(), GETARGLIST(), glout_info, FIX8::hypersleep< h_seconds >(), RandDev::init(), next_receive(), next_send(), print_usage(), quiet(), FIX8::tty_save_state::set_raw_mode(), sig_handler(), term_received(), and FIX8::f8Exception::what().

177 {
178  int val, lines(50);
179  bool server(false), reliable(false);
180  string clcf, replay_file;
181  unsigned next_send(0), next_receive(0);
182 
183  // for xterm or if tput is available, export LINES so we can use here
184  const char *gresult(getenv("LINES"));
185  if (gresult && *gresult)
186  {
187  const string result(gresult);
188  const int nlines(stoi(result));
189  if (nlines > 10)
190  lines = nlines - 4;
191  }
192 
193 #ifdef FIX8_HAVE_GETOPT_LONG
194  option long_options[]
195  {
196  { "help", 0, 0, 'h' },
197  { "version", 0, 0, 'v' },
198  { "log", 1, 0, 'l' },
199  { "config", 1, 0, 'c' },
200  { "replay", 1, 0, 'p' },
201  { "server", 0, 0, 's' },
202  { "send", 1, 0, 'S' },
203  { "receive", 1, 0, 'R' },
204  { "lines", 1, 0, 'L' },
205  { "quiet", 0, 0, 'q' },
206  { "reliable", 0, 0, 'r' },
207  { 0 },
208  };
209 
210  while ((val = getopt_long (argc, argv, GETARGLIST.c_str(), long_options, 0)) != -1)
211 #else
212  while ((val = getopt (argc, argv, GETARGLIST.c_str())) != -1)
213 #endif
214  {
215  switch (val)
216  {
217  case 'v':
218  cout << argv[0] << " for " FIX8_PACKAGE " version " FIX8_VERSION << endl;
219  cout << "Released under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3. See <http://fsf.org/> for details." << endl;
220  return 0;
221  case ':': case '?': return 1;
222  case 'h': print_usage(); return 0;
223  case 'l': GlobalLogger::set_global_filename(optarg); break;
224  case 'p': replay_file = optarg; break;
225  case 'c': clcf = optarg; break;
226  case 's': server = true; break;
227  case 'S': next_send = stoul(optarg); break;
228  case 'R': next_receive = stoul(optarg); break;
229  case 'L': lines = stoul(optarg); break;
230  case 'q': quiet = true; break;
231  case 'r': reliable = 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  try
245  {
246  const string conf_file(server ? clcf.empty() ? "myfix_server.xml" : clcf : clcf.empty() ? "myfix_client.xml" : clcf);
247 
248  if (server)
249  {
250  unique_ptr<ServerSessionBase> ms(new ServerSession<myfix_session_server>(TEX::ctx(), conf_file, "TEX1"));
251 
252  for (unsigned scnt(0); !term_received; )
253  {
254  if (!ms->poll())
255  continue;
256  unique_ptr<FIX8::SessionInstanceBase> inst(ms->create_server_instance());
257  if (!quiet)
258  inst->session_ptr()->control() |= Session::printnohb;
259  glout_info << "client(" << ++scnt << ") connection established.";
260  inst->start(true, next_send, next_receive);
261  cout << "Session(" << scnt << ") finished." << endl;
262  inst->stop();
263  }
264  }
265  else
266  {
267  unique_ptr<ClientSessionBase>
268  mc(reliable ? new ReliableClientSession<myfix_session_client>(TEX::ctx(), conf_file, "DLD1")
269  : new ClientSession<myfix_session_client>(TEX::ctx(), conf_file, "DLD1"));
270  if (!quiet)
271  mc->session_ptr()->control() |= Session::printnohb;
272 
273  if (!reliable)
274  {
275  const LoginParameters& lparam(mc->session_ptr()->get_login_parameters());
276  mc->start(false, next_send, next_receive, lparam._davi());
277  }
278  else
279  mc->start(false);
280 
281  ConsoleMenu cm(TEX::ctx(), cin, cout, lines);
282  MyMenu mymenu(*mc->session_ptr(), 0, cout, &cm);
283  mymenu.get_tty().set_raw_mode();
285 
286  // permit replaying of test message sets
287  if (!replay_file.empty() && mymenu.load_msgs(replay_file))
288  mymenu.send_lst();
289 
290  for(; !term_received;)
291  {
292  cout << endl;
293  if (mymenu.get_msg_cnt())
294  cout << '[' << mymenu.get_msg_cnt() << "] msgs; ";
295  cout << "?=help > " << flush;
296  char ch{};
297  mymenu.get_istr().get(ch);
298  cout << ch << endl;
299  if (mymenu.get_istr().bad() || ch == 0x3 || !mymenu.process(ch))
300  break;
301  }
302 
303  mymenu.get_tty().unset_raw_mode();
304  }
305  }
306  catch (f8Exception& e)
307  {
308  cerr << "exception: " << e.what() << endl;
309  }
310  catch (exception& e) // also catches Poco::Net::NetException
311  {
312  cerr << "exception: " << e.what() << endl;
313  }
314 
315  if (term_received)
316  cout << "terminated." << endl;
317  return 0;
318 }
static void init()
Initialise the random number generator.
Definition: hftest.hpp:205
void print_usage()
Definition: harness.cpp:379
FIX8::tty_save_state & get_tty()
Definition: hftest.hpp:197
bool quiet(false)
#define FIX8_PACKAGE
Definition: f8config.h:601
Client wrapper.
unsigned next_receive(0)
unsigned next_send(0)
const F8MetaCntx & ctx()
Compiler generated metadata object, accessed through this function.
Base exception class.
Definition: f8exception.hpp:49
Console test harness menu.
Definition: consolemenu.hpp:48
const string GETARGLIST("hl:svqc:R:S:rp:L:")
#define glout_info
Definition: logger.hpp:601
Simple menu system that will work with most term types.
Definition: hftest.hpp:151
void sig_handler(int sig)
Definition: harness.cpp:160
bool term_received(false)
int hypersleep< h_seconds >(unsigned amt)
Definition: hypersleep.hpp:83
#define FIX8_VERSION
Definition: f8config.h:742
const char * what() const
Definition: f8exception.hpp:85
Reliable Client wrapper. This client attempts to recover from disconnects and login rejects...
void print_usage ( )

Definition at line 379 of file harness.cpp.

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

Referenced by main().

380 {
381  UsageMan um("harness", GETARGLIST, "");
382  um.setdesc("harness -- menu driven f8 test client/server");
383  um.add('s', "server", "run in server mode (default client mode)");
384  um.add('h', "help", "help, this screen");
385  um.add('v', "version", "print version then exit");
386  um.add('l', "log", "global log filename");
387  um.add('p', "replay", "name of fix input file to send on connect");
388  um.add('c', "config", "xml config (default: myfix_client.xml or myfix_server.xml)");
389  um.add('q', "quiet", "do not print fix output");
390  um.add('R', "receive", "set next expected receive sequence number");
391  um.add('L', "lines", "set number of screen lines in the console menu (default 50)");
392  um.add('S', "send", "set next send sequence number");
393  um.add('r', "reliable", "start in reliable mode");
394  um.print(cerr);
395 }
const string GETARGLIST("hl:svqc:R:S:rp:L:")
Convenient program help/usage wrapper. Generates a standardised usage message.
Definition: usage.hpp:42
bool quiet ( false  )

Referenced by main().

void sig_handler ( int  sig)

Definition at line 160 of file harness.cpp.

References term_received().

Referenced by main().

161 {
162  switch (sig)
163  {
164  case SIGTERM:
165  case SIGINT:
166 #ifndef _MSC_VER
167  case SIGQUIT:
168 #endif
169  term_received = true;
170  signal(sig, sig_handler);
171  break;
172  }
173 }
void sig_handler(int sig)
Definition: harness.cpp:160
bool term_received(false)
bool term_received ( false  )

Referenced by main(), and sig_handler().