TvlSim Logo  1.00.0
C++ Simulated Travel-Oriented Distribution System Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TvlSimServer.cpp
Go to the documentation of this file.
1 
5 // //////////////////////////////////////////////////////////////////////
6 // Import section
7 // //////////////////////////////////////////////////////////////////////
8 // STL
9 #include <cassert>
10 #include <sstream>
11 #include <fstream>
12 #include <string>
13 #include <unistd.h>
14 // Boost (Extended STL)
15 #include <boost/program_options.hpp>
16 #include <boost/tokenizer.hpp>
17 // ZeroMQ
18 #include <zmq.hpp>
19 // StdAir
20 #include <stdair/stdair_basic_types.hpp>
21 #include <stdair/stdair_json.hpp>
22 #include <stdair/basic/BasConst_General.hpp>
23 #include <stdair/basic/BasLogParams.hpp>
24 #include <stdair/basic/BasDBParams.hpp>
25 #include <stdair/basic/DemandGenerationMethod.hpp>
26 #include <stdair/service/Logger.hpp>
27 // TvlSim
28 #include <tvlsim/config/tvlsim-paths.hpp>
30 
31 // ///////// Type definitions //////////
35 typedef unsigned int NbOfRuns_T;
36 
40 typedef std::vector<std::string> WordList_T;
41 
45 typedef unsigned int ServerPort_T;
46 
47 // //////// Constants //////
51 const std::string K_TVLSIM_DEFAULT_LOG_FILENAME ("tvlsimServer.log");
52 
56 const std::string K_TVLSIM_DEFAULT_SERVER_PROTOCOL ("tcp://");
57 
61 const std::string K_TVLSIM_DEFAULT_SERVER_ADDRESS ("*");
62 
66 const ServerPort_T K_TVLSIM_DEFAULT_SERVER_PORT (5555);
67 
72  "/rds01/schedule05.csv");
73 
78  "/ond01.csv");
79 
84  "/frat5.csv");
89  "/ffDisutility.csv");
90 
95  "/rds01/yield.csv");
96 
101  "/rds01/fare.csv");
102 
107  "/rds01/demand05.csv");
108 
113 
117 const stdair::RandomSeed_T K_TRADEMGEN_DEFAULT_RANDOM_SEED =
118  stdair::DEFAULT_RANDOM_SEED;
119 
124 
130 const bool K_TVLSIM_DEFAULT_BUILT_IN_INPUT = false;
131 
135 const int K_TVLSIM_EARLY_RETURN_STATUS = 99;
136 
140 const std::string K_TVLSIM_DEFAULT_QUERY_STRING ("my good old query");
141 
145 const std::string K_TVLSIM_DEFAULT_DB_USER ("tvlsim");
146 const std::string K_TVLSIM_DEFAULT_DB_PASSWD ("tvlsim");
147 const std::string K_TVLSIM_DEFAULT_DB_DBNAME ("sim_tvlsim");
148 const std::string K_TVLSIM_DEFAULT_DB_HOST ("localhost");
149 const std::string K_TVLSIM_DEFAULT_DB_PORT ("3306");
150 
151 // //////////////////////////////////////////////////////////////////////
152 void tokeniseStringIntoWordList (const std::string& iPhrase,
153  WordList_T& ioWordList) {
154  // Empty the word list
155  ioWordList.clear();
156 
157  // Boost Tokeniser
158  typedef boost::tokenizer<boost::char_separator<char> > Tokeniser_T;
159 
160  // Define the separators
161  const boost::char_separator<char> lSepatorList(" .,;:|+-*/_=!@#$%`~^&(){}[]?'<>\"");
162 
163  // Initialise the phrase to be tokenised
164  Tokeniser_T lTokens (iPhrase, lSepatorList);
165  for (Tokeniser_T::const_iterator tok_iter = lTokens.begin();
166  tok_iter != lTokens.end(); ++tok_iter) {
167  const std::string& lTerm = *tok_iter;
168  ioWordList.push_back (lTerm);
169  }
170 
171 }
172 
173 // //////////////////////////////////////////////////////////////////////
174 std::string createStringFromWordList (const WordList_T& iWordList) {
175  std::ostringstream oStr;
176 
177  unsigned short idx = iWordList.size();
178  for (WordList_T::const_iterator itWord = iWordList.begin();
179  itWord != iWordList.end(); ++itWord, --idx) {
180  const std::string& lWord = *itWord;
181  oStr << lWord;
182  if (idx > 1) {
183  oStr << " ";
184  }
185  }
186 
187  return oStr.str();
188 }
189 
190 // ///////// Parsing of Options & Configuration /////////
191 // A helper function to simplify the main part.
192 template<class T> std::ostream& operator<< (std::ostream& os,
193  const std::vector<T>& v) {
194  std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
195  return os;
196 }
197 
198 // ///////// Parsing of Options & Configuration /////////
200 int readConfiguration (int argc, char* argv[], std::string& ioServerProtocol,
201  std::string& ioServerAddress, ServerPort_T& ioServerPort,
202  bool& ioIsBuiltin, stdair::RandomSeed_T& ioRandomSeed,
203  NbOfRuns_T& ioRandomRuns, std::string& ioQueryString,
204  stdair::Filename_T& ioScheduleInputFilename,
205  stdair::Filename_T& ioOnDInputFilename,
206  stdair::Filename_T& ioFRAT5Filename,
207  stdair::Filename_T& ioFFDisutilityFilename,
208  stdair::Filename_T& ioYieldInputFilename,
209  stdair::Filename_T& ioFareInputFilename,
210  stdair::Filename_T& ioDemandInputFilename,
211  std::string& ioLogFilename,
212  stdair::DemandGenerationMethod& ioDemandGenerationMethod,
213  std::string& ioDBUser, std::string& ioDBPasswd,
214  std::string& ioDBHost, std::string& ioDBPort,
215  std::string& ioDBDBName) {
216 
217  // Demand generation method as a single char (e.g., 'P' or 'S').
218  char lDemandGenerationMethodChar;
219 
220  // Default for the built-in input
221  ioIsBuiltin = K_TVLSIM_DEFAULT_BUILT_IN_INPUT;
222 
223  // Initialise the travel query string, if that one is empty
224  if (ioQueryString.empty() == true) {
225  ioQueryString = K_TVLSIM_DEFAULT_QUERY_STRING;
226  }
227 
228  // Transform the query string into a list of words (STL strings)
229  WordList_T lWordList;
230  tokeniseStringIntoWordList (ioQueryString, lWordList);
231 
232  // Declare a group of options that will be allowed only on command line
233  boost::program_options::options_description generic ("Generic options");
234  generic.add_options()
235  ("prefix", "print installation prefix")
236  ("version,v", "print version string")
237  ("help,h", "produce help message");
238 
239  // Declare a group of options that will be allowed both on command
240  // line and in config file
241 
242  boost::program_options::options_description config ("Configuration");
243  config.add_options()
244  ("builtin,b",
245  "The sample BOM tree can be either built-in or parsed from input files. In that latter case, the input files must be specified as well (e.g., -d/--demand, -s/--schedule, -o/--ond, -f/--fare, -y/--yield)")
246  ("seed,S",
247  boost::program_options::value<stdair::RandomSeed_T>(&ioRandomSeed)->default_value(K_TRADEMGEN_DEFAULT_RANDOM_SEED),
248  "Seed for the random generation")
249  ("runs,r",
250  boost::program_options::value<NbOfRuns_T>(&ioRandomRuns)->default_value(K_TRADEMGEN_DEFAULT_RANDOM_DRAWS),
251  "Number of simulation runs")
252  ("schedule,s",
253  boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_TVLSIM_DEFAULT_SCHEDULE_INPUT_FILENAME),
254  "(CSV) input file for the schedules")
255  ("ond,o",
256  boost::program_options::value< std::string >(&ioOnDInputFilename)->default_value(K_TVLSIM_DEFAULT_OND_INPUT_FILENAME),
257  "(CSV) input file for the O&D definitions")
258  ("frat5,r",
259  boost::program_options::value< std::string >(&ioFRAT5Filename)->default_value(K_TVLSIM_DEFAULT_FRAT5_INPUT_FILENAME),
260  "(CSV) input file for the FRAT5 Curve")
261  ("ff_disutility,d",
262  boost::program_options::value< std::string >(&ioFFDisutilityFilename)->default_value(K_TVLSIM_DEFAULT_FF_DISUTILITY_INPUT_FILENAME),
263  "(CSV) input file for the FF disutility Curve")
264  ("yield,y",
265  boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_TVLSIM_DEFAULT_YIELD_INPUT_FILENAME),
266  "(CSV) input file for the yields")
267  ("fare,f",
268  boost::program_options::value< std::string >(&ioFareInputFilename)->default_value(K_TVLSIM_DEFAULT_FARE_INPUT_FILENAME),
269  "(CSV) input file for the fares")
270  ("demand,d",
271  boost::program_options::value< std::string >(&ioDemandInputFilename)->default_value(K_TVLSIM_DEFAULT_DEMAND_INPUT_FILENAME),
272  "(CSV) input file for the demand distributions")
273  ("protocol,t",
274  boost::program_options::value< std::string >(&ioServerProtocol)->default_value(K_TVLSIM_DEFAULT_SERVER_PROTOCOL),
275  "Server protocol")
276  ("address,a",
277  boost::program_options::value< std::string >(&ioServerAddress)->default_value(K_TVLSIM_DEFAULT_SERVER_ADDRESS),
278  "Server address")
279  ("port,p",
280  boost::program_options::value< ServerPort_T >(&ioServerPort)->default_value(K_TVLSIM_DEFAULT_SERVER_PORT),
281  "Server port")
282  ("log,l",
283  boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_TVLSIM_DEFAULT_LOG_FILENAME),
284  "Filepath for the logs")
285  ("demandgeneration,G",
286  boost::program_options::value< char >(&lDemandGenerationMethodChar)->default_value(K_TVLSIM_DEMAND_GENERATION_METHOD_CHAR),
287  "Method used to generate the demand (i.e., booking requests): Poisson Process (e.g., P) or Statistics Order (e.g., S)")
288  ("user,u",
289  boost::program_options::value< std::string >(&ioDBUser)->default_value(K_TVLSIM_DEFAULT_DB_USER),
290  "SQL database hostname (e.g., tvlsim)")
291  ("passwd,w",
292  boost::program_options::value< std::string >(&ioDBPasswd)->default_value(K_TVLSIM_DEFAULT_DB_PASSWD),
293  "SQL database hostname (e.g., tvlsim)")
294  ("host,H",
295  boost::program_options::value< std::string >(&ioDBHost)->default_value(K_TVLSIM_DEFAULT_DB_HOST),
296  "SQL database hostname (e.g., localhost)")
297  ("dbport,P",
298  boost::program_options::value< std::string >(&ioDBPort)->default_value(K_TVLSIM_DEFAULT_DB_PORT),
299  "SQL database port (e.g., 3306)")
300  ("dbname,n",
301  boost::program_options::value< std::string >(&ioDBDBName)->default_value(K_TVLSIM_DEFAULT_DB_DBNAME),
302  "SQL database name (e.g., tvlsim)")
303  ("query,q",
304  boost::program_options::value< WordList_T >(&lWordList)->multitoken(),
305  "Query word list")
306  ;
307 
308  // Hidden options, will be allowed both on command line and
309  // in config file, but will not be shown to the user.
310  boost::program_options::options_description hidden ("Hidden options");
311  hidden.add_options()
312  ("copyright",
313  boost::program_options::value< std::vector<std::string> >(),
314  "Show the copyright (license)");
315 
316  boost::program_options::options_description cmdline_options;
317  cmdline_options.add(generic).add(config).add(hidden);
318 
319  boost::program_options::options_description config_file_options;
320  config_file_options.add(config).add(hidden);
321 
322  boost::program_options::options_description visible ("Allowed options");
323  visible.add(generic).add(config);
324 
325  boost::program_options::positional_options_description p;
326  p.add ("copyright", -1);
327 
328  boost::program_options::variables_map vm;
329  boost::program_options::
330  store (boost::program_options::command_line_parser (argc, argv).
331  options (cmdline_options).positional(p).run(), vm);
332 
333  std::ifstream ifs ("simulate.cfg");
334  boost::program_options::store (parse_config_file (ifs, config_file_options),
335  vm);
336  boost::program_options::notify (vm);
337 
338  if (vm.count ("help")) {
339  std::cout << visible << std::endl;
341  }
342 
343  if (vm.count ("version")) {
344  std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
346  }
347 
348  if (vm.count ("prefix")) {
349  std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
351  }
352 
353  if (vm.count ("protocol")) {
354  ioServerProtocol = vm["protocol"].as< std::string >();
355  std::cout << "Server protocol is: " << ioServerProtocol << std::endl;
356  }
357 
358  if (vm.count ("address")) {
359  ioServerAddress = vm["address"].as< std::string >();
360  std::cout << "Server address is: " << ioServerAddress << std::endl;
361  }
362 
363  if (vm.count ("port")) {
364  ioServerPort = vm["port"].as< ServerPort_T >();
365  std::cout << "Server port is: " << ioServerPort << std::endl;
366  }
367 
368  if (vm.count ("builtin")) {
369  ioIsBuiltin = true;
370  }
371  const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
372  std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
373 
374  //
375  std::ostringstream oErrorMessageStr;
376  oErrorMessageStr << "Either the -b/--builtin option, or the combination of "
377  << "the -d/--demand, -s/--schedule, -o/--ond, -f/--fare "
378  << "and -y/--yield options must be specified";
379 
380  if (ioIsBuiltin == false) {
381  if (vm.count ("schedule")) {
382  ioScheduleInputFilename = vm["schedule"].as< std::string >();
383  std::cout << "Schedule input filename is: " << ioScheduleInputFilename
384  << std::endl;
385 
386  } else {
387  // The built-in option is not selected. However, no schedule input file
388  // is specified
389  std::cerr << oErrorMessageStr.str() << std::endl;
390  }
391 
392  if (vm.count ("ond")) {
393  ioOnDInputFilename = vm["ond"].as< std::string >();
394  std::cout << "O&D input filename is: " << ioOnDInputFilename << std::endl;
395 
396  } else {
397  // The built-in option is not selected. However, no schedule input file
398  // is specified
399  std::cerr << oErrorMessageStr.str() << std::endl;
400  }
401 
402  if (vm.count ("frat5")) {
403  ioFRAT5Filename = vm["frat5"].as< std::string >();
404  std::cout << "FRAT5 input filename is: " << ioFRAT5Filename << std::endl;
405 
406  } else {
407  // The built-in option is not selected. However, no frat5 input file
408  // is specified
409  std::cerr << oErrorMessageStr.str() << std::endl;
410  }
411 
412  if (vm.count ("ff_disutility")) {
413  ioFFDisutilityFilename = vm["ff_disutility"].as< std::string >();
414  std::cout << "FF disutility input filename is: "
415  << ioFFDisutilityFilename << std::endl;
416 
417  } else {
418  // The built-in option is not selected. However, no ff
419  // disutility input file is specified
420  std::cerr << oErrorMessageStr.str() << std::endl;
421  }
422 
423  if (vm.count ("yield")) {
424  ioYieldInputFilename = vm["yield"].as< std::string >();
425  std::cout << "Yield input filename is: " << ioYieldInputFilename << std::endl;
426 
427  } else {
428  // The built-in option is not selected. However, no schedule input file
429  // is specified
430  std::cerr << oErrorMessageStr.str() << std::endl;
431  }
432 
433  if (vm.count ("fare")) {
434  ioFareInputFilename = vm["fare"].as< std::string >();
435  std::cout << "Fare input filename is: " << ioFareInputFilename << std::endl;
436 
437  } else {
438  // The built-in option is not selected. However, no schedule input file
439  // is specified
440  std::cerr << oErrorMessageStr.str() << std::endl;
441  }
442 
443  if (vm.count ("demand")) {
444  ioDemandInputFilename = vm["demand"].as< std::string >();
445  std::cout << "Demand input filename is: " << ioDemandInputFilename
446  << std::endl;
447  } else {
448  // The built-in option is not selected. However, no schedule input file
449  // is specified
450  std::cerr << oErrorMessageStr.str() << std::endl;
451  }
452  }
453 
454  if (vm.count ("log")) {
455  ioLogFilename = vm["log"].as< std::string >();
456  std::cout << "Log filename is: " << ioLogFilename << std::endl;
457  }
458 
459  //
460  if (vm.count ("demandgeneration")) {
461  ioDemandGenerationMethod =
462  stdair::DemandGenerationMethod (lDemandGenerationMethodChar);
463  std::cout << "Demand generation method is: "
464  << ioDemandGenerationMethod.describe() << std::endl;
465  }
466 
467  //
468  std::cout << "The random generation seed is: " << ioRandomSeed << std::endl;
469 
470  //
471  std::cout << "The number of simulation runs is: " << ioRandomRuns
472  << std::endl;
473 
474  //
475  if (vm.count ("user")) {
476  ioDBUser = vm["user"].as< std::string >();
477  std::cout << "SQL database user name is: " << ioDBUser << std::endl;
478  }
479 
480  if (vm.count ("passwd")) {
481  ioDBPasswd = vm["passwd"].as< std::string >();
482  //std::cout << "SQL database user password is: " << ioDBPasswd << std::endl;
483  }
484 
485  if (vm.count ("host")) {
486  ioDBHost = vm["host"].as< std::string >();
487  std::cout << "SQL database host name is: " << ioDBHost << std::endl;
488  }
489 
490  if (vm.count ("dbport")) {
491  ioDBPort = vm["dbport"].as< std::string >();
492  std::cout << "SQL database port number is: " << ioDBPort << std::endl;
493  }
494 
495  if (vm.count ("dbname")) {
496  ioDBDBName = vm["dbname"].as< std::string >();
497  std::cout << "SQL database name is: " << ioDBDBName << std::endl;
498  }
499 
500  //
501  ioQueryString = createStringFromWordList (lWordList);
502  std::cout << "The query string is: " << ioQueryString << std::endl;
503 
504  return 0;
505 }
506 
507 
508 // ///////// Utility functions on top of the ZeroMQ library /////////
512 static std::string s_recv (zmq::socket_t& socket) {
513  zmq::message_t message;
514  socket.recv (&message);
515 
516  return std::string (static_cast<char*> (message.data()), message.size());
517 }
518 
522 static bool s_send (zmq::socket_t& socket, const std::string& string) {
523  zmq::message_t message (string.size());
524  memcpy (message.data(), string.data(), string.size());
525 
526  bool rc = socket.send (message);
527  return rc;
528 }
529 
530 
531 // /////////////////////// M A I N ////////////////////////
532 int main (int argc, char* argv[]) {
533 
534  // Server parameters (for ZeroMQ)
535  std::string ioServerProtocol;
536  std::string ioServerAddress;
537  ServerPort_T ioServerPort;
538 
539  // State whether the BOM tree should be built-in or parsed from an
540  // input file
541  bool isBuiltin;
542 
543  // Random generation seed
544  stdair::RandomSeed_T lRandomSeed;
545 
546  // Number of simulation runs to be performed
547  NbOfRuns_T lNbOfRuns;
548 
549  // Query
550  std::string lQuery;
551 
552  // Start date
553  stdair::Date_T lStartDate (2009, boost::gregorian::Feb, 01);
554 
555  // End date
556  stdair::Date_T lEndDate (2012, boost::gregorian::Mar, 02);
557 
558  // Schedule input file name
559  stdair::Filename_T lScheduleInputFilename;
560 
561  // O&D input filename
562  std::string lOnDInputFilename;
563 
564  // FRAT5 input filename
565  std::string lFRAT5InputFilename;
566 
567  // FF disutility input filename
568  std::string lFFDisutilityInputFilename;
569 
570  // Yield input filename
571  std::string lYieldInputFilename;
572 
573  // Fare input filename
574  std::string lFareInputFilename;
575 
576  // Demand input file name
577  stdair::Filename_T lDemandInputFilename;
578 
579  // Output log File
580  std::string lLogFilename;
581 
582  // Demand generation method.
583  stdair::DemandGenerationMethod
584  lDemandGenerationMethod (K_TVLSIM_DEMAND_GENERATION_METHOD_CHAR);
585 
586  // SQL database parameters
587  std::string lDBUser;
588  std::string lDBPasswd;
589  std::string lDBHost;
590  std::string lDBPort;
591  std::string lDBDBName;
592 
593  // Call the command-line option parser
594  const int lOptionParserStatus =
595  readConfiguration (argc, argv, ioServerProtocol, ioServerAddress,
596  ioServerPort, isBuiltin, lRandomSeed, lNbOfRuns, lQuery,
597  lScheduleInputFilename, lOnDInputFilename,
598  lFRAT5InputFilename, lFFDisutilityInputFilename,
599  lYieldInputFilename, lFareInputFilename,
600  lDemandInputFilename, lLogFilename,
601  lDemandGenerationMethod,
602  lDBUser, lDBPasswd, lDBHost, lDBPort, lDBDBName);
603 
604  if (lOptionParserStatus == K_TVLSIM_EARLY_RETURN_STATUS) {
605  return 0;
606  }
607 
608  // Set the database parameters
609  stdair::BasDBParams lDBParams (lDBUser, lDBPasswd, lDBHost, lDBPort,
610  lDBDBName);
611 
612  // Set the log parameters
613  std::ofstream logOutputFile;
614  // Open and clean the log outputfile
615  logOutputFile.open (lLogFilename.c_str());
616  logOutputFile.clear();
617 
618  // Initialise the simulation context
619  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
620  TVLSIM::TVLSIM_Service tvlsimService (lLogParams, lDBParams, lStartDate, lEndDate,
621  lRandomSeed, lDemandGenerationMethod,
622  lNbOfRuns);
623 
624  // DEBUG
625  STDAIR_LOG_DEBUG ("Initialisation of the TvlSim server");
626 
627  // Check wether or not a (CSV) input file should be read
628  if (isBuiltin == true) {
629 
630  // Build the sample BOM tree
631  tvlsimService.buildSampleBom();
632 
633  } else {
634 
635  // Build the BOM tree from parsing input files
636  stdair::ScheduleFilePath lScheduleFilePath (lScheduleInputFilename);
637  stdair::ODFilePath lODFilePath (lOnDInputFilename);
638  stdair::FRAT5FilePath lFRAT5FilePath (lFRAT5InputFilename);
639  stdair::FFDisutilityFilePath lFFDisutilityFilePath (lFFDisutilityInputFilename);
640  const SIMFQT::FareFilePath lFareFilePath (lFareInputFilename);
641  const AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename);
642  const TRADEMGEN::DemandFilePath lDemandFilePath (lDemandInputFilename);
643  tvlsimService.setInputFiles (lScheduleFilePath, lODFilePath,
644  lFRAT5FilePath, lFFDisutilityFilePath,
645  lYieldFilePath, lFareFilePath,
646  lDemandFilePath);
647  tvlsimService.parseAndLoad ();
648 
649  }
650 
651  // Initialise the snapshot and RM events
652  tvlsimService.initSnapshotAndRMEvents();
653 
654  // Build the connection string (e.g., "tcp://*:5555", which is the default)
655  std::ostringstream oZeroMQBindStream;
656  oZeroMQBindStream << ioServerProtocol << ioServerAddress
657  << ":" << ioServerPort;
658  const std::string lZeroMQBindString (oZeroMQBindStream.str());
659 
660  // Prepare the context and socket of the server
661  zmq::context_t context (1);
662  zmq::socket_t socket (context, ZMQ_REP);
663  socket.bind (lZeroMQBindString.c_str());
664 
665  // DEBUG
666  STDAIR_LOG_DEBUG ("The TvlSim server is ready to receive requests...");
667 
668  while (true) {
669 
670  // Wait for next request from client, which is expected to give
671  // a JSON-ified command.
672  const std::string& lReceivedString = s_recv (socket);
673 
674  // DEBUG
675  STDAIR_LOG_DEBUG ("Received: '" << lReceivedString << "'");
676 
677  const stdair::JSONString lJSONCommandString (lReceivedString);
678  const std::string& lJSONDump =
679  tvlsimService.jsonHandler (lJSONCommandString);
680 
681  // DEBUG
682  STDAIR_LOG_DEBUG ("Send: '" << lJSONDump << "'");
683 
684  // Send back the answer details to the client
685  s_send (socket, lJSONDump);
686  }
687 
688  return 0;
689 }
690