llfix
Low-latency FIX engine
engine.h
1 /*
2 MIT License
3 
4 Copyright (c) 2026 Coreware Limited
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 #pragma once
25 
26 #include "common.h"
27 
28 #include <atomic>
29 #include <cstdint>
30 #include <cstdlib>
31 #include <cstdio>
32 #include <filesystem>
33 
34 #include "core/os/vdso.h"
35 #include "core/os/process_utilities.h"
36 #include "core/os/thread_local_storage.h"
37 #include "core/os/hangup_signal_handler.h"
38 #include "core/os/virtual_memory.h"
39 
40 #ifdef LLFIX_ENABLE_NUMA // VOLTRON_EXCLUDE
41 #include "core/os/numa_utilities.h"
42 #endif // VOLTRON_EXCLUDE
43 
44 #ifdef LLFIX_ENABLE_TCPDIRECT // VOLTRON_EXCLUDE
45 #include "core/solarflare_tcpdirect/tcpdirect_api.h"
46 #endif // VOLTRON_EXCLUDE
47 
48 #ifdef LLFIX_ENABLE_OPENSSL // VOLTRON_EXCLUDE
49 #include "core/ssl/ssl_api.h"
50 #endif // VOLTRON_EXCLUDE
51 
52 #include "core/os/socket.h"
53 #include "core/utilities/logger.h"
54 #include "core/utilities/version.h"
55 #include "core/utilities/allocator.h"
56 
57 #include "engine_settings.h"
58 
59 #include "management_server/management_server_settings.h"
60 #include "management_server/management_server.h"
61 
62 namespace llfix
63 {
64 
71 class Engine
72 {
73  public:
74 
84  static void on_start(const std::string& config_file_path = "", const std::string& config_group_name ="ENGINE")
85  {
86  if(m_engine_initialised.load() == true)
87  {
88  return;
89  }
90 
91  m_application_start_timestamp = VDSO::nanoseconds_monotonic();
92 
93  EngineSettings engine_settings;
94 
95  if(config_file_path.length()>0)
96  {
97  if(engine_settings.load_from_config_file(config_file_path, config_group_name) == false)
98  {
99  fprintf(stderr, "Failed to load %s : %s \n", config_file_path.c_str(), engine_settings.config_load_error.c_str());
100  std::exit(-2);
101  }
102  }
103 
104  if(engine_settings.validate() == false)
105  {
106  fprintf(stderr, "llfix engine : Failed to verify %s : %s \n", config_file_path.c_str(), engine_settings.validation_error.c_str());
107  std::exit(-3);
108  }
109 
110  HangupSignalHandler::set_ignore(engine_settings.ignore_sighup);
111 
112  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)
113  {
114  fprintf(stderr, "llfix engine : Logger initialisation failed\n");
115  std::exit(-4);
116  }
117 
118  if(engine_settings.numa_bind_node >= 0)
119  {
120  #ifdef _WIN32
121  fprintf(stderr, "WARNING : numa_bind_node is specified however NUMA features supported only on Linux.\n");
122  #elif __linux__
123  #ifdef LLFIX_ENABLE_NUMA
124  if(NumaUtilities::get_current_numa_node() == -1)
125  {
126  fprintf(stderr, "WARNING : numa_bind_node is set however there is no NUMA node on the system, therefore it won't take affect\n");
127  }
128  else
129  {
130  if( NumaUtilities::bind_to_numa_node(engine_settings.numa_bind_node) == false)
131  {
132  fprintf(stderr, "llfix engine : Failed to bind to NUMA node %d \n", engine_settings.numa_bind_node);
133  std::exit(-5);
134  }
135 
136  LLFIX_LOG_INFO("Bound NUMA node : " + std::to_string(NumaUtilities::get_current_numa_node()));
137  Allocator::set_numa_aware(engine_settings.numa_aware_allocations);
138  }
139  #else
140  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");
141  #endif
142  #endif
143  }
144 
145  if(engine_settings.lock_pages)
146  {
147  #ifdef __linux__
148  if (ProcessUtilities::has_root_privileges() == false)
149  {
150  fprintf(stderr, "llfix engine : lock_pages option requires root privileges on Linux.\n");
151  std::exit(-1);
152  }
153  auto page_lock_success = VirtualMemory::lock_all_pages();
154  LLFIX_LOG_INFO("VM pages locked : " + std::string( (page_lock_success?"1":"0") ));
155  #endif
156  }
157 
158  if (ThreadLocalStorage::get_instance().create() == false)
159  {
160  LLFIX_LOG_ERROR("Failed to create thread local storage");
161  std::exit(-5);
162  }
163 
164  Socket<>::socket_library_initialise();
165 
166  ManagementServerSettings management_server_settings;
167 
168  if (management_server_settings.specified_by_user(config_file_path, config_group_name))
169  {
170  if (management_server_settings.load_from_config_file(config_file_path, config_group_name) == true)
171  {
172  if (management_server_settings.validate() == true)
173  {
174  std::filesystem::path cwd = std::filesystem::current_path();
175  std::filesystem::path full_log_path = cwd / engine_settings.log_file;
176 
177  if (m_management_server.create(management_server_settings, m_application_start_timestamp, m_version.to_string(), full_log_path.string()))
178  {
179  m_management_server_started = true;
180  LLFIX_LOG_INFO("Started management server , port : " + std::to_string(management_server_settings.management_server_port) + " nic : " + management_server_settings.management_server_nic_ip);
181  }
182  else
183  {
184  LLFIX_LOG_ERROR("Failed to create management server");
185  }
186  }
187  else
188  {
189  LLFIX_LOG_ERROR("Failed to validate management server settings. Error : " + management_server_settings.validation_error);
190  }
191  }
192  }
193 
194  LLFIX_LOG_INFO("LLFIX ENGINE Loaded config =>\n" + engine_settings.to_string());
195 
196  #ifndef LLFIX_BUILD_CONFIG_GENERATED
197  LLFIX_LOG_INFO("LLFIX ENGINE LIBRARY TYPE=HEADER-ONLY , version : " + m_version.to_string());
198  #else
199  LLFIX_LOG_INFO("LLFIX ENGINE LIBRARY TYPE=STATIC-LIB , version : " + m_version.to_string());
200  #endif
201 
202  #ifdef LLFIX_ENABLE_TCPDIRECT
203  LLFIX_LOG_INFO("LLFIX ENGINE TCPDIRECT=ON , TCPDirect library version : " + std::string(TCPDirectApi::get_version()));
204  #else
205  LLFIX_LOG_INFO("LLFIX ENGINE TCPDIRECT=OFF");
206  #endif
207 
208  #ifdef LLFIX_ENABLE_NUMA
209  LLFIX_LOG_INFO("LLFIX ENGINE LIBNUMA=ON");
210  #else
211  LLFIX_LOG_INFO("LLFIX ENGINE LIBNUMA=OFF");
212  #endif
213 
214  #ifdef LLFIX_ENABLE_OPENSSL
215  LLFIX_LOG_INFO("LLFIX ENGINE OPENSSL=ON , OpenSSL library version : " + std::string(SSLApi::get_version()));
216 
217  if (SSLApi::get_version_major_number() < 3)
218  {
219  LLFIX_LOG_ERROR("OpenSSL major version >= 3.0.0 required");
220  std::exit(-6);
221  }
222 
223  if ( !(SSLApi::get_version_major_number() == 3 && SSLApi::get_version_minor_number() == 6) )
224  {
225  fprintf(stderr, "WARNING : Supported OpenSSL version is 3.6.\n");
226  }
227 
228  LLFIX_LOG_INFO("LLFIX ENGINE OPENSSL=ON , OpenSSL initialisation : " + std::string(SSLApi::initialise()?"true":"false"));
229  #else
230  LLFIX_LOG_INFO("LLFIX ENGINE OPENSSL=OFF");
231  #endif
232 
233  #ifdef LLFIX_ENABLE_DICTIONARY
234  LLFIX_LOG_INFO("LLFIX ENGINE DICTIONARY=ON");
235  #else
236  LLFIX_LOG_INFO("LLFIX ENGINE DICTIONARY=OFF");
237  #endif
238 
239  #ifdef LLFIX_ENABLE_BINARY_FIELDS
240  LLFIX_LOG_INFO("LLFIX BINARY FIELDS SUPPORT=ON");
241  #else
242  LLFIX_LOG_INFO("LLFIX BINARY FIELDS SUPPORT=OFF");
243  #endif
244 
245  LLFIX_LOG_INFO("LLFIX ENGINE initialised successfully");
246 
247  m_engine_initialised.store(true);
248  }
249 
255  static void shutdown()
256  {
258 
259  ThreadLocalStorage::get_instance().destroy();
260 
261  #ifdef LLFIX_ENABLE_OPENSSL
262  SSLApi::uninitialise();
263  #endif
264 
265  #ifdef LLFIX_ENABLE_TCPDIRECT
266  TCPDirectApi::uninitialise();
267  #endif
268  }
269 
276  {
277  if(m_management_server_stopped == false)
278  {
279  if (m_management_server_started == true)
280  {
281  LLFIX_LOG_INFO("Stopping management server");
282  m_management_server.stop();
283  }
284  m_management_server_stopped = true;
285  }
286  }
287 
294  {
295  return m_management_server;
296  }
297 
298  static bool initialised() { return m_engine_initialised.load(); }
299  static const Version& get_version() { return m_version; }
300  static uint64_t get_application_start_timestamp() { return m_application_start_timestamp; }
301  private:
302  static inline Version m_version{"1.0.4"};
303  static inline uint64_t m_application_start_timestamp = 0;
304  static inline std::atomic<bool> m_engine_initialised = false;
305 
306  static inline ManagementServer m_management_server;
307  static inline bool m_management_server_started = false;
308  static inline bool m_management_server_stopped = false;
309 };
310 
311 } // 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:84
llfix::Engine
Singleton Engine instance.
Definition: engine.h:71
llfix::Engine::stop_management_server
static void stop_management_server()
Stops the management server.
Definition: engine.h:275
llfix::Engine::shutdown
static void shutdown()
Stops the engine by releasing resources.
Definition: engine.h:255
llfix::ManagementServer
Management TCP server for FIX engine runtime control and inspection.
Definition: management_server.h:71
llfix::Engine::get_management_server
static ManagementServer & get_management_server()
Get reference to the management server instance.
Definition: engine.h:293