fix8  version 1.4.0
Open Source C++ FIX Framework
hftest.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 "Perf_types.hpp"
#include "Perf_router.hpp"
#include "Perf_classes.hpp"
#include "hftest.hpp"

Go to the source code of this file.

Namespaces

 FIX8
 
 FIX8::TEX
 

Functions

void print_usage ()
 
const string GETARGLIST ("hl:svqc:R:S:rb:p:u:o")
 
bool term_received (false)
 
unsigned batch_size (1000)
 
unsigned preload_count (0)
 
unsigned update_count (5000)
 
bool quiet (true)
 
void sig_handler (int sig)
 
int main (int argc, char **argv)
 

Detailed Description


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

Usage: hftest [-RSchlqrsv]
-R,–receive set next expected receive sequence number
-S,–send set next send sequence number
-c,–config xml config (default: hf_client.xml or hf_server.xml)
-h,–help help, this screen
-l,–log global log filename
-q,–quiet do not print fix output
-u,–update update interval for console counters (default 5000)
-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:

% hftest -sl server

In another terminal session, start the client:

% hftest -l client

Notes

  1. Configure with –enable-codectiming
  2. The client has a simple menu. Press ? to see options.
  3. The server will wait for the client to logout before exiting.
  4. Press P to preload NewOrderSingle messages, T to transmit them.
  5. The server uses hf_client.xml and the client uses hf_server.xml for configuration settings.
  6. The example uses FIX42.xml

Definition in file hftest.cpp.

Function Documentation

unsigned batch_size ( 1000  )
const string GETARGLIST ( "hl:svqc:R:S:rb:p:u:o"  )

Referenced by main(), and print_usage().

int main ( int  argc,
char **  argv 
)

Definition at line 172 of file hftest.cpp.

References batch_size(), FIX8::TEX::ctx(), FIX8_PACKAGE, FIX8_VERSION, GETARGLIST(), RandDev::init(), FIX8::SingleLogger< fn >::log(), next_receive(), next_send(), FIX8::pm_coro, FIX8::pm_pipeline, preload_count(), MyMenu::preload_new_order_single(), FIX8::Session::print, print_usage(), quiet(), FIX8::SingleLogger< fn >::set_global_filename(), sig_handler(), term_received(), update_count(), and FIX8::f8Exception::what().

