llfix
Low-latency FIX engine
engine.h
1 // DISCLAIMER_PLACEHOLDER
2 #pragma once
3 
4 #include "common.h"
5 
6 #include <atomic>
7 #include <cstdint>
8 #include <cstdlib>
9 #include <cstdio>
10 #include <filesystem>
11 
12 #include "core/os/vdso.h"
13 #include "core/os/process_utilities.h"
14 #include "core/os/thread_local_storage.h"
15 #include "core/os/hangup_signal_handler.h"
16 #include "core/os/virtual_memory.h"
17 
18 #ifdef LLFIX_ENABLE_NUMA // VOLTRON_EXCLUDE
19 #include "core/os/numa_utilities.h"
20 #endif // VOLTRON_EXCLUDE
21 
22 #ifdef LLFIX_ENABLE_TCPDIRECT // VOLTRON_EXCLUDE
23 #include "core/solarflare_tcpdirect/tcpdirect_api.h"
24 #endif // VOLTRON_EXCLUDE
25 
26 #ifdef LLFIX_ENABLE_OPENSSL // VOLTRON_EXCLUDE
27 #include "core/ssl/ssl_api.h"
28 #endif // VOLTRON_EXCLUDE
29 
30 #include "core/os/socket.h"
31 #include "core/utilities/logger.h"
32 #include "core/utilities/version.h"
33 #include "core/utilities/allocator.h"
34 
35 #include "engine_settings.h"
36 
37 #include "management_server/management_server_settings.h"
38 #include "management_server/management_server.h"
39 
40 namespace llfix
41 {
42 
49 class Engine
50 {
51  public:
52 
62  static void on_start(const std::string& config_file_path = "", const std::string& config_group_name ="ENGINE")
63  {
64  if(m_engine_initialised.load() == true)
65  {
66  return;
67  }
68 
69  #ifdef __linux__
70  if(ProcessUtilities::has_root_privileges() == false)
71  {
72  fprintf(stderr, "llfix engine : Requires root privileges on Linux.\n");
73  std::exit(-1);
74  }
75  #endif
76 
77  m_application_start_timestamp = VDSO::nanoseconds_monotonic();
78 
79  EngineSettings engine_settings;
80 
81  if(config_file_path.length()>0)
82  {
83  if(engine_settings.load_from_config_file(config_file_path, config_group_name) == false)
84  {
85  fprintf(stderr, "Failed to load %s : %s \n", config_file_path.c_str(), engine_settings.config_load_error.c_str());
86  std::exit(-2);
87  }
88  }
89 
90  if(engine_settings.validate() == false)
91  {
92  fprintf(stderr, "llfix engine : Failed to verify %s : %s \n", config_file_path.c_str(), engine_settings.validation_error.c_str());
93  std::exit(-3);
94  }
95 
96  HangupSignalHandler::set_ignore(engine_settings.ignore_sighup);
97 
98  if( Logger<>::get_instance().initialise(engine_settings.log_file, Logger<>::convert_string_to_log_level(engine_settings.log_level), engine_settings.logger_async, engine_settings.logger_buffer_capacity) == false)
99  {
100  fprintf(stderr, "llfix engine : Logger initialisation failed\n");
101  std::exit(-4);
102  }
103 
104  if(engine_settings.numa_bind_node >= 0)
105  {
106  #ifdef _WIN32
107  fprintf(stderr, "WARNING : numa_bind_node is specified however NUMA features supported only on Linux.\n");
108  #elif __linux__
109  #ifdef LLFIX_ENABLE_NUMA
110  if(NumaUtilities::get_current_numa_node() == -1)
111  {
112  fprintf(stderr, "WARNING : numa_bind_node is set however there is no NUMA node on the system, therefore it won't take affect\n");
113  }
114  else
115  {
116  if( NumaUtilities::bind_to_numa_node(engine_settings.numa_bind_node) == false)
117  {
118  fprintf(stderr, "llfix engine : Failed to bind to NUMA node %d \n", engine_settings.numa_bind_node);
119  std::exit(-5);
120  }
121 
122  LLFIX_LOG_INFO("Bound NUMA node : " + std::to_string(NumaUtilities::get_current_numa_node()));
123  Allocator::set_numa_aware(engine_settings.numa_aware_allocations);
124  }
125  #else
126  fprintf(stderr, "WARNING : numa_bind_node is set however this build not built with LLFIX_ENABLE_NUMA flag, therefore it won't take affect\n");
127  #endif
128  #endif
129  }
130 
131  if(engine_settings.lock_pages)
132  {
133  #ifdef __linux__
134  auto page_lock_success = VirtualMemory::lock_all_pages();
135  LLFIX_LOG_INFO("VM pages locked : " + std::string( (page_lock_success?"1":"0") ));
136  #endif
137  }
138 
139  if (ThreadLocalStorage::get_instance().create() == false)
140  {
141  LLFIX_LOG_ERROR("Failed to create thread local storage");
142  std::exit(-5);
143  }
144 
145  Socket<>::socket_library_initialise();
146 
147  ManagementServerSettings management_server_settings;
148 
149  if (management_server_settings.specified_by_user(config_file_path, config_group_name))
150  {
151  if (management_server_settings.load_from_config_file(config_file_path, config_group_name) == true)
152  {
153  if (management_server_settings.validate() == true)
154  {
155  std::filesystem::path cwd = std::filesystem::current_path();
156  std::filesystem::path full_log_path = cwd / engine_settings.log_file;
157 
158  if (m_management_server.create(management_server_settings, m_application_start_timestamp, m_version.to_string(), full_log_path.string()))
159  {
160  m_management_server_started = true;
161  LLFIX_LOG_INFO("Started management server , port : " + std::to_string(management_server_settings.management_server_port) + " nic : " + management_server_settings.management_server_nic_ip);
162  }
163  else
164  {
165  LLFIX_LOG_ERROR("Failed to create management server");
166  }
167  }
168  else
169  {
170  LLFIX_LOG_ERROR("Failed to validate management server settings. Error : " + management_server_settings.validation_error);
171  }
172  }
173  }
174 
175  LLFIX_LOG_INFO("LLFIX ENGINE Loaded config =>\n" + engine_settings.to_string());
176 
177  #ifndef LLFIX_BUILD_CONFIG_GENERATED
178  LLFIX_LOG_INFO("LLFIX ENGINE LIBRARY TYPE=HEADER-ONLY , version : " + m_version.to_string());
179  #else
180  LLFIX_LOG_INFO("LLFIX ENGINE LIBRARY TYPE=STATIC-LIB , version : " + m_version.to_string());
181  #endif
182 
183  #ifdef LLFIX_ENABLE_TCPDIRECT
184  LLFIX_LOG_INFO("LLFIX ENGINE TCPDIRECT=ON , TCPDirect library version : " + std::string(TCPDirectApi::get_version()));
185  #else
186  LLFIX_LOG_INFO("LLFIX ENGINE TCPDIRECT=OFF");
187  #endif
188 
189  #ifdef LLFIX_ENABLE_NUMA
190  LLFIX_LOG_INFO("LLFIX ENGINE LIBNUMA=ON");
191  #else
192  LLFIX_LOG_INFO("LLFIX ENGINE LIBNUMA=OFF");
193  #endif
194 
195  #ifdef LLFIX_ENABLE_OPENSSL
196  LLFIX_LOG_INFO("LLFIX ENGINE OPENSSL=ON , OpenSSL library version : " + std::string(SSLApi::get_version()));
197 
198  if (SSLApi::get_version_major_number() < 3)
199  {
200  LLFIX_LOG_ERROR("OpenSSL major version >= 3.0.0 required");
201  std::exit(-6);
202  }
203 
204  if ( !(SSLApi::get_version_major_number() == 3 && SSLApi::get_version_minor_number() == 6) )
205  {
206  fprintf(stderr, "WARNING : Supported OpenSSL version is 3.6.\n");
207  }
208 
209  LLFIX_LOG_INFO("LLFIX ENGINE OPENSSL=ON , OpenSSL initialisation : " + std::string(SSLApi::initialise()?"true":"false"));
210  #else
211  LLFIX_LOG_INFO("LLFIX ENGINE OPENSSL=OFF");
212  #endif
213 
214  #ifdef LLFIX_ENABLE_DICTIONARY
215  LLFIX_LOG_INFO("LLFIX ENGINE DICTIONARY=ON");
216  #else
217  LLFIX_LOG_INFO("LLFIX ENGINE DICTIONARY=OFF");
218  #endif
219 
220  #ifdef LLFIX_ENABLE_BINARY_FIELDS
221  LLFIX_LOG_INFO("LLFIX BINARY FIELDS SUPPORT=ON");
222  #else
223  LLFIX_LOG_INFO("LLFIX BINARY FIELDS SUPPORT=OFF");
224  #endif
225 
226  LLFIX_LOG_INFO("LLFIX ENGINE initialised successfully");
227 
228  m_engine_initialised.store(true);
229  }
230 
236  static void shutdown()
237  {
239 
240  ThreadLocalStorage::get_instance().destroy();
241 
242  #ifdef LLFIX_ENABLE_OPENSSL
243  SSLApi::uninitialise();
244  #endif
245 
246  #ifdef LLFIX_ENABLE_TCPDIRECT
247  TCPDirectApi::uninitialise();
248  #endif
249  }
250 
257  {
258  if(m_management_server_stopped == false)
259  {
260  if (m_management_server_started == true)
261  {
262  LLFIX_LOG_INFO("Stopping management server");
263  m_management_server.stop();
264  }
265  m_management_server_stopped = true;
266  }
267  }
268 
275  {
276  return m_management_server;
277  }
278 
279  static bool initialised() { return m_engine_initialised.load(); }
280  static const Version& get_version() { return m_version; }
281  static uint64_t get_application_start_timestamp() { return m_application_start_timestamp; }
282  private:
283  static inline Version m_version{"1.0.0"};
284  static inline uint64_t m_application_start_timestamp = 0;
285  static inline std::atomic<bool> m_engine_initialised = false;
286 
287  static inline ManagementServer m_management_server;
288  static inline bool m_management_server_started = false;
289  static inline bool m_management_server_stopped = false;
290 };
291 
292 } // namespace
llfix::Engine::on_start
static void on_start(const std::string &config_file_path="", const std::string &config_group_name="ENGINE")
Initialise and start the engine.
Definition: engine.h:62
llfix::Engine
Singleton Engine instance.
Definition: engine.h:49
llfix::Engine::stop_management_server
static void stop_management_server()
Stops the management server.
Definition: engine.h:256
llfix::Engine::shutdown
static void shutdown()
Stops the engine by releasing resources.
Definition: engine.h:236
llfix::ManagementServer
Management TCP server for FIX engine runtime control and inspection.
Definition: management_server.h:49
llfix::Engine::get_management_server
static ManagementServer & get_management_server()
Get reference to the management server instance.
Definition: engine.h:274