173 {
174  int val;
175  bool server(false), once(false), reliable(false);
176  string clcf;
177  unsigned next_send(0), next_receive(0);
178 
179 #ifdef FIX8_HAVE_GETOPT_LONG
180  option long_options[]
181  {
182  { "help", 0, 0, 'h' },
183  { "version", 0, 0, 'v' },
184  { "once", 0, 0, 'o' },
185  { "log", 1, 0, 'l' },
186  { "config", 1, 0, 'c' },
187  { "server", 0, 0, 's' },
188  { "batch", 1, 0, 'b' },
189  { "send", 1, 0, 'S' },
190  { "receive", 1, 0, 'R' },
191  { "quiet", 0, 0, 'q' },
192  { "reliable", 0, 0, 'r' },
193  { "preload", 1, 0, 'p' },
194  { "update", 1, 0, 'u' },
195  { 0 },
196  };
197 
198  while ((val = getopt_long (argc, argv, GETARGLIST.c_str(), long_options, 0)) != -1)
199 #else
200  while ((val = getopt (argc, argv, GETARGLIST.c_str())) != -1)
201 #endif
202  {
203  switch (val)
204  {
205  case 'v':
206  cout << argv[0] << " for " FIX8_PACKAGE " version " FIX8_VERSION << endl;
207  cout << "Released under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3. See <http://fsf.org/> for details." << endl;
208  return 0;
209  case ':': case '?': return 1;
210  case 'h': print_usage(); return 0;
211  case 'l': FIX8::GlobalLogger::set_global_filename(optarg); break;
212  case 'c': clcf = optarg; break;
213  case 'b': batch_size = stoul(optarg); break;
214  case 'p': preload_count = stoul(optarg); break;
215  case 'u': update_count = stoul(optarg); break;
216  case 's': server = true; break;
217  case 'o': once = true; break;
218  case 'S': next_send = stoul(optarg); break;
219  case 'R': next_receive = stoul(optarg); break;
220  case 'q': quiet = false; break;
221  case 'r': reliable = true; break;
222  default: break;
223  }
224  }
225 
226  RandDev::init();
227 
228  signal(SIGTERM, sig_handler);
229  signal(SIGINT, sig_handler);
230 #ifndef _MSC_VER
231  signal(SIGQUIT, sig_handler);
232 #endif
233 
234  try
235  {
236  const string conf_file(server ? clcf.empty() ? "hf_server.xml" : clcf : clcf.empty() ? "hf_client.xml" : clcf);
237 
238  if (server)
239  {
240  unique_ptr<FIX8::ServerSessionBase> ms(new FIX8::ServerSession<hf_session_server>(FIX8::TEX::ctx(), conf_file, "TEX1"));
241 
242  XmlElement::XmlSet eset;
243 
244  for (unsigned scnt(0); !term_received; )
245  {
246  if (!ms->poll())
247  continue;
248  unique_ptr<FIX8::SessionInstanceBase> inst(ms->create_server_instance());
249  if (!quiet)
250  inst->session_ptr()->control() |= FIX8::Session::print;
251  ostringstream sostr;
252  sostr << "client(" << ++scnt << ") connection established.";
253  FIX8::GlobalLogger::log(sostr.str());
254  const FIX8::ProcessModel pm(ms->get_process_model(ms->_ses));
255  inst->start(pm == FIX8::pm_pipeline, next_send, next_receive);
256  cout << (pm == FIX8::pm_pipeline ? "Pipelined" : "Threaded") << " mode." << endl;
257  if (inst->session_ptr()->get_connection()->is_secure())
258  cout << "Session is secure (SSL)" << endl;
259  if (pm != FIX8::pm_pipeline)
260  while (!inst->session_ptr()->is_shutdown())
261  FIX8::hypersleep<FIX8::h_milliseconds>(100);
262  cout << "Session(" << scnt << ") finished." << endl;
263  inst->stop();
264 #if defined FIX8_CODECTIMING
265  FIX8::Message::report_codec_timings("server");
266 #endif
267  if (once)
268  break;
269  }
270  }
271  else
272  {
273  unique_ptr<FIX8::ClientSessionBase>
274  mc(reliable ? new FIX8::ReliableClientSession<hf_session_client>(FIX8::TEX::ctx(), conf_file, "DLD1")
275  : new FIX8::ClientSession<hf_session_client>(FIX8::TEX::ctx(), conf_file, "DLD1"));
276  if (!quiet)
277  mc->session_ptr()->control() |= FIX8::Session::print;
278 
279  const FIX8::ProcessModel pm(mc->get_process_model(mc->_ses));
280  if (!reliable)
281  mc->start(false, next_send, next_receive, mc->session_ptr()->get_login_parameters()._davi());
282  else
283  mc->start(false, next_send, next_receive);
284 
285  MyMenu mymenu(*mc->session_ptr(), 0, cout);
286  cout << endl << "Menu started. Press '?' for help..." << endl << endl;
287  if (mc->session_ptr()->get_connection()->is_secure())
288  cout << "Session is secure (SSL)" << endl;
289  if (preload_count)
290  mymenu.preload_new_order_single();
291  char ch;
292  mymenu.get_tty().set_raw_mode();
293  if (pm == FIX8::pm_coro)
294  {
295  cout << "Coroutine mode." << endl;
296  fd_set rfds;
297  timeval tv {};
298 
299  while (!term_received)
300  {
301  mc->session_ptr()->get_connection()->reader_execute();
302  char ch(0);
303  FD_ZERO(&rfds);
304  FD_SET(0, &rfds);
305 #ifdef _MSC_VER
306  if (kbhit())
307  {
308  ch = getch();
309 #else
310  if (select(1, &rfds, 0, 0, &tv) > 0)
311  {
312  if (read (0, &ch, 1) < 0)
313  break;
314 #endif
315  if (ch == 'a')
316  {
317  cout << "Sending messages..." << endl;
318  coroutine coro;
319  while(mymenu.send_all_preloaded(coro, mc->session_ptr()))
320  mc->session_ptr()->get_connection()->reader_execute();
321  }
322  else if (ch == 0x3 || !mymenu.process(ch))
323  break;
324  }
325  }
326  }
327  else
328  {
329  cout << (pm == FIX8::pm_pipeline ? "Pipelined" : "Threaded") << " mode." << endl;
330  while(!mymenu.get_istr().get(ch).bad() && !term_received && ch != 0x3 && mymenu.process(ch))
331  ;
332  }
333  cout << endl;
334 #if defined FIX8_CODECTIMING
335  FIX8::Message::report_codec_timings("client");
336 #endif
337  if (!mc->session_ptr()->is_shutdown())
338  mc->session_ptr()->stop();
339 
340  mymenu.get_tty().unset_raw_mode();
341  }
342  }
343  catch (FIX8::f8Exception& e)
344  {
345  cerr << "exception: " << e.what() << endl;
346  }
347  catch (exception& e) // also catches Poco::Net::NetException
348  {
349  cerr << "exception: " << e.what() << endl;
350  }
351 
352  if (term_received)
353  cout << "terminated." << endl;
354  return 0;
355 }
void sig_handler(int sig)
Definition: hftest.cpp:153
static void init()
Initialise the random number generator.
Definition: hftest.hpp:205
unsigned preload_count(0)
bool preload_new_order_single()
Definition: hftest.cpp:491
const string GETARGLIST("hl:svqc:R:S:rb:p:u:o")
#define FIX8_PACKAGE
Definition: f8config.h:601
Client wrapper.
ProcessModel
Supported session process models.
Definition: f8types.hpp:56
unsigned next_receive(0)
void print_usage()
Definition: hftest.cpp:557
unsigned next_send(0)
bool term_received(false)
const F8MetaCntx & ctx()
Compiler generated metadata object, accessed through this function.
Base exception class.
Definition: f8exception.hpp:49
bool quiet(true)
std::set< const XmlElement *, EntityOrderComp > XmlSet
Definition: xml.hpp:74
Simple menu system that will work with most term types.
Definition: hftest.hpp:151
unsigned update_count(5000)
static void set_global_filename(const std::string &from)
Definition: logger.hpp:492
#define FIX8_VERSION
Definition: f8config.h:742
const char * what() const
Definition: f8exception.hpp:85
unsigned batch_size(1000)
static bool log(const std::string &what, Logger::Level lev=Logger::Info, const char *fl=nullptr, unsigned int val=0)
Definition: logger.hpp:501
Reliable Client wrapper. This client attempts to recover from disconnects and login rejects...
unsigned preload_count ( )
void print_usage ( )

Definition at line 557 of file hftest.cpp.

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

Referenced by main().

558 {
559  UsageMan um("hftest", GETARGLIST, "");
560  um.setdesc("hftest -- f8 HF test client/server");
561  um.add('s', "server", "run in server mode (default client mode)");
562  um.add('h', "help", "help, this screen");
563  um.add('v', "version", "print version then exit");
564  um.add('l', "log", "global log filename");
565  um.add('c', "config", "xml config (default: hf_client.xml or hf_server.xml)");
566  um.add('o', "once", "for server, allow one client session then exit");
567  um.add('q', "quiet", "do not print fix output (default yes)");
568  um.add('b', "batch", "if using batch send, number of messages in each batch (default 1000)");
569  um.add('p', "preload", "if batching or preloading, default number of messages to create");
570  um.add('R', "receive", "set next expected receive sequence number");
571  um.add('S', "send", "set next send sequence number");
572  um.add('r', "reliable", "start in reliable mode");
573  um.add('u', "update", "message count update frequency (default 5000)");
574  um.print(cerr);
575 }
const string GETARGLIST("hl:svqc:R:S:rb:p:u:o")
Convenient program help/usage wrapper. Generates a standardised usage message.
Definition: usage.hpp:42
bool quiet ( true  )

Referenced by main().

void sig_handler ( int  sig)

Definition at line 153 of file hftest.cpp.

References term_received().

Referenced by main().

154 {
155  switch (sig)
156  {
157  case SIGTERM:
158  case SIGINT:
159 #ifndef _MSC_VER
160  case SIGQUIT:
161 #endif
162  term_received = true;
163  signal(sig, sig_handler);
164  break;
165  default:
166  cerr << sig << endl;
167  break;
168  }
169 }
void sig_handler(int sig)
Definition: hftest.cpp:153
bool term_received(false)
bool term_received ( false  )

Referenced by main(), and sig_handler().

unsigned update_count ( 5000  )