From 09fd0779e8e3e86257a4a9b05ec2601271261faa Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 30 Jan 2025 20:08:46 -0700 Subject: [PATCH 001/105] Add sst_support. --- network/impl/CMakeLists.txt | 2 ++ network/impl/src/lf_sst_support.c | 1 + 2 files changed, 3 insertions(+) create mode 100644 network/impl/src/lf_sst_support.c diff --git a/network/impl/CMakeLists.txt b/network/impl/CMakeLists.txt index 225edf3d5..60b61157c 100644 --- a/network/impl/CMakeLists.txt +++ b/network/impl/CMakeLists.txt @@ -10,6 +10,8 @@ target_sources(lf-network-impl PUBLIC if(COMM_TYPE MATCHES TCP) target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_socket_support.c) +elseif(COMM_TYPE MATCHES SST) + target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_sst_support.c) else() message(FATAL_ERROR "Your communication type is not supported! The C target supports TCP.") endif() diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c new file mode 100644 index 000000000..2f74ed84f --- /dev/null +++ b/network/impl/src/lf_sst_support.c @@ -0,0 +1 @@ +#include "net_driver.h" From 3fb0bf916f99c4416212831250df4ed2118129ae Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 14:55:35 -0700 Subject: [PATCH 002/105] Add sst_priv_t struct. --- network/api/lf_sst_support.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 network/api/lf_sst_support.h diff --git a/network/api/lf_sst_support.h b/network/api/lf_sst_support.h new file mode 100644 index 000000000..13cc8b166 --- /dev/null +++ b/network/api/lf_sst_support.h @@ -0,0 +1,12 @@ +#ifndef LF_SST_SUPPORT_H +#define LF_SST_SUPPORT_H + +#include "socket_common.h" + +typedef struct sst_priv_t { + socket_priv_t* socket_priv; + SST_ctx_t* sst_ctx; + SST_session_ctx_t* session_ctx; +} sst_priv_t; + +#endif /* LF_SST_SUPPORT_H */ From 27ac24e66e82f1b18793786c2aec85cc724b0a16 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 14:55:47 -0700 Subject: [PATCH 003/105] Add initialize_netdrv for sst. --- network/impl/src/lf_sst_support.c | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 2f74ed84f..65c9fac6d 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -1 +1,33 @@ #include "net_driver.h" +#include "lf_sst_support.h" +#include "util.h" + +netdrv_t initialize_netdrv() { + // Initialize sst_priv. + sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); + if (sst_priv == NULL) { + lf_print_error_and_exit("Falied to malloc sst_priv_t."); + } + // Initialize socket_priv. + socket_priv_t* socket_priv = malloc(sizeof(socket_priv_t)); + if (socket_priv == NULL) { + lf_print_error_and_exit("Falied to malloc socket_priv_t."); + } + + // Server initialization. + socket_priv->port = 0; + socket_priv->user_specified_port = 0; + socket_priv->socket_descriptor = -1; + + // Federate initialization + strncpy(socket_priv->server_hostname, "localhost", INET_ADDRSTRLEN); + socket_priv->server_ip_addr.s_addr = 0; + socket_priv->server_port = -1; + + // SST initialization. Only set pointers to NULL. + sst_priv->sst_ctx = NULL; + sst_priv->session_ctx = NULL; + + return (netdrv_t)sst_priv; +} + From a814a07e847f28370b21a6ea677c3c9319cb04ab Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 14:59:39 -0700 Subject: [PATCH 004/105] Add free_netdrv for sst --- network/impl/src/lf_sst_support.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 65c9fac6d..29684e71c 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -2,6 +2,14 @@ #include "lf_sst_support.h" #include "util.h" +static sst_priv_t* get_sst_priv_t(netdrv_t drv) { + if (drv == NULL) { + lf_print_error("Network driver is already closed."); + return NULL; + } + return (sst_priv_t*)drv; +} + netdrv_t initialize_netdrv() { // Initialize sst_priv. sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); @@ -24,6 +32,8 @@ netdrv_t initialize_netdrv() { socket_priv->server_ip_addr.s_addr = 0; socket_priv->server_port = -1; + sst_priv->socket_priv = socket_priv; + // SST initialization. Only set pointers to NULL. sst_priv->sst_ctx = NULL; sst_priv->session_ctx = NULL; @@ -31,3 +41,9 @@ netdrv_t initialize_netdrv() { return (netdrv_t)sst_priv; } +void free_netdrv(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + free(priv->socket_priv); + free(priv); +} + From 82e63bd3cf3dca29aa6603cef23b3cbd63fa4942 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 15:10:02 -0700 Subject: [PATCH 005/105] Add create_server, with also passing path as global var in lf_sst_support.h --- core/federated/RTI/main.c | 9 +++++++++ network/api/lf_sst_support.h | 2 ++ network/api/net_driver.h | 4 ++++ network/impl/src/lf_sst_support.c | 10 ++++++++++ 4 files changed, 25 insertions(+) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index b7507615c..63a847696 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -266,6 +266,15 @@ int process_args(int argc, const char* argv[]) { return 0; #endif rti.authentication_enabled = true; + } else if (strcmp(argv[i], "-sst") == 0 || strcmp(argv[i], "--sst") == 0) { +#ifndef COMM_TYPE_SST + lf_print_error("--sst requires the RTI to be built with the --DCOMM_TYPE=SST option."); + usage(argc, argv); + return 0; +#else + i++; + lf_set_sst_config_path(argv[i]); +#endif } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--tracing") == 0) { rti.base.tracing_enabled = true; } else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dnet_disabled") == 0) { diff --git a/network/api/lf_sst_support.h b/network/api/lf_sst_support.h index 13cc8b166..c37bf5b77 100644 --- a/network/api/lf_sst_support.h +++ b/network/api/lf_sst_support.h @@ -9,4 +9,6 @@ typedef struct sst_priv_t { SST_session_ctx_t* session_ctx; } sst_priv_t; +void lf_set_sst_config_path(const char* config_path); + #endif /* LF_SST_SUPPORT_H */ diff --git a/network/api/net_driver.h b/network/api/net_driver.h index b29e8b108..d01478a02 100644 --- a/network/api/net_driver.h +++ b/network/api/net_driver.h @@ -3,6 +3,10 @@ #include "socket_common.h" +#if defined(COMM_TYPE_SST) +#include "lf_sst_support.h" +#endif + typedef void* netdrv_t; /** diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 29684e71c..b196c6424 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -2,6 +2,8 @@ #include "lf_sst_support.h" #include "util.h" +const char* sst_config_path; // The SST's configuration file path. + static sst_priv_t* get_sst_priv_t(netdrv_t drv) { if (drv == NULL) { lf_print_error("Network driver is already closed."); @@ -47,3 +49,11 @@ void free_netdrv(netdrv_t drv) { free(priv); } +int create_server(netdrv_t drv, bool increment_port_on_retry) { + sst_priv_t* priv = get_sst_priv_t(drv); + SST_ctx_t* ctx = init_SST(sst_config_path); + return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, + &priv->socket_priv->port, TCP, increment_port_on_retry); +} + +void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From 4a5f1b6a5efed81619900f6c4c04f5b85c0ab90e Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 15:20:00 -0700 Subject: [PATCH 006/105] Add structure of accept_netdrv --- network/impl/src/lf_sst_support.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index b196c6424..0f7bd8c92 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -56,4 +56,33 @@ int create_server(netdrv_t drv, bool increment_port_on_retry) { &priv->socket_priv->port, TCP, increment_port_on_retry); } +netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { + sst_priv_t* serv_priv = get_sst_priv_t(server_drv); + int rti_socket; + if (rti_drv == NULL) { + rti_socket = -1; + } else { + sst_priv_t* rti_priv = get_sst_priv_t(rti_drv); + rti_socket = rti_priv->socket_priv->socket_descriptor; + } + netdrv_t fed_netdrv = initialize_netdrv(); + sst_priv_t* fed_priv = get_sst_priv_t(fed_netdrv); + + int sock = accept_socket(serv_priv->socket_priv->socket_descriptor, rti_socket); + if (sock == -1) { + free_netdrv(fed_netdrv); + return NULL; + } + fed_priv->socket_priv->socket_descriptor = sock; + // Get the peer address from the connected socket_id. Saving this for the address query. + if (get_peer_address(fed_netdrv) != 0) { + lf_print_error("RTI failed to get peer address."); + }; + + + session_key_list_t *s_key_list = init_empty_session_key_list(); + return fed_netdrv; +} + +// Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From 4d28852df0d92f4f481917be002b4e3d77c64187 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 15:31:51 -0700 Subject: [PATCH 007/105] Add comments. --- network/impl/src/lf_sst_support.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 0f7bd8c92..22427bedc 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -60,6 +60,8 @@ netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { sst_priv_t* serv_priv = get_sst_priv_t(server_drv); int rti_socket; if (rti_drv == NULL) { + // Set to -1, to indicate that this accept_netdrv() call is not trying to check if the rti_drv is available, inside + // the accept_socket() function. rti_socket = -1; } else { sst_priv_t* rti_priv = get_sst_priv_t(rti_drv); @@ -79,8 +81,7 @@ netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { lf_print_error("RTI failed to get peer address."); }; - - session_key_list_t *s_key_list = init_empty_session_key_list(); + session_key_list_t* s_key_list = init_empty_session_key_list(); return fed_netdrv; } From 241d8dae06e4ae08293edbd17a2dcbc0599d201d Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 15:56:20 -0700 Subject: [PATCH 008/105] Set handshake with client. --- network/impl/src/lf_sst_support.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 22427bedc..8e65b5228 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -77,11 +77,17 @@ netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { } fed_priv->socket_priv->socket_descriptor = sock; // Get the peer address from the connected socket_id. Saving this for the address query. - if (get_peer_address(fed_netdrv) != 0) { + if (get_peer_address(fed_priv->socket_priv) != 0) { lf_print_error("RTI failed to get peer address."); }; + // TODO: Do we need to copy sst_ctx form server_drv to fed_drv? session_key_list_t* s_key_list = init_empty_session_key_list(); + SST_session_ctx_t* session_ctx = + server_secure_comm_setup(serv_priv->sst_ctx, fed_priv->socket_priv->socket_descriptor, s_key_list); + // Session key used is copied to the session_ctx. + free_session_key_list_t(s_key_list); + fed_priv->session_ctx = session_ctx; return fed_netdrv; } From 5be07ad4036c22e1c9158cc6b759be7c914bde95 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 16:13:52 -0700 Subject: [PATCH 009/105] Add create_client and connect_to_netdrv for sst. --- network/impl/src/lf_sst_support.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 8e65b5228..5dbd19eae 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -91,5 +91,25 @@ netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { return fed_netdrv; } +void create_client(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); + SST_ctx_t* ctx = init_SST(sst_config_path); + priv->sst_ctx = ctx; +} + +int connect_to_netdrv(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + int ret = connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, + priv->socket_priv->server_port); + if (ret != 0) { + return ret; + } + session_key_list_t* s_key_list = get_session_key(priv->sst_ctx, NULL); + SST_session_ctx_t* session_ctx = secure_connect_to_server_with_socket(&s_key_list->s_key[0], priv->socket_priv->socket_descriptor); + priv->session_ctx = session_ctx; + return 0; +} + // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From 37145ff73f67211ecce1b3cdfa1bfdec5aee9407 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 16:14:11 -0700 Subject: [PATCH 010/105] Add user input path of sst config to federate.c --- core/reactor_common.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/reactor_common.c b/core/reactor_common.c index 7257e5132..7f3049d10 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1068,6 +1068,17 @@ int process_args(int argc, const char* argv[]) { return 0; } } +#endif +#ifdef COMM_TYPE_SST + else if (strcmp(arg, "-sst") == 0 || strcmp(arg, "--sst") == 0) { + if (argc < i + 1) { + lf_print_error("--sst needs a string argument."); + usage(argc, argv); + return 0; + } + const char* fid = argv[i++]; + lf_set_sst_config_path(fid); + } #endif else if (strcmp(arg, "--ros-args") == 0) { // FIXME: Ignore ROS arguments for now From 42a688c36c6e06d6e03fa385f12a7331c3a2573b Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 16:18:50 -0700 Subject: [PATCH 011/105] Add get/set functions. --- network/impl/src/lf_sst_support.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 5dbd19eae..934ff7bc7 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -111,5 +111,42 @@ int connect_to_netdrv(netdrv_t drv) { return 0; } +// Get/set functions. +int32_t get_my_port(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + return priv->socket_priv->port; +} + +int32_t get_server_port(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + return priv->socket_priv->server_port; +} + +struct in_addr* get_ip_addr(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + return &priv->socket_priv->server_ip_addr; +} + +char* get_server_hostname(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + return priv->socket_priv->server_hostname; +} + +void set_my_port(netdrv_t drv, int32_t port) { + sst_priv_t* priv = get_sst_priv_t(drv); + priv->socket_priv->port = port; +} + +void set_server_port(netdrv_t drv, int32_t port) { + sst_priv_t* priv = get_sst_priv_t(drv); + priv->socket_priv->server_port = port; +} + +void set_server_hostname(netdrv_t drv, const char* hostname) { + sst_priv_t* priv = get_sst_priv_t(drv); + memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); +} + + // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From c374b7225d1878ed0c2f08e8c17326fb5d17510f Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 31 Jan 2025 16:21:18 -0700 Subject: [PATCH 012/105] Add read/write/shutdown functions. --- network/impl/src/lf_sst_support.c | 98 ++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 934ff7bc7..e4ed51ebe 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -106,11 +106,106 @@ int connect_to_netdrv(netdrv_t drv) { return ret; } session_key_list_t* s_key_list = get_session_key(priv->sst_ctx, NULL); - SST_session_ctx_t* session_ctx = secure_connect_to_server_with_socket(&s_key_list->s_key[0], priv->socket_priv->socket_descriptor); + SST_session_ctx_t* session_ctx = + secure_connect_to_server_with_socket(&s_key_list->s_key[0], priv->socket_priv->socket_descriptor); priv->session_ctx = session_ctx; return 0; } +// TODO: +int read_from_netdrv(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(drv); + return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); +} + +int read_from_netdrv_close_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(drv); + int read_failed = read_from_netdrv(drv, num_bytes, buffer); + if (read_failed) { + // Read failed. + // Socket has probably been closed from the other side. + // Shut down and close the socket from this side. + shutdown_socket(&priv->socket_priv->socket_descriptor, false); + return -1; + } + return 0; +} + +void read_from_netdrv_fail_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, + char* format, ...) { + va_list args; + int read_failed = read_from_netdrv_close_on_error(drv, num_bytes, buffer); + if (read_failed) { + // Read failed. + if (mutex != NULL) { + LF_MUTEX_UNLOCK(mutex); + } + if (format != NULL) { + va_start(args, format); + lf_print_error_system_failure(format, args); + va_end(args); + } else { + lf_print_error_system_failure("Failed to read from socket."); + } + } +} + +int write_to_netdrv(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(drv); + return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); +} + +int write_to_netdrv_close_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(drv); + int result = write_to_netdrv(drv, num_bytes, buffer); + if (result) { + // Write failed. + // Socket has probably been closed from the other side. + // Shut down and close the socket from this side. + shutdown_socket(&priv->socket_priv->socket_descriptor, false); + } + return result; +} + +void write_to_netdrv_fail_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, + char* format, ...) { + va_list args; + int result = write_to_netdrv_close_on_error(drv, num_bytes, buffer); + if (result) { + // Write failed. + if (mutex != NULL) { + LF_MUTEX_UNLOCK(mutex); + } + if (format != NULL) { + va_start(args, format); + lf_print_error_system_failure(format, args); + va_end(args); + } else { + lf_print_error("Failed to write to socket. Closing it."); + } + } +} + +bool check_netdrv_closed(netdrv_t drv) { + sst_priv_t* priv = get_sst_priv_t(drv); + return check_socket_closed(priv->socket_priv->socket_descriptor); +} + +int shutdown_netdrv(netdrv_t drv, bool read_before_closing) { + if (drv == NULL) { + lf_print("Socket already closed."); + return 0; + } + sst_priv_t* priv = get_sst_priv_t(drv); + int ret = shutdown_socket(&priv->socket_priv->socket_descriptor, read_before_closing); + if (ret != 0) { + lf_print_error("Failed to shutdown socket."); + } + free_netdrv(drv); + return ret; +} +// END of TODO: + // Get/set functions. int32_t get_my_port(netdrv_t drv) { sst_priv_t* priv = get_sst_priv_t(drv); @@ -147,6 +242,5 @@ void set_server_hostname(netdrv_t drv, const char* hostname) { memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); } - // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From a96d00e91a4a71fadbf5cf4cf9138965f2873b41 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sat, 1 Feb 2025 15:13:32 -0700 Subject: [PATCH 013/105] Minor fix on adding void --- network/api/net_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/api/net_driver.h b/network/api/net_driver.h index d01478a02..d0285935e 100644 --- a/network/api/net_driver.h +++ b/network/api/net_driver.h @@ -13,7 +13,7 @@ typedef void* netdrv_t; * Allocate memory for the network driver. * @return netdrv_t Initialized network driver. */ -netdrv_t initialize_netdrv(); +netdrv_t initialize_netdrv(void); /** * Create a netdriver server. This is such as a server socket which accepts connections. From 8922c0d374aa1fd35dc1cc67f49ce70f8f657364 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sat, 1 Feb 2025 15:14:20 -0700 Subject: [PATCH 014/105] Minor fix on adding `void` and new line on EOF. --- logging/api/logging_macros.h | 2 +- low_level_platform/api/low_level_platform.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logging/api/logging_macros.h b/logging/api/logging_macros.h index 3e22950b5..0fbabd157 100644 --- a/logging/api/logging_macros.h +++ b/logging/api/logging_macros.h @@ -107,4 +107,4 @@ static const bool _lf_log_level_is_debug = LOG_LEVEL >= LOG_LEVEL_DEBUG; } \ } while (0) #endif // NDEBUG -#endif // LOGGING_MACROS_H \ No newline at end of file +#endif // LOGGING_MACROS_H diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index afffd2a9e..3fe4d42d3 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -113,12 +113,12 @@ int lf_mutex_lock(lf_mutex_t* mutex); /** * @brief Get the number of cores on the host machine. */ -int lf_available_cores(); +int lf_available_cores(void); /** * @brief Return the lf_thread_t of the calling thread. */ -lf_thread_t lf_thread_self(); +lf_thread_t lf_thread_self(void); /** * Create a new thread, starting with execution of lf_thread @@ -273,12 +273,12 @@ int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time); * @brief The ID of the current thread. The only guarantee is that these IDs will be a contiguous range of numbers * starting at 0. */ -int lf_thread_id(); +int lf_thread_id(void); /** * @brief Initialize the thread ID for the current thread. */ -void initialize_lf_thread_id(); +void initialize_lf_thread_id(void); #endif // !defined(LF_SINGLE_THREADED) /** From ab3d92dd664de4ebc457f42ffe20a65ab5f1275c Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sat, 1 Feb 2025 15:14:59 -0700 Subject: [PATCH 015/105] Enable finding the sst-c-api library, and include it in lf_sst_support.h --- network/api/lf_sst_support.h | 1 + network/impl/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/network/api/lf_sst_support.h b/network/api/lf_sst_support.h index c37bf5b77..7fdb941ab 100644 --- a/network/api/lf_sst_support.h +++ b/network/api/lf_sst_support.h @@ -2,6 +2,7 @@ #define LF_SST_SUPPORT_H #include "socket_common.h" +#include typedef struct sst_priv_t { socket_priv_t* socket_priv; diff --git a/network/impl/CMakeLists.txt b/network/impl/CMakeLists.txt index 60b61157c..e078e9e86 100644 --- a/network/impl/CMakeLists.txt +++ b/network/impl/CMakeLists.txt @@ -11,7 +11,9 @@ target_sources(lf-network-impl PUBLIC if(COMM_TYPE MATCHES TCP) target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_socket_support.c) elseif(COMM_TYPE MATCHES SST) + find_package(sst-lib REQUIRED) target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_sst_support.c) + target_link_libraries(lf-network-impl PUBLIC sst-lib::sst-c-api) else() message(FATAL_ERROR "Your communication type is not supported! The C target supports TCP.") endif() From 2772e866917c008a0c10ca631bbed4834a39b141 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sat, 1 Feb 2025 19:10:24 -0700 Subject: [PATCH 016/105] Add options to use user specified port for sst. --- core/federated/RTI/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index 63a847696..2e0f9ae67 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -234,7 +234,7 @@ int process_args(int argc, const char* argv[]) { rti.base.number_of_scheduling_nodes = (int32_t)num_federates; // FIXME: Loses numbers on 64-bit machines lf_print("RTI: Number of federates: %d", rti.base.number_of_scheduling_nodes); } else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) { -#ifdef COMM_TYPE_TCP +#if defined(COMM_TYPE_TCP) || defined(COMM_TYPE_SST) if (argc < i + 2) { lf_print_error("--port needs a short unsigned integer argument ( > 0 and < %d).", UINT16_MAX); usage(argc, argv); From cb5b23bc15e064f4b1b544b3a8c7ea02442a671d Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sat, 1 Feb 2025 19:10:47 -0700 Subject: [PATCH 017/105] Minor fix on including headers. --- network/impl/src/lf_sst_support.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index e4ed51ebe..982404fc0 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -1,3 +1,6 @@ +#include // malloc() +#include // strncpy() + #include "net_driver.h" #include "lf_sst_support.h" #include "util.h" @@ -52,6 +55,7 @@ void free_netdrv(netdrv_t drv) { int create_server(netdrv_t drv, bool increment_port_on_retry) { sst_priv_t* priv = get_sst_priv_t(drv); SST_ctx_t* ctx = init_SST(sst_config_path); + priv->sst_ctx = ctx; return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, &priv->socket_priv->port, TCP, increment_port_on_retry); } From e7cea3b9a81f616431f3eb134ac79f0c95c47a5b Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sun, 2 Feb 2025 19:55:04 -0700 Subject: [PATCH 018/105] Add -sst option for federate. --- core/reactor_common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/reactor_common.c b/core/reactor_common.c index 7f3049d10..90b972029 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -919,6 +919,9 @@ void usage(int argc, const char* argv[]) { printf(" The address of the RTI, which can be in the form of user@host:port or ip:port.\n\n"); printf(" -l\n"); printf(" Send stdout to individual log files for each federate.\n\n"); +#ifdef COMM_TYPE_SST + printf(" -sst, --sst \n"); +#endif #endif printf("Command given:\n"); From 3fa7c48deb2ff96b8650a279f3a7820d5bb05632 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Tue, 4 Feb 2025 15:18:15 -0700 Subject: [PATCH 019/105] Add usage for --sst for RTI. --- core/federated/RTI/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index 2e0f9ae67..06818b629 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -137,6 +137,7 @@ void usage(int argc, const char* argv[]) { lf_print(" -a, --auth Turn on HMAC authentication options.\n"); lf_print(" -t, --tracing Turn on tracing.\n"); lf_print(" -d, --disable_dnet Turn off the use of DNET signals.\n"); + lf_print(" -sst, --sst SST config path for RTI.\n"); lf_print("Command given:"); for (int i = 0; i < argc; i++) { From a3887e9b578ef3612877374d23abb9ce92bdc044 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 6 Feb 2025 14:10:33 -0700 Subject: [PATCH 020/105] Fix read/write to send header separately to match numbers. Fed-to-Fed not done yet. --- core/federated/RTI/rti_remote.c | 30 +++++++++++++-------- core/federated/federate.c | 47 +++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 296774338..6eb8a09e8 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -75,7 +75,8 @@ void notify_tag_advance_grant(scheduling_node_t* e, tag_t tag) { // This function is called in notify_advance_grant_if_safe(), which is a long // function. During this call, the network driver might close, causing the following write_to_netdrv // to fail. Consider a failure here a soft failure and update the federate's status. - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length, buffer)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || + write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { lf_print_error("RTI failed to send tag advance grant to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -108,7 +109,8 @@ void notify_provisional_tag_advance_grant(scheduling_node_t* e, tag_t tag) { // This function is called in notify_advance_grant_if_safe(), which is a long // function. During this call, the network driver might close, causing the following write_to_netdrv // to fail. Consider a failure here a soft failure and update the federate's status. - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length, buffer)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || + write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { lf_print_error("RTI failed to send tag advance grant to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -165,7 +167,7 @@ void notify_downstream_next_event_tag(scheduling_node_t* e, tag_t tag) { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_DNET, e->id, &tag); } - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length, buffer)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { lf_print_error("RTI failed to send downstream next event tag to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -243,9 +245,8 @@ void handle_port_absent_message(federate_info_t* sending_federate, unsigned char } void handle_timed_message(federate_info_t* sending_federate, unsigned char* buffer) { - size_t header_size = 1 + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(int64_t) + sizeof(uint32_t); - // Read the header, minus the first byte which has already been read. - read_from_netdrv_fail_on_error(sending_federate->fed_netdrv, header_size - 1, &(buffer[1]), NULL, + size_t header_size = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(int64_t) + sizeof(uint32_t); + read_from_netdrv_fail_on_error(sending_federate->fed_netdrv, header_size, &(buffer[1]), NULL, "RTI failed to read the timed message header from remote federate."); // Extract the header information. of the sender uint16_t reactor_port_id; @@ -331,8 +332,9 @@ void handle_timed_message(federate_info_t* sending_federate, unsigned char* buff if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_TAGGED_MSG, federate_id, &intended_tag); } - - write_to_netdrv_fail_on_error(fed->fed_netdrv, bytes_read, buffer, &rti_mutex, + write_to_netdrv_fail_on_error(fed->fed_netdrv, 1, buffer, &rti_mutex, + "RTI failed to forward message header to federate %d.", federate_id); + write_to_netdrv_fail_on_error(fed->fed_netdrv, bytes_read - 1, buffer + 1, &rti_mutex, "RTI failed to forward message to federate %d.", federate_id); // The message length may be longer than the buffer, @@ -458,7 +460,10 @@ static void broadcast_stop_time_to_federates_locked() { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_STOP_GRN, fed->enclave.id, &rti_remote->base.max_stop_tag); } - write_to_netdrv_fail_on_error(fed->fed_netdrv, MSG_TYPE_STOP_GRANTED_LENGTH, outgoing_buffer, &rti_mutex, + write_to_netdrv_fail_on_error(fed->fed_netdrv, 1, outgoing_buffer, &rti_mutex, + "RTI failed to send MSG_TYPE_STOP_GRANTED message header to federate %d.", + fed->enclave.id); + write_to_netdrv_fail_on_error(fed->fed_netdrv, MSG_TYPE_STOP_GRANTED_LENGTH - 1, outgoing_buffer + 1, &rti_mutex, "RTI failed to send MSG_TYPE_STOP_GRANTED message to federate %d.", fed->enclave.id); } @@ -578,8 +583,11 @@ void handle_stop_request_message(federate_info_t* fed) { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_STOP_REQ, f->enclave.id, &rti_remote->base.max_stop_tag); } - write_to_netdrv_fail_on_error(f->fed_netdrv, MSG_TYPE_STOP_REQUEST_LENGTH, stop_request_buffer, &rti_mutex, - "RTI failed to forward MSG_TYPE_STOP_REQUEST message to federate %d.", + write_to_netdrv_fail_on_error(f->fed_netdrv, 1, stop_request_buffer, &rti_mutex, + "RTI failed to forward MSG_TYPE_STOP_REQUEST message header to federate %d.", + f->enclave.id); + write_to_netdrv_fail_on_error(f->fed_netdrv, MSG_TYPE_STOP_REQUEST_LENGTH - 1, stop_request_buffer + 1, + &rti_mutex, "RTI failed to forward MSG_TYPE_STOP_REQUEST message to federate %d.", f->enclave.id); } } diff --git a/core/federated/federate.c b/core/federated/federate.c index 460f72255..c5dad4454 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -111,7 +111,9 @@ static void send_time(unsigned char type, instant_t time) { tracepoint_federate_to_rti(send_TIMESTAMP, _lf_my_fed_id, &tag); LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write, buffer, &lf_outbound_netdrv_mutex, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, + "Failed to send MSG_TYPE_TIMESTAMP header."); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write - 1, buffer + 1, &lf_outbound_netdrv_mutex, "Failed to send time " PRINTF_TIME " to the RTI.", time - start_time); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); } @@ -138,7 +140,8 @@ static void send_tag(unsigned char type, tag_t tag) { trace_event_t event_type = (type == MSG_TYPE_NEXT_EVENT_TAG) ? send_NET : send_LTC; // Trace the event when tracing is enabled tracepoint_federate_to_rti(event_type, _lf_my_fed_id, &tag); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write, buffer, &lf_outbound_netdrv_mutex, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, "Failed to send tag header."); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write - 1, buffer + 1, &lf_outbound_netdrv_mutex, "Failed to send tag " PRINTF_TAG " to the RTI.", tag.time - start_time, tag.microstep); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); } @@ -1418,7 +1421,9 @@ static void handle_stop_request_message() { // Send the current logical time to the RTI. LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_REPLY_LENGTH, outgoing_buffer, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, outgoing_buffer, &lf_outbound_netdrv_mutex, + "Failed to send the answer to MSG_TYPE_STOP_REQUEST to RTI."); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_REPLY_LENGTH - 1, outgoing_buffer + 1, &lf_outbound_netdrv_mutex, "Failed to send the answer to MSG_TYPE_STOP_REQUEST to RTI."); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); @@ -1543,12 +1548,13 @@ static void* listen_to_rti_netdrv(void* args) { case MSG_TYPE_STOP_GRANTED: handle_stop_granted_message(); break; - case MSG_TYPE_PORT_ABSENT: - if (handle_port_absent_message(_fed.netdrv_to_RTI, -1)) { - // Failures to complete the read of absent messages from the RTI are fatal. - lf_print_error_and_exit("Failed to complete the reading of an absent message from the RTI."); - } - break; +//TODO: Check. RTI does not send MSG_TYPE_PORT_ABSENT + // case MSG_TYPE_PORT_ABSENT: + // if (handle_port_absent_message(_fed.netdrv_to_RTI, -1)) { + // // Failures to complete the read of absent messages from the RTI are fatal. + // lf_print_error_and_exit("Failed to complete the reading of an absent message from the RTI."); + // } + // break; case MSG_TYPE_DOWNSTREAM_NEXT_EVENT_TAG: handle_downstream_next_event_tag(); break; @@ -1711,7 +1717,9 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { tracepoint_federate_to_rti(send_ADR_QR, _lf_my_fed_id, NULL); LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(uint16_t) + 1, buffer, &lf_outbound_netdrv_mutex, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, + "Failed to send address query header for federate %d to RTI.", remote_federate_id); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(uint16_t), buffer + 1, &lf_outbound_netdrv_mutex, "Failed to send address query for federate %d to RTI.", remote_federate_id); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); @@ -1971,7 +1979,9 @@ void lf_create_server(int specified_port) { tracepoint_federate_to_rti(send_ADR_AD, _lf_my_fed_id, NULL); // No need for a mutex because we have the only handle on this network driver. - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(int32_t) + 1, (unsigned char*)buffer, NULL, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, (unsigned char*)buffer, NULL, + "Failed to send address advertisement header."); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(int32_t), (unsigned char*)buffer + 1, NULL, "Failed to send address advertisement."); LF_PRINT_DEBUG("Sent port %d to the RTI.", server_port); @@ -2411,7 +2421,8 @@ void lf_send_port_absent_to_federate(environment_t* env, interval_t additional_d } LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - int result = write_to_netdrv_close_on_error(netdrv, message_length, buffer); + int result = write_to_netdrv_close_on_error(netdrv, 1, buffer); + result = write_to_netdrv_close_on_error(netdrv, message_length - 1, buffer + 1); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); if (result != 0) { @@ -2448,9 +2459,11 @@ int lf_send_stop_request_to_rti(tag_t stop_tag) { } // Trace the event when tracing is enabled tracepoint_federate_to_rti(send_STOP_REQ, _lf_my_fed_id, &stop_tag); - - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_LENGTH, buffer, &lf_outbound_netdrv_mutex, - "Failed to send stop time " PRINTF_TIME " to the RTI.", stop_tag.time - start_time); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, + "Failed to send stop request header."); + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_LENGTH - 1, buffer + 1, + &lf_outbound_netdrv_mutex, "Failed to send stop time " PRINTF_TIME " to the RTI.", + stop_tag.time - start_time); // Treat this sending as equivalent to having received a stop request from the RTI. _fed.received_stop_request_from_rti = true; @@ -2524,8 +2537,8 @@ int lf_send_tagged_message(environment_t* env, interval_t additional_delay, int if (lf_tag_compare(_fed.last_DNET, current_message_intended_tag) > 0) { _fed.last_DNET = current_message_intended_tag; } - - int result = write_to_netdrv_close_on_error(netdrv, header_length, header_buffer); + int result = write_to_netdrv_close_on_error(netdrv, 1, header_buffer); + result = write_to_netdrv_close_on_error(netdrv, header_length - 1, header_buffer + 1); if (result == 0) { // Header sent successfully. Send the body. result = write_to_netdrv_close_on_error(netdrv, length, message); From 53b2100d0e315ecc91a2b1bb7257241e38d7aced Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 6 Feb 2025 14:11:23 -0700 Subject: [PATCH 021/105] Minor cleanup. --- core/federated/federate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index c5dad4454..f660aba66 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -725,7 +725,6 @@ static int handle_port_absent_message(netdrv_t netdrv, int fed_id) { * network driver in _fed.netdrvs_for_inbound_p2p_connections * to -1 and returns, terminating the thread. * @param _args The remote federate ID (cast to void*). - * @param fed_id_ptr A pointer to a uint16_t containing federate ID being listened to. * This procedure frees the memory pointed to before returning. */ static void* listen_to_federates(void* _args) { From af591a24cbd431021621e73be05db9e7662f8d61 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 6 Feb 2025 14:14:26 -0700 Subject: [PATCH 022/105] Fix read/write to match for fed2fed messages. --- core/federated/federate.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index f660aba66..1f92ecf6e 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1547,13 +1547,13 @@ static void* listen_to_rti_netdrv(void* args) { case MSG_TYPE_STOP_GRANTED: handle_stop_granted_message(); break; -//TODO: Check. RTI does not send MSG_TYPE_PORT_ABSENT - // case MSG_TYPE_PORT_ABSENT: - // if (handle_port_absent_message(_fed.netdrv_to_RTI, -1)) { - // // Failures to complete the read of absent messages from the RTI are fatal. - // lf_print_error_and_exit("Failed to complete the reading of an absent message from the RTI."); - // } - // break; + // TODO: Check. RTI does not send MSG_TYPE_PORT_ABSENT + // case MSG_TYPE_PORT_ABSENT: + // if (handle_port_absent_message(_fed.netdrv_to_RTI, -1)) { + // // Failures to complete the read of absent messages from the RTI are fatal. + // lf_print_error_and_exit("Failed to complete the reading of an absent message from the RTI."); + // } + // break; case MSG_TYPE_DOWNSTREAM_NEXT_EVENT_TAG: handle_downstream_next_event_tag(); break; @@ -2212,7 +2212,8 @@ int lf_send_message(int message_type, unsigned short port, unsigned short federa // Trace the event when tracing is enabled tracepoint_federate_to_federate(send_P2P_MSG, _lf_my_fed_id, federate, NULL); - int result = write_to_netdrv_close_on_error(netdrv, header_length, header_buffer); + int result = write_to_netdrv_close_on_error(netdrv, 1, header_buffer); + result = write_to_netdrv_close_on_error(netdrv, header_length - 1, header_buffer + 1); if (result == 0) { // Header sent successfully. Send the body. result = write_to_netdrv_close_on_error(netdrv, length, message); From b92b7373d3b73e815fd3fd47bd962dba247f723a Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 6 Feb 2025 14:31:06 -0700 Subject: [PATCH 023/105] Fix forwarding on port absent messages. --- core/federated/RTI/rti_remote.c | 7 +++++-- core/federated/federate.c | 13 ++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 6eb8a09e8..3f3651a1c 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -167,7 +167,8 @@ void notify_downstream_next_event_tag(scheduling_node_t* e, tag_t tag) { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_DNET, e->id, &tag); } - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || + write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { lf_print_error("RTI failed to send downstream next event tag to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -238,7 +239,9 @@ void handle_port_absent_message(federate_info_t* sending_federate, unsigned char } // Forward the message. - write_to_netdrv_fail_on_error(fed->fed_netdrv, message_size + 1, buffer, &rti_mutex, + write_to_netdrv_fail_on_error(fed->fed_netdrv, 1, buffer, &rti_mutex, "RTI failed to forward message to federate %d.", + federate_id); + write_to_netdrv_fail_on_error(fed->fed_netdrv, message_size, buffer + 1, &rti_mutex, "RTI failed to forward message to federate %d.", federate_id); LF_MUTEX_UNLOCK(&rti_mutex); diff --git a/core/federated/federate.c b/core/federated/federate.c index 1f92ecf6e..83d57a9d7 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1547,13 +1547,12 @@ static void* listen_to_rti_netdrv(void* args) { case MSG_TYPE_STOP_GRANTED: handle_stop_granted_message(); break; - // TODO: Check. RTI does not send MSG_TYPE_PORT_ABSENT - // case MSG_TYPE_PORT_ABSENT: - // if (handle_port_absent_message(_fed.netdrv_to_RTI, -1)) { - // // Failures to complete the read of absent messages from the RTI are fatal. - // lf_print_error_and_exit("Failed to complete the reading of an absent message from the RTI."); - // } - // break; + case MSG_TYPE_PORT_ABSENT: + if (handle_port_absent_message(_fed.netdrv_to_RTI, -1)) { + // Failures to complete the read of absent messages from the RTI are fatal. + lf_print_error_and_exit("Failed to complete the reading of an absent message from the RTI."); + } + break; case MSG_TYPE_DOWNSTREAM_NEXT_EVENT_TAG: handle_downstream_next_event_tag(); break; From 62bad679a58d0a450c679b3305601bd91317fd32 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Wed, 12 Feb 2025 15:42:02 -0700 Subject: [PATCH 024/105] Revert "Fix read/write to send header separately to match numbers. Fed-to-Fed not done yet." This reverts commit a3887e9b578ef3612877374d23abb9ce92bdc044. --- core/federated/RTI/rti_remote.c | 35 +++++++++++-------------------- core/federated/federate.c | 37 +++++++++++---------------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 3f3651a1c..296774338 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -75,8 +75,7 @@ void notify_tag_advance_grant(scheduling_node_t* e, tag_t tag) { // This function is called in notify_advance_grant_if_safe(), which is a long // function. During this call, the network driver might close, causing the following write_to_netdrv // to fail. Consider a failure here a soft failure and update the federate's status. - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || - write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length, buffer)) { lf_print_error("RTI failed to send tag advance grant to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -109,8 +108,7 @@ void notify_provisional_tag_advance_grant(scheduling_node_t* e, tag_t tag) { // This function is called in notify_advance_grant_if_safe(), which is a long // function. During this call, the network driver might close, causing the following write_to_netdrv // to fail. Consider a failure here a soft failure and update the federate's status. - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || - write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length, buffer)) { lf_print_error("RTI failed to send tag advance grant to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -167,8 +165,7 @@ void notify_downstream_next_event_tag(scheduling_node_t* e, tag_t tag) { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_DNET, e->id, &tag); } - if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, 1, buffer) || - write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length - 1, buffer + 1)) { + if (write_to_netdrv(((federate_info_t*)e)->fed_netdrv, message_length, buffer)) { lf_print_error("RTI failed to send downstream next event tag to federate %d.", e->id); e->state = NOT_CONNECTED; } else { @@ -239,17 +236,16 @@ void handle_port_absent_message(federate_info_t* sending_federate, unsigned char } // Forward the message. - write_to_netdrv_fail_on_error(fed->fed_netdrv, 1, buffer, &rti_mutex, "RTI failed to forward message to federate %d.", - federate_id); - write_to_netdrv_fail_on_error(fed->fed_netdrv, message_size, buffer + 1, &rti_mutex, + write_to_netdrv_fail_on_error(fed->fed_netdrv, message_size + 1, buffer, &rti_mutex, "RTI failed to forward message to federate %d.", federate_id); LF_MUTEX_UNLOCK(&rti_mutex); } void handle_timed_message(federate_info_t* sending_federate, unsigned char* buffer) { - size_t header_size = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(int64_t) + sizeof(uint32_t); - read_from_netdrv_fail_on_error(sending_federate->fed_netdrv, header_size, &(buffer[1]), NULL, + size_t header_size = 1 + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(int64_t) + sizeof(uint32_t); + // Read the header, minus the first byte which has already been read. + read_from_netdrv_fail_on_error(sending_federate->fed_netdrv, header_size - 1, &(buffer[1]), NULL, "RTI failed to read the timed message header from remote federate."); // Extract the header information. of the sender uint16_t reactor_port_id; @@ -335,9 +331,8 @@ void handle_timed_message(federate_info_t* sending_federate, unsigned char* buff if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_TAGGED_MSG, federate_id, &intended_tag); } - write_to_netdrv_fail_on_error(fed->fed_netdrv, 1, buffer, &rti_mutex, - "RTI failed to forward message header to federate %d.", federate_id); - write_to_netdrv_fail_on_error(fed->fed_netdrv, bytes_read - 1, buffer + 1, &rti_mutex, + + write_to_netdrv_fail_on_error(fed->fed_netdrv, bytes_read, buffer, &rti_mutex, "RTI failed to forward message to federate %d.", federate_id); // The message length may be longer than the buffer, @@ -463,10 +458,7 @@ static void broadcast_stop_time_to_federates_locked() { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_STOP_GRN, fed->enclave.id, &rti_remote->base.max_stop_tag); } - write_to_netdrv_fail_on_error(fed->fed_netdrv, 1, outgoing_buffer, &rti_mutex, - "RTI failed to send MSG_TYPE_STOP_GRANTED message header to federate %d.", - fed->enclave.id); - write_to_netdrv_fail_on_error(fed->fed_netdrv, MSG_TYPE_STOP_GRANTED_LENGTH - 1, outgoing_buffer + 1, &rti_mutex, + write_to_netdrv_fail_on_error(fed->fed_netdrv, MSG_TYPE_STOP_GRANTED_LENGTH, outgoing_buffer, &rti_mutex, "RTI failed to send MSG_TYPE_STOP_GRANTED message to federate %d.", fed->enclave.id); } @@ -586,11 +578,8 @@ void handle_stop_request_message(federate_info_t* fed) { if (rti_remote->base.tracing_enabled) { tracepoint_rti_to_federate(send_STOP_REQ, f->enclave.id, &rti_remote->base.max_stop_tag); } - write_to_netdrv_fail_on_error(f->fed_netdrv, 1, stop_request_buffer, &rti_mutex, - "RTI failed to forward MSG_TYPE_STOP_REQUEST message header to federate %d.", - f->enclave.id); - write_to_netdrv_fail_on_error(f->fed_netdrv, MSG_TYPE_STOP_REQUEST_LENGTH - 1, stop_request_buffer + 1, - &rti_mutex, "RTI failed to forward MSG_TYPE_STOP_REQUEST message to federate %d.", + write_to_netdrv_fail_on_error(f->fed_netdrv, MSG_TYPE_STOP_REQUEST_LENGTH, stop_request_buffer, &rti_mutex, + "RTI failed to forward MSG_TYPE_STOP_REQUEST message to federate %d.", f->enclave.id); } } diff --git a/core/federated/federate.c b/core/federated/federate.c index 83d57a9d7..1f660db67 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -111,9 +111,7 @@ static void send_time(unsigned char type, instant_t time) { tracepoint_federate_to_rti(send_TIMESTAMP, _lf_my_fed_id, &tag); LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, - "Failed to send MSG_TYPE_TIMESTAMP header."); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write - 1, buffer + 1, &lf_outbound_netdrv_mutex, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write, buffer, &lf_outbound_netdrv_mutex, "Failed to send time " PRINTF_TIME " to the RTI.", time - start_time); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); } @@ -140,8 +138,7 @@ static void send_tag(unsigned char type, tag_t tag) { trace_event_t event_type = (type == MSG_TYPE_NEXT_EVENT_TAG) ? send_NET : send_LTC; // Trace the event when tracing is enabled tracepoint_federate_to_rti(event_type, _lf_my_fed_id, &tag); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, "Failed to send tag header."); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write - 1, buffer + 1, &lf_outbound_netdrv_mutex, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, bytes_to_write, buffer, &lf_outbound_netdrv_mutex, "Failed to send tag " PRINTF_TAG " to the RTI.", tag.time - start_time, tag.microstep); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); } @@ -1420,9 +1417,7 @@ static void handle_stop_request_message() { // Send the current logical time to the RTI. LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, outgoing_buffer, &lf_outbound_netdrv_mutex, - "Failed to send the answer to MSG_TYPE_STOP_REQUEST to RTI."); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_REPLY_LENGTH - 1, outgoing_buffer + 1, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_REPLY_LENGTH, outgoing_buffer, &lf_outbound_netdrv_mutex, "Failed to send the answer to MSG_TYPE_STOP_REQUEST to RTI."); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); @@ -1715,9 +1710,7 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { tracepoint_federate_to_rti(send_ADR_QR, _lf_my_fed_id, NULL); LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, - "Failed to send address query header for federate %d to RTI.", remote_federate_id); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(uint16_t), buffer + 1, &lf_outbound_netdrv_mutex, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(uint16_t) + 1, buffer, &lf_outbound_netdrv_mutex, "Failed to send address query for federate %d to RTI.", remote_federate_id); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); @@ -1977,9 +1970,7 @@ void lf_create_server(int specified_port) { tracepoint_federate_to_rti(send_ADR_AD, _lf_my_fed_id, NULL); // No need for a mutex because we have the only handle on this network driver. - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, (unsigned char*)buffer, NULL, - "Failed to send address advertisement header."); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(int32_t), (unsigned char*)buffer + 1, NULL, + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, sizeof(int32_t) + 1, (unsigned char*)buffer, NULL, "Failed to send address advertisement."); LF_PRINT_DEBUG("Sent port %d to the RTI.", server_port); @@ -2211,8 +2202,7 @@ int lf_send_message(int message_type, unsigned short port, unsigned short federa // Trace the event when tracing is enabled tracepoint_federate_to_federate(send_P2P_MSG, _lf_my_fed_id, federate, NULL); - int result = write_to_netdrv_close_on_error(netdrv, 1, header_buffer); - result = write_to_netdrv_close_on_error(netdrv, header_length - 1, header_buffer + 1); + int result = write_to_netdrv_close_on_error(netdrv, header_length, header_buffer); if (result == 0) { // Header sent successfully. Send the body. result = write_to_netdrv_close_on_error(netdrv, length, message); @@ -2420,8 +2410,7 @@ void lf_send_port_absent_to_federate(environment_t* env, interval_t additional_d } LF_MUTEX_LOCK(&lf_outbound_netdrv_mutex); - int result = write_to_netdrv_close_on_error(netdrv, 1, buffer); - result = write_to_netdrv_close_on_error(netdrv, message_length - 1, buffer + 1); + int result = write_to_netdrv_close_on_error(netdrv, message_length, buffer); LF_MUTEX_UNLOCK(&lf_outbound_netdrv_mutex); if (result != 0) { @@ -2458,11 +2447,9 @@ int lf_send_stop_request_to_rti(tag_t stop_tag) { } // Trace the event when tracing is enabled tracepoint_federate_to_rti(send_STOP_REQ, _lf_my_fed_id, &stop_tag); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, 1, buffer, &lf_outbound_netdrv_mutex, - "Failed to send stop request header."); - write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_LENGTH - 1, buffer + 1, - &lf_outbound_netdrv_mutex, "Failed to send stop time " PRINTF_TIME " to the RTI.", - stop_tag.time - start_time); + + write_to_netdrv_fail_on_error(_fed.netdrv_to_RTI, MSG_TYPE_STOP_REQUEST_LENGTH, buffer, &lf_outbound_netdrv_mutex, + "Failed to send stop time " PRINTF_TIME " to the RTI.", stop_tag.time - start_time); // Treat this sending as equivalent to having received a stop request from the RTI. _fed.received_stop_request_from_rti = true; @@ -2536,8 +2523,8 @@ int lf_send_tagged_message(environment_t* env, interval_t additional_delay, int if (lf_tag_compare(_fed.last_DNET, current_message_intended_tag) > 0) { _fed.last_DNET = current_message_intended_tag; } - int result = write_to_netdrv_close_on_error(netdrv, 1, header_buffer); - result = write_to_netdrv_close_on_error(netdrv, header_length - 1, header_buffer + 1); + + int result = write_to_netdrv_close_on_error(netdrv, header_length, header_buffer); if (result == 0) { // Header sent successfully. Send the body. result = write_to_netdrv_close_on_error(netdrv, length, message); From f6e86745d64f4bf78674efa0b3b6bd23e30e861a Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 28 Feb 2025 12:43:09 -0700 Subject: [PATCH 025/105] Minor fix. --- network/impl/src/lf_sst_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 982404fc0..6d469ff43 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -116,7 +116,7 @@ int connect_to_netdrv(netdrv_t drv) { return 0; } -// TODO: +// TODO: Still need to fix... int read_from_netdrv(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(drv); return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); From b2846c253620c028d7ad1dbaebdbf9bddc53797b Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 28 Feb 2025 12:44:21 -0700 Subject: [PATCH 026/105] Minor fix on formatting. --- network/impl/src/lf_sst_support.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 6d469ff43..0180e000a 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -1,5 +1,5 @@ -#include // malloc() -#include // strncpy() +#include // malloc() +#include // strncpy() #include "net_driver.h" #include "lf_sst_support.h" From 01a4b55b8316a1527b7330ce6debeb7b32bd2b6d Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 28 Feb 2025 14:45:21 -0700 Subject: [PATCH 027/105] Fix names to chan. --- network/impl/src/lf_sst_support.c | 114 +++++++++++++++--------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 0180e000a..5c49493f2 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -7,15 +7,15 @@ const char* sst_config_path; // The SST's configuration file path. -static sst_priv_t* get_sst_priv_t(netdrv_t drv) { - if (drv == NULL) { +static sst_priv_t* get_sst_priv_t(netchan_t chan) { + if (chan == NULL) { lf_print_error("Network driver is already closed."); return NULL; } - return (sst_priv_t*)drv; + return (sst_priv_t*)chan; } -netdrv_t initialize_netdrv() { +netchan_t initialize_netchan() { // Initialize sst_priv. sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); if (sst_priv == NULL) { @@ -43,40 +43,40 @@ netdrv_t initialize_netdrv() { sst_priv->sst_ctx = NULL; sst_priv->session_ctx = NULL; - return (netdrv_t)sst_priv; + return (netchan_t)sst_priv; } -void free_netdrv(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +void free_netchan(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); free(priv->socket_priv); free(priv); } -int create_server(netdrv_t drv, bool increment_port_on_retry) { - sst_priv_t* priv = get_sst_priv_t(drv); +int create_server(netchan_t chan, bool increment_port_on_retry) { + sst_priv_t* priv = get_sst_priv_t(chan); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, &priv->socket_priv->port, TCP, increment_port_on_retry); } -netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { - sst_priv_t* serv_priv = get_sst_priv_t(server_drv); +netchan_t accept_netchan(netchan_t server_chan, netchan_t rti_chan) { + sst_priv_t* serv_priv = get_sst_priv_t(server_chan); int rti_socket; - if (rti_drv == NULL) { - // Set to -1, to indicate that this accept_netdrv() call is not trying to check if the rti_drv is available, inside + if (rti_chan == NULL) { + // Set to -1, to indicate that this accept_netchan() call is not trying to check if the rti_chan is available, inside // the accept_socket() function. rti_socket = -1; } else { - sst_priv_t* rti_priv = get_sst_priv_t(rti_drv); + sst_priv_t* rti_priv = get_sst_priv_t(rti_chan); rti_socket = rti_priv->socket_priv->socket_descriptor; } - netdrv_t fed_netdrv = initialize_netdrv(); - sst_priv_t* fed_priv = get_sst_priv_t(fed_netdrv); + netchan_t fed_netchan = initialize_netchan(); + sst_priv_t* fed_priv = get_sst_priv_t(fed_netchan); int sock = accept_socket(serv_priv->socket_priv->socket_descriptor, rti_socket); if (sock == -1) { - free_netdrv(fed_netdrv); + free_netchan(fed_netchan); return NULL; } fed_priv->socket_priv->socket_descriptor = sock; @@ -85,25 +85,25 @@ netdrv_t accept_netdrv(netdrv_t server_drv, netdrv_t rti_drv) { lf_print_error("RTI failed to get peer address."); }; - // TODO: Do we need to copy sst_ctx form server_drv to fed_drv? + // TODO: Do we need to copy sst_ctx form server_chan to fed_chan? session_key_list_t* s_key_list = init_empty_session_key_list(); SST_session_ctx_t* session_ctx = server_secure_comm_setup(serv_priv->sst_ctx, fed_priv->socket_priv->socket_descriptor, s_key_list); // Session key used is copied to the session_ctx. free_session_key_list_t(s_key_list); fed_priv->session_ctx = session_ctx; - return fed_netdrv; + return fed_netchan; } -void create_client(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +void create_client(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; } -int connect_to_netdrv(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +int connect_to_netchan(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); int ret = connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, priv->socket_priv->server_port); if (ret != 0) { @@ -117,14 +117,14 @@ int connect_to_netdrv(netdrv_t drv) { } // TODO: Still need to fix... -int read_from_netdrv(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(drv); +int read_from_netchan(netchan_t chan, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(chan); return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int read_from_netdrv_close_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(drv); - int read_failed = read_from_netdrv(drv, num_bytes, buffer); +int read_from_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(chan); + int read_failed = read_from_netchan(chan, num_bytes, buffer); if (read_failed) { // Read failed. // Socket has probably been closed from the other side. @@ -135,10 +135,10 @@ int read_from_netdrv_close_on_error(netdrv_t drv, size_t num_bytes, unsigned cha return 0; } -void read_from_netdrv_fail_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, +void read_from_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, char* format, ...) { va_list args; - int read_failed = read_from_netdrv_close_on_error(drv, num_bytes, buffer); + int read_failed = read_from_netchan_close_on_error(chan, num_bytes, buffer); if (read_failed) { // Read failed. if (mutex != NULL) { @@ -154,14 +154,14 @@ void read_from_netdrv_fail_on_error(netdrv_t drv, size_t num_bytes, unsigned cha } } -int write_to_netdrv(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(drv); +int write_to_netchan(netchan_t chan, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(chan); return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int write_to_netdrv_close_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(drv); - int result = write_to_netdrv(drv, num_bytes, buffer); +int write_to_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(chan); + int result = write_to_netchan(chan, num_bytes, buffer); if (result) { // Write failed. // Socket has probably been closed from the other side. @@ -171,10 +171,10 @@ int write_to_netdrv_close_on_error(netdrv_t drv, size_t num_bytes, unsigned char return result; } -void write_to_netdrv_fail_on_error(netdrv_t drv, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, +void write_to_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, char* format, ...) { va_list args; - int result = write_to_netdrv_close_on_error(drv, num_bytes, buffer); + int result = write_to_netchan_close_on_error(chan, num_bytes, buffer); if (result) { // Write failed. if (mutex != NULL) { @@ -190,59 +190,59 @@ void write_to_netdrv_fail_on_error(netdrv_t drv, size_t num_bytes, unsigned char } } -bool check_netdrv_closed(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +bool check_netchan_closed(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); return check_socket_closed(priv->socket_priv->socket_descriptor); } -int shutdown_netdrv(netdrv_t drv, bool read_before_closing) { - if (drv == NULL) { +int shutdown_netchan(netchan_t chan, bool read_before_closing) { + if (chan == NULL) { lf_print("Socket already closed."); return 0; } - sst_priv_t* priv = get_sst_priv_t(drv); + sst_priv_t* priv = get_sst_priv_t(chan); int ret = shutdown_socket(&priv->socket_priv->socket_descriptor, read_before_closing); if (ret != 0) { lf_print_error("Failed to shutdown socket."); } - free_netdrv(drv); + free_netchan(chan); return ret; } // END of TODO: // Get/set functions. -int32_t get_my_port(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +int32_t get_my_port(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); return priv->socket_priv->port; } -int32_t get_server_port(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +int32_t get_server_port(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); return priv->socket_priv->server_port; } -struct in_addr* get_ip_addr(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +struct in_addr* get_ip_addr(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); return &priv->socket_priv->server_ip_addr; } -char* get_server_hostname(netdrv_t drv) { - sst_priv_t* priv = get_sst_priv_t(drv); +char* get_server_hostname(netchan_t chan) { + sst_priv_t* priv = get_sst_priv_t(chan); return priv->socket_priv->server_hostname; } -void set_my_port(netdrv_t drv, int32_t port) { - sst_priv_t* priv = get_sst_priv_t(drv); +void set_my_port(netchan_t chan, int32_t port) { + sst_priv_t* priv = get_sst_priv_t(chan); priv->socket_priv->port = port; } -void set_server_port(netdrv_t drv, int32_t port) { - sst_priv_t* priv = get_sst_priv_t(drv); +void set_server_port(netchan_t chan, int32_t port) { + sst_priv_t* priv = get_sst_priv_t(chan); priv->socket_priv->server_port = port; } -void set_server_hostname(netdrv_t drv, const char* hostname) { - sst_priv_t* priv = get_sst_priv_t(drv); +void set_server_hostname(netchan_t chan, const char* hostname) { + sst_priv_t* priv = get_sst_priv_t(chan); memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); } From d1a967a0ced46e496adadd0e38ce9c3cce2f1a78 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 14 Mar 2025 09:41:50 +0900 Subject: [PATCH 028/105] Minor change --- network/api/net_driver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/api/net_driver.h b/network/api/net_driver.h index d21683e59..561ce0dcb 100644 --- a/network/api/net_driver.h +++ b/network/api/net_driver.h @@ -94,7 +94,7 @@ int read_from_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned * a negative number for an error. */ void read_from_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, - char* format, ...); + char* format, ...); /** * Write the specified number of bytes to the specified network channel from the @@ -135,7 +135,7 @@ int write_to_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned c * to print a generic error message. */ void write_to_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, - char* format, ...); + char* format, ...); /** * Checks if the network channel is still connected to the peer. From ff0aecf90cd60b25946f65393d09ab49a4579a37 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 10 Nov 2025 15:16:43 -0700 Subject: [PATCH 029/105] Add include to sst support.h --- network/api/net_abstraction.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index 834cc8497..37d617071 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -16,6 +16,9 @@ #define NET_ABSTRACTION_H #include "socket_common.h" +#if defined(COMM_TYPE_SST) +#include "lf_sst_support.h" +#endif typedef void* net_abstraction_t; // net_abstraction_t From 813d3f00d41b5696d2d9d1b743718bb5cfe11028 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 10 Nov 2025 15:34:26 -0700 Subject: [PATCH 030/105] Add find openssl in cmake. --- network/impl/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/network/impl/CMakeLists.txt b/network/impl/CMakeLists.txt index e078e9e86..116f7db1e 100644 --- a/network/impl/CMakeLists.txt +++ b/network/impl/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(lf-network-impl PUBLIC if(COMM_TYPE MATCHES TCP) target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_socket_support.c) elseif(COMM_TYPE MATCHES SST) + find_package(OpenSSL REQUIRED) find_package(sst-lib REQUIRED) target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_sst_support.c) target_link_libraries(lf-network-impl PUBLIC sst-lib::sst-c-api) From 28e64cc9987bc1ae5955968f7f08d86dbd1b853d Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 10 Nov 2025 15:36:03 -0700 Subject: [PATCH 031/105] Fix to netchan to net_abstraction --- network/impl/src/lf_sst_support.c | 76 +++++++++++++++---------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 5c49493f2..e9ad43a58 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -1,21 +1,21 @@ #include // malloc() #include // strncpy() -#include "net_driver.h" +#include "net_abstraction.h" #include "lf_sst_support.h" #include "util.h" const char* sst_config_path; // The SST's configuration file path. -static sst_priv_t* get_sst_priv_t(netchan_t chan) { +static sst_priv_t* get_sst_priv_t(net_abstraction_t chan) { if (chan == NULL) { - lf_print_error("Network driver is already closed."); + lf_print_error("Network abstraction is already closed."); return NULL; } return (sst_priv_t*)chan; } -netchan_t initialize_netchan() { +net_abstraction_t initialize_net_abstraction() { // Initialize sst_priv. sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); if (sst_priv == NULL) { @@ -43,16 +43,16 @@ netchan_t initialize_netchan() { sst_priv->sst_ctx = NULL; sst_priv->session_ctx = NULL; - return (netchan_t)sst_priv; + return (net_abstraction_t)sst_priv; } -void free_netchan(netchan_t chan) { +void free_net_abstraction(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); free(priv->socket_priv); free(priv); } -int create_server(netchan_t chan, bool increment_port_on_retry) { +int create_server(net_abstraction_t chan, bool increment_port_on_retry) { sst_priv_t* priv = get_sst_priv_t(chan); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; @@ -60,23 +60,23 @@ int create_server(netchan_t chan, bool increment_port_on_retry) { &priv->socket_priv->port, TCP, increment_port_on_retry); } -netchan_t accept_netchan(netchan_t server_chan, netchan_t rti_chan) { +net_abstraction_t accept_net_abstraction(net_abstraction_t server_chan, net_abstraction_t rti_chan) { sst_priv_t* serv_priv = get_sst_priv_t(server_chan); int rti_socket; if (rti_chan == NULL) { - // Set to -1, to indicate that this accept_netchan() call is not trying to check if the rti_chan is available, inside - // the accept_socket() function. + // Set to -1, to indicate that this accept_net_abstraction() call is not trying to check if the rti_chan is + // available, inside the accept_socket() function. rti_socket = -1; } else { sst_priv_t* rti_priv = get_sst_priv_t(rti_chan); rti_socket = rti_priv->socket_priv->socket_descriptor; } - netchan_t fed_netchan = initialize_netchan(); - sst_priv_t* fed_priv = get_sst_priv_t(fed_netchan); + net_abstraction_t fed_net_abstraction = initialize_net_abstraction(); + sst_priv_t* fed_priv = get_sst_priv_t(fed_net_abstraction); int sock = accept_socket(serv_priv->socket_priv->socket_descriptor, rti_socket); if (sock == -1) { - free_netchan(fed_netchan); + free_net_abstraction(fed_net_abstraction); return NULL; } fed_priv->socket_priv->socket_descriptor = sock; @@ -92,17 +92,17 @@ netchan_t accept_netchan(netchan_t server_chan, netchan_t rti_chan) { // Session key used is copied to the session_ctx. free_session_key_list_t(s_key_list); fed_priv->session_ctx = session_ctx; - return fed_netchan; + return fed_net_abstraction; } -void create_client(netchan_t chan) { +void create_client(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; } -int connect_to_netchan(netchan_t chan) { +int connect_to_net_abstraction(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); int ret = connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, priv->socket_priv->server_port); @@ -117,14 +117,14 @@ int connect_to_netchan(netchan_t chan) { } // TODO: Still need to fix... -int read_from_netchan(netchan_t chan, size_t num_bytes, unsigned char* buffer) { +int read_from_net_abstraction(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(chan); return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int read_from_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer) { +int read_from_net_abstraction_close_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(chan); - int read_failed = read_from_netchan(chan, num_bytes, buffer); + int read_failed = read_from_net_abstraction(chan, num_bytes, buffer); if (read_failed) { // Read failed. // Socket has probably been closed from the other side. @@ -135,10 +135,10 @@ int read_from_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned return 0; } -void read_from_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, - char* format, ...) { +void read_from_net_abstraction_fail_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer, + lf_mutex_t* mutex, char* format, ...) { va_list args; - int read_failed = read_from_netchan_close_on_error(chan, num_bytes, buffer); + int read_failed = read_from_net_abstraction_close_on_error(chan, num_bytes, buffer); if (read_failed) { // Read failed. if (mutex != NULL) { @@ -154,14 +154,14 @@ void read_from_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned } } -int write_to_netchan(netchan_t chan, size_t num_bytes, unsigned char* buffer) { +int write_to_net_abstraction(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(chan); return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int write_to_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer) { +int write_to_net_abstraction_close_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(chan); - int result = write_to_netchan(chan, num_bytes, buffer); + int result = write_to_net_abstraction(chan, num_bytes, buffer); if (result) { // Write failed. // Socket has probably been closed from the other side. @@ -171,10 +171,10 @@ int write_to_netchan_close_on_error(netchan_t chan, size_t num_bytes, unsigned c return result; } -void write_to_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, - char* format, ...) { +void write_to_net_abstraction_fail_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer, + lf_mutex_t* mutex, char* format, ...) { va_list args; - int result = write_to_netchan_close_on_error(chan, num_bytes, buffer); + int result = write_to_net_abstraction_close_on_error(chan, num_bytes, buffer); if (result) { // Write failed. if (mutex != NULL) { @@ -190,12 +190,12 @@ void write_to_netchan_fail_on_error(netchan_t chan, size_t num_bytes, unsigned c } } -bool check_netchan_closed(netchan_t chan) { +bool check_net_abstraction_closed(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); return check_socket_closed(priv->socket_priv->socket_descriptor); } -int shutdown_netchan(netchan_t chan, bool read_before_closing) { +int shutdown_net_abstraction(net_abstraction_t chan, bool read_before_closing) { if (chan == NULL) { lf_print("Socket already closed."); return 0; @@ -205,43 +205,43 @@ int shutdown_netchan(netchan_t chan, bool read_before_closing) { if (ret != 0) { lf_print_error("Failed to shutdown socket."); } - free_netchan(chan); + free_net_abstraction(chan); return ret; } // END of TODO: // Get/set functions. -int32_t get_my_port(netchan_t chan) { +int32_t get_my_port(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); return priv->socket_priv->port; } -int32_t get_server_port(netchan_t chan) { +int32_t get_server_port(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); return priv->socket_priv->server_port; } -struct in_addr* get_ip_addr(netchan_t chan) { +struct in_addr* get_ip_addr(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); return &priv->socket_priv->server_ip_addr; } -char* get_server_hostname(netchan_t chan) { +char* get_server_hostname(net_abstraction_t chan) { sst_priv_t* priv = get_sst_priv_t(chan); return priv->socket_priv->server_hostname; } -void set_my_port(netchan_t chan, int32_t port) { +void set_my_port(net_abstraction_t chan, int32_t port) { sst_priv_t* priv = get_sst_priv_t(chan); priv->socket_priv->port = port; } -void set_server_port(netchan_t chan, int32_t port) { +void set_server_port(net_abstraction_t chan, int32_t port) { sst_priv_t* priv = get_sst_priv_t(chan); priv->socket_priv->server_port = port; } -void set_server_hostname(netchan_t chan, const char* hostname) { +void set_server_hostname(net_abstraction_t chan, const char* hostname) { sst_priv_t* priv = get_sst_priv_t(chan); memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); } From e21fed9256966d982425475868030e6f2b0fc8b7 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 10 Nov 2025 15:40:19 -0700 Subject: [PATCH 032/105] Minor fix on name. --- network/impl/src/lf_sst_support.c | 95 +++++++++++++++---------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index e9ad43a58..35ee94ad4 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -7,12 +7,12 @@ const char* sst_config_path; // The SST's configuration file path. -static sst_priv_t* get_sst_priv_t(net_abstraction_t chan) { - if (chan == NULL) { +static sst_priv_t* get_sst_priv_t(net_abstraction_t net_abs) { + if (net_abs == NULL) { lf_print_error("Network abstraction is already closed."); return NULL; } - return (sst_priv_t*)chan; + return (sst_priv_t*)net_abs; } net_abstraction_t initialize_net_abstraction() { @@ -46,14 +46,14 @@ net_abstraction_t initialize_net_abstraction() { return (net_abstraction_t)sst_priv; } -void free_net_abstraction(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +void free_net_abstraction(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); free(priv->socket_priv); free(priv); } -int create_server(net_abstraction_t chan, bool increment_port_on_retry) { - sst_priv_t* priv = get_sst_priv_t(chan); +int create_server(net_abstraction_t net_abs, bool increment_port_on_retry) { + sst_priv_t* priv = get_sst_priv_t(net_abs); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, @@ -95,15 +95,15 @@ net_abstraction_t accept_net_abstraction(net_abstraction_t server_chan, net_abst return fed_net_abstraction; } -void create_client(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +void create_client(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; } -int connect_to_net_abstraction(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +int connect_to_net_abstraction(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); int ret = connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, priv->socket_priv->server_port); if (ret != 0) { @@ -117,14 +117,14 @@ int connect_to_net_abstraction(net_abstraction_t chan) { } // TODO: Still need to fix... -int read_from_net_abstraction(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(chan); +int read_from_net_abstraction(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int read_from_net_abstraction_close_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(chan); - int read_failed = read_from_net_abstraction(chan, num_bytes, buffer); +int read_from_net_abstraction_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(net_abs); + int read_failed = read_from_net_abstraction(net_abs, num_bytes, buffer); if (read_failed) { // Read failed. // Socket has probably been closed from the other side. @@ -135,15 +135,12 @@ int read_from_net_abstraction_close_on_error(net_abstraction_t chan, size_t num_ return 0; } -void read_from_net_abstraction_fail_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer, - lf_mutex_t* mutex, char* format, ...) { +void read_from_net_abstraction_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, + char* format, ...) { va_list args; - int read_failed = read_from_net_abstraction_close_on_error(chan, num_bytes, buffer); + int read_failed = read_from_net_abstraction_close_on_error(net_abs, num_bytes, buffer); if (read_failed) { // Read failed. - if (mutex != NULL) { - LF_MUTEX_UNLOCK(mutex); - } if (format != NULL) { va_start(args, format); lf_print_error_system_failure(format, args); @@ -154,14 +151,14 @@ void read_from_net_abstraction_fail_on_error(net_abstraction_t chan, size_t num_ } } -int write_to_net_abstraction(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(chan); +int write_to_net_abstraction(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int write_to_net_abstraction_close_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(chan); - int result = write_to_net_abstraction(chan, num_bytes, buffer); +int write_to_net_abstraction_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + sst_priv_t* priv = get_sst_priv_t(net_abs); + int result = write_to_net_abstraction(net_abs, num_bytes, buffer); if (result) { // Write failed. // Socket has probably been closed from the other side. @@ -171,10 +168,10 @@ int write_to_net_abstraction_close_on_error(net_abstraction_t chan, size_t num_b return result; } -void write_to_net_abstraction_fail_on_error(net_abstraction_t chan, size_t num_bytes, unsigned char* buffer, +void write_to_net_abstraction_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, char* format, ...) { va_list args; - int result = write_to_net_abstraction_close_on_error(chan, num_bytes, buffer); + int result = write_to_net_abstraction_close_on_error(net_abs, num_bytes, buffer); if (result) { // Write failed. if (mutex != NULL) { @@ -190,59 +187,59 @@ void write_to_net_abstraction_fail_on_error(net_abstraction_t chan, size_t num_b } } -bool check_net_abstraction_closed(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +bool check_net_abstraction_closed(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return check_socket_closed(priv->socket_priv->socket_descriptor); } -int shutdown_net_abstraction(net_abstraction_t chan, bool read_before_closing) { - if (chan == NULL) { +int shutdown_net_abstraction(net_abstraction_t net_abs, bool read_before_closing) { + if (net_abs == NULL) { lf_print("Socket already closed."); return 0; } - sst_priv_t* priv = get_sst_priv_t(chan); + sst_priv_t* priv = get_sst_priv_t(net_abs); int ret = shutdown_socket(&priv->socket_priv->socket_descriptor, read_before_closing); if (ret != 0) { lf_print_error("Failed to shutdown socket."); } - free_net_abstraction(chan); + free_net_abstraction(net_abs); return ret; } // END of TODO: // Get/set functions. -int32_t get_my_port(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +int32_t get_my_port(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return priv->socket_priv->port; } -int32_t get_server_port(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +int32_t get_server_port(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return priv->socket_priv->server_port; } -struct in_addr* get_ip_addr(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +struct in_addr* get_ip_addr(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return &priv->socket_priv->server_ip_addr; } -char* get_server_hostname(net_abstraction_t chan) { - sst_priv_t* priv = get_sst_priv_t(chan); +char* get_server_hostname(net_abstraction_t net_abs) { + sst_priv_t* priv = get_sst_priv_t(net_abs); return priv->socket_priv->server_hostname; } -void set_my_port(net_abstraction_t chan, int32_t port) { - sst_priv_t* priv = get_sst_priv_t(chan); +void set_my_port(net_abstraction_t net_abs, int32_t port) { + sst_priv_t* priv = get_sst_priv_t(net_abs); priv->socket_priv->port = port; } -void set_server_port(net_abstraction_t chan, int32_t port) { - sst_priv_t* priv = get_sst_priv_t(chan); +void set_server_port(net_abstraction_t net_abs, int32_t port) { + sst_priv_t* priv = get_sst_priv_t(net_abs); priv->socket_priv->server_port = port; } -void set_server_hostname(net_abstraction_t chan, const char* hostname) { - sst_priv_t* priv = get_sst_priv_t(chan); +void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { + sst_priv_t* priv = get_sst_priv_t(net_abs); memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); } From d2774200eac932ae84ef2900bbd4c0d84aced314 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 30 Jan 2026 09:59:31 -0700 Subject: [PATCH 033/105] Change api function name. --- network/impl/src/lf_sst_support.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 35ee94ad4..f817a6051 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -15,7 +15,7 @@ static sst_priv_t* get_sst_priv_t(net_abstraction_t net_abs) { return (sst_priv_t*)net_abs; } -net_abstraction_t initialize_net_abstraction() { +net_abstraction_t initialize_net() { // Initialize sst_priv. sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); if (sst_priv == NULL) { @@ -46,7 +46,7 @@ net_abstraction_t initialize_net_abstraction() { return (net_abstraction_t)sst_priv; } -void free_net_abstraction(net_abstraction_t net_abs) { +void free_net(net_abstraction_t net_abs) { sst_priv_t* priv = get_sst_priv_t(net_abs); free(priv->socket_priv); free(priv); @@ -60,23 +60,23 @@ int create_server(net_abstraction_t net_abs, bool increment_port_on_retry) { &priv->socket_priv->port, TCP, increment_port_on_retry); } -net_abstraction_t accept_net_abstraction(net_abstraction_t server_chan, net_abstraction_t rti_chan) { +net_abstraction_t accept_net(net_abstraction_t server_chan, net_abstraction_t rti_chan) { sst_priv_t* serv_priv = get_sst_priv_t(server_chan); int rti_socket; if (rti_chan == NULL) { - // Set to -1, to indicate that this accept_net_abstraction() call is not trying to check if the rti_chan is + // Set to -1, to indicate that this accept_net() call is not trying to check if the rti_chan is // available, inside the accept_socket() function. rti_socket = -1; } else { sst_priv_t* rti_priv = get_sst_priv_t(rti_chan); rti_socket = rti_priv->socket_priv->socket_descriptor; } - net_abstraction_t fed_net_abstraction = initialize_net_abstraction(); - sst_priv_t* fed_priv = get_sst_priv_t(fed_net_abstraction); + net_abstraction_t fed_net = initialize_net(); + sst_priv_t* fed_priv = get_sst_priv_t(fed_net); int sock = accept_socket(serv_priv->socket_priv->socket_descriptor, rti_socket); if (sock == -1) { - free_net_abstraction(fed_net_abstraction); + free_net(fed_net); return NULL; } fed_priv->socket_priv->socket_descriptor = sock; @@ -92,7 +92,7 @@ net_abstraction_t accept_net_abstraction(net_abstraction_t server_chan, net_abst // Session key used is copied to the session_ctx. free_session_key_list_t(s_key_list); fed_priv->session_ctx = session_ctx; - return fed_net_abstraction; + return fed_net; } void create_client(net_abstraction_t net_abs) { @@ -102,7 +102,7 @@ void create_client(net_abstraction_t net_abs) { priv->sst_ctx = ctx; } -int connect_to_net_abstraction(net_abstraction_t net_abs) { +int connect_to_net(net_abstraction_t net_abs) { sst_priv_t* priv = get_sst_priv_t(net_abs); int ret = connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, priv->socket_priv->server_port); @@ -117,14 +117,14 @@ int connect_to_net_abstraction(net_abstraction_t net_abs) { } // TODO: Still need to fix... -int read_from_net_abstraction(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { +int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(net_abs); return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int read_from_net_abstraction_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { +int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(net_abs); - int read_failed = read_from_net_abstraction(net_abs, num_bytes, buffer); + int read_failed = read_from_net(net_abs, num_bytes, buffer); if (read_failed) { // Read failed. // Socket has probably been closed from the other side. @@ -135,10 +135,10 @@ int read_from_net_abstraction_close_on_error(net_abstraction_t net_abs, size_t n return 0; } -void read_from_net_abstraction_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, +void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, char* format, ...) { va_list args; - int read_failed = read_from_net_abstraction_close_on_error(net_abs, num_bytes, buffer); + int read_failed = read_from_net_close_on_error(net_abs, num_bytes, buffer); if (read_failed) { // Read failed. if (format != NULL) { @@ -151,14 +151,14 @@ void read_from_net_abstraction_fail_on_error(net_abstraction_t net_abs, size_t n } } -int write_to_net_abstraction(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { +int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(net_abs); return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } -int write_to_net_abstraction_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { +int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { sst_priv_t* priv = get_sst_priv_t(net_abs); - int result = write_to_net_abstraction(net_abs, num_bytes, buffer); + int result = write_to_net(net_abs, num_bytes, buffer); if (result) { // Write failed. // Socket has probably been closed from the other side. @@ -168,10 +168,10 @@ int write_to_net_abstraction_close_on_error(net_abstraction_t net_abs, size_t nu return result; } -void write_to_net_abstraction_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, +void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, char* format, ...) { va_list args; - int result = write_to_net_abstraction_close_on_error(net_abs, num_bytes, buffer); + int result = write_to_net_close_on_error(net_abs, num_bytes, buffer); if (result) { // Write failed. if (mutex != NULL) { @@ -187,12 +187,12 @@ void write_to_net_abstraction_fail_on_error(net_abstraction_t net_abs, size_t nu } } -bool check_net_abstraction_closed(net_abstraction_t net_abs) { +bool check_net_closed(net_abstraction_t net_abs) { sst_priv_t* priv = get_sst_priv_t(net_abs); return check_socket_closed(priv->socket_priv->socket_descriptor); } -int shutdown_net_abstraction(net_abstraction_t net_abs, bool read_before_closing) { +int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { if (net_abs == NULL) { lf_print("Socket already closed."); return 0; @@ -202,7 +202,7 @@ int shutdown_net_abstraction(net_abstraction_t net_abs, bool read_before_closing if (ret != 0) { lf_print_error("Failed to shutdown socket."); } - free_net_abstraction(net_abs); + free_net(net_abs); return ret; } // END of TODO: From b8f189b3914fefbb2929ce19aff8b06e81ec1b12 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 30 Jan 2026 15:03:45 -0700 Subject: [PATCH 034/105] Fix to match newest network abstraction version. --- network/impl/src/lf_sst_support.c | 166 ++++++++++++------------------ 1 file changed, 63 insertions(+), 103 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index f817a6051..c265e5784 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -7,14 +7,6 @@ const char* sst_config_path; // The SST's configuration file path. -static sst_priv_t* get_sst_priv_t(net_abstraction_t net_abs) { - if (net_abs == NULL) { - lf_print_error("Network abstraction is already closed."); - return NULL; - } - return (sst_priv_t*)net_abs; -} - net_abstraction_t initialize_net() { // Initialize sst_priv. sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); @@ -47,83 +39,89 @@ net_abstraction_t initialize_net() { } void free_net(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); + if (net_abs == NULL) { + LF_PRINT_LOG("Socket already closed."); + return; + } + sst_priv_t* priv = (sst_priv_t*)net_abs; free(priv->socket_priv); free(priv); } -int create_server(net_abstraction_t net_abs, bool increment_port_on_retry) { - sst_priv_t* priv = get_sst_priv_t(net_abs); +int create_server(net_abstraction_t net_abs) { + sst_priv_t* priv = (sst_priv_t*)net_abs; SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, - &priv->socket_priv->port, TCP, increment_port_on_retry); + &priv->socket_priv->port, TCP); } -net_abstraction_t accept_net(net_abstraction_t server_chan, net_abstraction_t rti_chan) { - sst_priv_t* serv_priv = get_sst_priv_t(server_chan); - int rti_socket; - if (rti_chan == NULL) { - // Set to -1, to indicate that this accept_net() call is not trying to check if the rti_chan is - // available, inside the accept_socket() function. - rti_socket = -1; - } else { - sst_priv_t* rti_priv = get_sst_priv_t(rti_chan); - rti_socket = rti_priv->socket_priv->socket_descriptor; - } - net_abstraction_t fed_net = initialize_net(); - sst_priv_t* fed_priv = get_sst_priv_t(fed_net); +// TODO: check new implementation. +net_abstraction_t accept_net(net_abstraction_t server_chan) { + + LF_ASSERT_NON_NULL(server_chan); + sst_priv_t* serv_priv = (sst_priv_t*)server_chan; + + int sock = accept_socket(serv_priv->socket_priv->socket_descriptor); + if (sock != -1) { + net_abstraction_t client_net = initialize_net(); + sst_priv_t* client_priv = (sst_priv_t*)client_net; + client_priv->socket_priv->socket_descriptor = sock; + // Get the peer address from the connected socket_id. Saving this for the address query. + if (get_peer_address(client_priv->socket_priv) != 0) { + lf_print_error("Failed to save peer address."); + } - int sock = accept_socket(serv_priv->socket_priv->socket_descriptor, rti_socket); - if (sock == -1) { - free_net(fed_net); + // TODO: Do we need to copy sst_ctx form server_chan to fed_chan? + session_key_list_t* s_key_list = init_empty_session_key_list(); + SST_session_ctx_t* session_ctx = + server_secure_comm_setup(serv_priv->sst_ctx, client_priv->socket_priv->socket_descriptor, s_key_list); + // Session key used is copied to the session_ctx. + free_session_key_list_t(s_key_list); + client_priv->session_ctx = session_ctx; + + return client_net; + } else { return NULL; } - fed_priv->socket_priv->socket_descriptor = sock; - // Get the peer address from the connected socket_id. Saving this for the address query. - if (get_peer_address(fed_priv->socket_priv) != 0) { - lf_print_error("RTI failed to get peer address."); - }; - - // TODO: Do we need to copy sst_ctx form server_chan to fed_chan? - session_key_list_t* s_key_list = init_empty_session_key_list(); - SST_session_ctx_t* session_ctx = - server_secure_comm_setup(serv_priv->sst_ctx, fed_priv->socket_priv->socket_descriptor, s_key_list); - // Session key used is copied to the session_ctx. - free_session_key_list_t(s_key_list); - fed_priv->session_ctx = session_ctx; - return fed_net; } void create_client(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); + sst_priv_t* priv = (sst_priv_t*)net_abs; priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; } -int connect_to_net(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - int ret = connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, - priv->socket_priv->server_port); - if (ret != 0) { - return ret; +net_abstraction_t connect_to_net(net_params_t* params) { + // Create a network abstraction. + net_abstraction_t net = initialize_net(); + sst_priv_t* priv = (sst_priv_t*)net; + socket_connection_parameters_t* sock_params = (socket_connection_parameters_t*)params; + priv->socket_priv->server_port = sock_params->port; + memcpy(priv->socket_priv->server_hostname, sock_params->server_hostname, INET_ADDRSTRLEN); + // Create the client network abstraction. + create_client(net); + // Connect to the target server. + if (connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, priv->socket_priv->server_port) != 0) { + lf_print_error("Failed to connect to socket."); + return NULL; } session_key_list_t* s_key_list = get_session_key(priv->sst_ctx, NULL); SST_session_ctx_t* session_ctx = secure_connect_to_server_with_socket(&s_key_list->s_key[0], priv->socket_priv->socket_descriptor); priv->session_ctx = session_ctx; - return 0; + return net; } // TODO: Still need to fix... int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(net_abs); + sst_priv_t* priv = (sst_priv_t*)net_abs; return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(net_abs); + sst_priv_t* priv = (sst_priv_t*)net_abs; int read_failed = read_from_net(net_abs, num_bytes, buffer); if (read_failed) { // Read failed. @@ -135,8 +133,8 @@ int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, un return 0; } -void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, - char* format, ...) { +void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, char* format, + ...) { va_list args; int read_failed = read_from_net_close_on_error(net_abs, num_bytes, buffer); if (read_failed) { @@ -152,12 +150,12 @@ void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, un } int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(net_abs); + sst_priv_t* priv = (sst_priv_t*)net_abs; return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { - sst_priv_t* priv = get_sst_priv_t(net_abs); + sst_priv_t* priv = (sst_priv_t*)net_abs; int result = write_to_net(net_abs, num_bytes, buffer); if (result) { // Write failed. @@ -168,8 +166,8 @@ int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, uns return result; } -void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, - lf_mutex_t* mutex, char* format, ...) { +void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, + char* format, ...) { va_list args; int result = write_to_net_close_on_error(net_abs, num_bytes, buffer); if (result) { @@ -187,61 +185,23 @@ void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, uns } } -bool check_net_closed(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - return check_socket_closed(priv->socket_priv->socket_descriptor); +bool is_net_open(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + return is_socket_open(priv->socket_descriptor); } int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { if (net_abs == NULL) { - lf_print("Socket already closed."); + LF_PRINT_LOG("Socket already closed."); return 0; } - sst_priv_t* priv = get_sst_priv_t(net_abs); - int ret = shutdown_socket(&priv->socket_priv->socket_descriptor, read_before_closing); - if (ret != 0) { - lf_print_error("Failed to shutdown socket."); - } + socket_priv_t* priv = (socket_priv_t*)net_abs; + int ret = shutdown_socket(&priv->socket_descriptor, read_before_closing); free_net(net_abs); return ret; } // END of TODO: -// Get/set functions. -int32_t get_my_port(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - return priv->socket_priv->port; -} - -int32_t get_server_port(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - return priv->socket_priv->server_port; -} - -struct in_addr* get_ip_addr(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - return &priv->socket_priv->server_ip_addr; -} - -char* get_server_hostname(net_abstraction_t net_abs) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - return priv->socket_priv->server_hostname; -} - -void set_my_port(net_abstraction_t net_abs, int32_t port) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - priv->socket_priv->port = port; -} - -void set_server_port(net_abstraction_t net_abs, int32_t port) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - priv->socket_priv->server_port = port; -} - -void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { - sst_priv_t* priv = get_sst_priv_t(net_abs); - memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); -} - // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From de9bc3c53762c05791655228233163808721e317 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 2 Feb 2026 15:19:35 -0700 Subject: [PATCH 035/105] Add assert on net_abs. --- network/impl/src/lf_sst_support.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index c265e5784..7eb2bd554 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -34,7 +34,6 @@ net_abstraction_t initialize_net() { // SST initialization. Only set pointers to NULL. sst_priv->sst_ctx = NULL; sst_priv->session_ctx = NULL; - return (net_abstraction_t)sst_priv; } @@ -49,6 +48,7 @@ void free_net(net_abstraction_t net_abs) { } int create_server(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; SST_ctx_t* ctx = init_SST(sst_config_path); priv->sst_ctx = ctx; @@ -58,7 +58,6 @@ int create_server(net_abstraction_t net_abs) { // TODO: check new implementation. net_abstraction_t accept_net(net_abstraction_t server_chan) { - LF_ASSERT_NON_NULL(server_chan); sst_priv_t* serv_priv = (sst_priv_t*)server_chan; @@ -87,6 +86,7 @@ net_abstraction_t accept_net(net_abstraction_t server_chan) { } void create_client(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); SST_ctx_t* ctx = init_SST(sst_config_path); @@ -116,11 +116,13 @@ net_abstraction_t connect_to_net(net_params_t* params) { // TODO: Still need to fix... int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; int read_failed = read_from_net(net_abs, num_bytes, buffer); if (read_failed) { @@ -135,6 +137,7 @@ int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, un void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, char* format, ...) { + LF_ASSERT_NON_NULL(net_abs); va_list args; int read_failed = read_from_net_close_on_error(net_abs, num_bytes, buffer); if (read_failed) { @@ -150,11 +153,13 @@ void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, un } int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; int result = write_to_net(net_abs, num_bytes, buffer); if (result) { @@ -168,6 +173,7 @@ int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, uns void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, char* format, ...) { + LF_ASSERT_NON_NULL(net_abs); va_list args; int result = write_to_net_close_on_error(net_abs, num_bytes, buffer); if (result) { From e7347c3a5d3752416ccfcfc75a339246f744e04e Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 2 Feb 2026 15:20:10 -0700 Subject: [PATCH 036/105] Fix to set port on the net_abs. Need to fix to set function in future... --- core/federated/RTI/rti_remote.c | 10 +++++----- core/federated/federate.c | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 60c8e6af5..3ba6727f4 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -650,9 +650,9 @@ void handle_address_query(uint16_t fed_id) { // The network abstraction is initialized, but the RTI might still not know the port number. This can happen if the // RTI has not yet received a MSG_TYPE_ADDRESS_ADVERTISEMENT message from the remote federate. In such cases, the // returned port number might still be -1. - server_port = ((socket_priv_t*)remote_fed->net)->server_port; - ip_address = (uint32_t*)&((socket_priv_t*)remote_fed->net)->server_ip_addr; - server_host_name = ((socket_priv_t*)remote_fed->net)->server_hostname; + server_port = (((sst_priv_t*)remote_fed->net)->socket_priv)->server_port; + ip_address = (uint32_t*)&(((sst_priv_t*)remote_fed->net)->socket_priv)->server_ip_addr; + server_host_name = (((sst_priv_t*)remote_fed->net)->socket_priv)->server_hostname; } encode_int32(server_port, (unsigned char*)&buffer[1]); @@ -683,7 +683,7 @@ void handle_address_ad(uint16_t federate_id) { assert(server_port < 65536); LF_MUTEX_LOCK(&rti_mutex); - ((socket_priv_t*)fed->net)->server_port = server_port; + (((sst_priv_t*)fed->net)->socket_priv)->server_port = server_port; LF_MUTEX_UNLOCK(&rti_mutex); LF_PRINT_LOG("Received address advertisement with port %d from federate %d.", server_port, federate_id); @@ -1503,7 +1503,7 @@ int start_rti_server() { // Initialize RTI's network abstraction. rti_remote->rti_net = initialize_net(); // Set the user specified port to the network abstraction. - ((socket_priv_t*)rti_remote->rti_net)->user_specified_port = rti_remote->user_specified_port; + (((sst_priv_t*)rti_remote->rti_net)->socket_priv)->user_specified_port = rti_remote->user_specified_port; // Create the server if (create_server(rti_remote->rti_net)) { lf_print_error_system_failure("RTI failed to create TCP server: %s.", strerror(errno)); diff --git a/core/federated/federate.c b/core/federated/federate.c index 907871181..027e816ed 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1929,14 +1929,13 @@ void lf_create_server(int specified_port) { assert(specified_port <= UINT16_MAX && specified_port >= 0); net_abstraction_t* server_net = initialize_net(); - ((socket_priv_t*)server_net)->port = (uint16_t)specified_port; - + ((sst_priv_t*)server_net)->socket_priv->port = (uint16_t)specified_port; if (create_server(server_net)) { lf_print_error_system_failure("RTI failed to create server: %s.", strerror(errno)); }; _fed.server_net = server_net; // Get the final server port to send to the RTI on an MSG_TYPE_ADDRESS_ADVERTISEMENT message. - int32_t server_port = ((socket_priv_t*)server_net)->port; + int32_t server_port = ((sst_priv_t*)server_net)->socket_priv->port; LF_PRINT_LOG("Server for communicating with other federates started using port %d.", server_port); From 46cdaaef68b62953a89e432d86627d69bc31b389 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 2 Feb 2026 17:57:23 -0700 Subject: [PATCH 037/105] Fix to correct net_abs casting from socket to sst. --- network/impl/src/lf_sst_support.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 7eb2bd554..64d88832c 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -193,8 +193,8 @@ void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, uns bool is_net_open(net_abstraction_t net_abs) { LF_ASSERT_NON_NULL(net_abs); - socket_priv_t* priv = (socket_priv_t*)net_abs; - return is_socket_open(priv->socket_descriptor); + sst_priv_t* priv = (sst_priv_t*)net_abs; + return is_socket_open(priv->socket_priv->socket_descriptor); } int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { @@ -202,8 +202,8 @@ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { LF_PRINT_LOG("Socket already closed."); return 0; } - socket_priv_t* priv = (socket_priv_t*)net_abs; - int ret = shutdown_socket(&priv->socket_descriptor, read_before_closing); + sst_priv_t* priv = (sst_priv_t*)net_abs; + int ret = shutdown_socket(&priv->socket_priv->socket_descriptor, read_before_closing); free_net(net_abs); return ret; } From fc8080f86693c586809dbd2387372458f147c2f8 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 2 Feb 2026 22:03:10 -0700 Subject: [PATCH 038/105] Add secure read and write using SST API functions. --- network/api/lf_sst_support.h | 3 ++ network/impl/src/lf_sst_support.c | 60 +++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/network/api/lf_sst_support.h b/network/api/lf_sst_support.h index 7fdb941ab..181fe77e0 100644 --- a/network/api/lf_sst_support.h +++ b/network/api/lf_sst_support.h @@ -8,6 +8,9 @@ typedef struct sst_priv_t { socket_priv_t* socket_priv; SST_ctx_t* sst_ctx; SST_session_ctx_t* session_ctx; + unsigned char buffer[MAX_SECURE_COMM_MSG_LENGTH]; + size_t buf_filled; + size_t buf_off; } sst_priv_t; void lf_set_sst_config_path(const char* config_path); diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 64d88832c..2ec659d15 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -30,6 +30,8 @@ net_abstraction_t initialize_net() { socket_priv->server_port = -1; sst_priv->socket_priv = socket_priv; + sst_priv->buf_filled = 0; + sst_priv->buf_off = 0; // SST initialization. Only set pointers to NULL. sst_priv->sst_ctx = NULL; @@ -114,11 +116,62 @@ net_abstraction_t connect_to_net(net_params_t* params) { return net; } -// TODO: Still need to fix... int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; - return read_from_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); + + if (num_bytes > MAX_SECURE_COMM_MSG_LENGTH) { + lf_print_error("Unable to handle message. Expected: %zu, Maximum: %d", num_bytes, MAX_SECURE_COMM_MSG_LENGTH); + return -1; + } + int copied = 0; + // 1) First use buffered data. + if (priv->buf_off < priv->buf_filled) { + size_t avail = priv->buf_filled - priv->buf_off; + size_t to_copy = (avail < num_bytes) ? avail : num_bytes; + memcpy(buffer, priv->buffer + priv->buf_off, to_copy); + priv->buf_off += to_copy; + copied += to_copy; + + // Reset buffer offset when the buffer is all used. + if (priv->buf_off == priv->buf_filled) { + priv->buf_off = priv->buf_filled = 0; + } + + // Return when the buffered data is enough. + if (copied == num_bytes) { + return 0; + } + } + + // 2) Additionally try to read more bytes. + while (copied < num_bytes) { + int ret = read_secure_message(priv->buffer, priv->session_ctx); + if (ret == 0) { + // EOF received. + return 1; + } else if (ret < 0) { + lf_print_error("read_secure_message failed: %d", ret); + return -1; + } + + // Mark the filled length and reset offset. + priv->buf_filled = (size_t)ret; + priv->buf_off = 0; + + size_t need = num_bytes - copied; + size_t to_copy = (priv->buf_filled < need) ? priv->buf_filled : need; + memcpy(buffer + copied, priv->buffer + priv->buf_off, to_copy); + priv->buf_off += to_copy; + copied += to_copy; + + // Reset buffer offset when meets the end of the filled buffer. + if (priv->buf_off == priv->buf_filled) { + priv->buf_off = priv->buf_filled = 0; + } + } + + return 0; } int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { @@ -155,7 +208,8 @@ void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, un int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; - return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); + return send_secure_message((char *)buffer, (unsigned int) num_bytes, priv->session_ctx); + // return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { From b36044b796ae5affc6a7c4c2bb7988b8e7036824 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Thu, 5 Feb 2026 12:54:20 -0700 Subject: [PATCH 039/105] Add function `update_deadline` in Python target --- lib/schedule.c | 1 + python/include/pythontarget.h | 17 +++++++++++++++++ python/lib/pythontarget.c | 17 +++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/lib/schedule.c b/lib/schedule.c index 9c37213de..e7e78b9f7 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -91,6 +91,7 @@ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { } void lf_update_deadline(void* self, interval_t updated_deadline) { + LF_PRINT_DEBUG("lf_update_deadline: update deadline to %lld.", updated_deadline); reaction_t* reaction = ((self_base_t*)self)->executing_reaction; if (reaction != NULL) { reaction->deadline = updated_deadline; diff --git a/python/include/pythontarget.h b/python/include/pythontarget.h index 8afd744a9..e8475b9ca 100644 --- a/python/include/pythontarget.h +++ b/python/include/pythontarget.h @@ -102,6 +102,23 @@ PyObject* py_package_directory(PyObject* self, PyObject* args); */ PyObject* py_check_deadline(PyObject* self, PyObject* args); +/** + * @brief Update the deadline of the currently executing reaction. + * + * Updating the deadline with this function does not affect + * the deadline check that has been performed (at the beginning + * of the caller reaction or check_deadline called before). + * Therefore, you need to invoke check_deadline after + * update the deadline through this function to confirm + * whether the newly updated deadline has been violated. + * + * @param self The Python object of the reactor. + * @param args contains: + * - updated_deadline: The updated deadline. + * @return Py_None + */ +PyObject* py_update_deadline(PyObject* self, PyObject* args); + ////////////////////////////////////////////////////////////// ///////////// Main function callable from Python code diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 2787d9088..7a3e25a2e 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -240,6 +240,21 @@ PyObject* py_check_deadline(PyObject* self, PyObject* args) { return PyBool_FromLong(result); } +PyObject* py_update_deadline(PyObject* self, PyObject* args) { + PyObject* py_self; + int64_t updated_deadline = 0; // Default to 0 + + if (!PyArg_ParseTuple(args, "O|L", &py_self, &updated_deadline)) { + return NULL; + } + void* self_ptr = get_lf_self_pointer(py_self); + if (self_ptr == NULL) { + return NULL; + } + lf_update_deadline(self_ptr, updated_deadline); + return Py_None; +} + ////////////////////////////////////////////////////////////// ///////////// Main function callable from Python code @@ -293,6 +308,8 @@ static PyMethodDef GEN_NAME(MODULE_NAME, _methods)[] = { {"package_directory", py_package_directory, METH_NOARGS, "Root package directory path"}, {"check_deadline", (PyCFunction)py_check_deadline, METH_VARARGS, "Check whether the deadline of the currently executing reaction has passed"}, + {"update_deadline", (PyCFunction)py_update_deadline, METH_VARARGS, + "Update the deadline of the currently executing reaction"}, {NULL, NULL, 0, NULL}}; /** From 7955c34623472d3ac89e17bedd0a30845274977c Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Thu, 5 Feb 2026 13:02:40 -0700 Subject: [PATCH 040/105] Minor update --- lib/schedule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schedule.c b/lib/schedule.c index e7e78b9f7..c8aa6fb06 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -91,7 +91,7 @@ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { } void lf_update_deadline(void* self, interval_t updated_deadline) { - LF_PRINT_DEBUG("lf_update_deadline: update deadline to %lld.", updated_deadline); + LF_PRINT_DEBUG("lf_update_deadline: update deadline to %ld.", updated_deadline); reaction_t* reaction = ((self_base_t*)self)->executing_reaction; if (reaction != NULL) { reaction->deadline = updated_deadline; From 96c53bfc6b98249f0367ed20ee335c9b877e059a Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Thu, 5 Feb 2026 13:08:50 -0700 Subject: [PATCH 041/105] Apply formatter --- python/include/pythontarget.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/include/pythontarget.h b/python/include/pythontarget.h index e8475b9ca..47ae981c7 100644 --- a/python/include/pythontarget.h +++ b/python/include/pythontarget.h @@ -105,11 +105,11 @@ PyObject* py_check_deadline(PyObject* self, PyObject* args); /** * @brief Update the deadline of the currently executing reaction. * - * Updating the deadline with this function does not affect + * Updating the deadline with this function does not affect * the deadline check that has been performed (at the beginning * of the caller reaction or check_deadline called before). - * Therefore, you need to invoke check_deadline after - * update the deadline through this function to confirm + * Therefore, you need to invoke check_deadline after + * update the deadline through this function to confirm * whether the newly updated deadline has been violated. * * @param self The Python object of the reactor. From 6efb7a8125b207304ef4bab9fed5e4f5017383a6 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Thu, 5 Feb 2026 13:14:28 -0700 Subject: [PATCH 042/105] Point to python-update-deadline branch (Revert me) --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 1f7391f92..01d44e951 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master +python-update-deadline From 3e9e32a14916cd1aad0ec15cf1af0938ce58ee7e Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Thu, 5 Feb 2026 15:12:59 -0700 Subject: [PATCH 043/105] Minor fix --- lib/schedule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schedule.c b/lib/schedule.c index c8aa6fb06..dde40cc62 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -91,7 +91,7 @@ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { } void lf_update_deadline(void* self, interval_t updated_deadline) { - LF_PRINT_DEBUG("lf_update_deadline: update deadline to %ld.", updated_deadline); + LF_PRINT_DEBUG("lf_update_deadline: update deadline to " PRINTF_TIME ".", updated_deadline); reaction_t* reaction = ((self_base_t*)self)->executing_reaction; if (reaction != NULL) { reaction->deadline = updated_deadline; From 841dbcdc6c1b57c91ac7495a74e0e4040b574478 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Thu, 5 Feb 2026 16:52:12 -0700 Subject: [PATCH 044/105] Enable handling floating-point deadline values --- python/lib/pythontarget.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 7a3e25a2e..236a4f4ca 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -243,10 +243,22 @@ PyObject* py_check_deadline(PyObject* self, PyObject* args) { PyObject* py_update_deadline(PyObject* self, PyObject* args) { PyObject* py_self; int64_t updated_deadline = 0; // Default to 0 + double updated_deadline_in_double = + 0.0; // Deadline may be passed as a floating-point value in nanoseconds, e.g., SEC(0.5) → 0.5 * 1e9. - if (!PyArg_ParseTuple(args, "O|L", &py_self, &updated_deadline)) { + if (!PyArg_ParseTuple(args, "O|d", &py_self, &updated_deadline_in_double)) { return NULL; } + + // Check overflow before converting a double to int64_t (interval_t). + if (updated_deadline_in_double > (double)INT64_MAX || updated_deadline_in_double < (double)INT64_MIN) { + PyErr_SetString(PyExc_OverflowError, "The updated deadline value is out of int64 range"); + return NULL; + } + + // Convert double to int64_t + updated_deadline = (int64_t)updated_deadline_in_double; + void* self_ptr = get_lf_self_pointer(py_self); if (self_ptr == NULL) { return NULL; From b4b674376894353e37546101c9814d3dcb0f3484 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 6 Feb 2026 12:34:55 -0700 Subject: [PATCH 045/105] Fix log. --- core/federated/federate.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 027e816ed..62aa7c6d7 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1736,10 +1736,13 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { char hostname[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &host_ip_addr, hostname, INET_ADDRSTRLEN); - socket_connection_parameters_t params; - params.type = TCP; - params.port = uport; - params.server_hostname = hostname; + sst_connection_params_t params; + + params.socket_params.type = TCP; + params.socket_params.port = uport; + params.socket_params.server_hostname = hostname; + params.target = 1; + net_abstraction_t net = connect_to_net((net_params_t*)¶ms); if (net == NULL) { lf_print_error_and_exit("Failed to connect to federate."); @@ -1817,10 +1820,12 @@ void lf_connect_to_rti(const char* hostname, int port) { hostname = federation_metadata.rti_host ? federation_metadata.rti_host : hostname; port = federation_metadata.rti_port >= 0 ? federation_metadata.rti_port : port; - socket_connection_parameters_t params; - params.type = TCP; - params.port = port; - params.server_hostname = hostname; + sst_connection_params_t params; + + params.socket_params.type = TCP; + params.socket_params.port = port; + params.socket_params.server_hostname = hostname; + params.target = 0; net_abstraction_t net = connect_to_net((net_params_t*)¶ms); if (net == NULL) { lf_print_error_and_exit("Failed to connect to RTI."); @@ -1931,7 +1936,7 @@ void lf_create_server(int specified_port) { net_abstraction_t* server_net = initialize_net(); ((sst_priv_t*)server_net)->socket_priv->port = (uint16_t)specified_port; if (create_server(server_net)) { - lf_print_error_system_failure("RTI failed to create server: %s.", strerror(errno)); + lf_print_error_system_failure("Failed to create server: %s.", strerror(errno)); }; _fed.server_net = server_net; // Get the final server port to send to the RTI on an MSG_TYPE_ADDRESS_ADVERTISEMENT message. From 365836e9e88633147c484b539ea203ee6e0043dc Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 6 Feb 2026 12:36:12 -0700 Subject: [PATCH 046/105] Add sst_connection_params_t --- network/api/lf_sst_support.h | 7 +++++++ network/api/socket_common.h | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/network/api/lf_sst_support.h b/network/api/lf_sst_support.h index 181fe77e0..f4ed2709f 100644 --- a/network/api/lf_sst_support.h +++ b/network/api/lf_sst_support.h @@ -13,6 +13,13 @@ typedef struct sst_priv_t { size_t buf_off; } sst_priv_t; +typedef struct sst_connection_params_t { + socket_connection_params_t socket_params; + + // 0 for RTI, 1 for federates. + int target; +} sst_connection_params_t; + void lf_set_sst_config_path(const char* config_path); #endif /* LF_SST_SUPPORT_H */ diff --git a/network/api/socket_common.h b/network/api/socket_common.h index 4cfa8d89c..edab21dd8 100644 --- a/network/api/socket_common.h +++ b/network/api/socket_common.h @@ -124,7 +124,7 @@ */ typedef enum socket_type_t { TCP, UDP } socket_type_t; -typedef struct socket_connection_parameters_t { +typedef struct socket_connection_params_t { /** @brief Socket type (TCP or UDP). */ socket_type_t type; @@ -133,7 +133,7 @@ typedef struct socket_connection_parameters_t { /** @brief Hostname of the remote server. */ const char* server_hostname; -} socket_connection_parameters_t; +} socket_connection_params_t; /** * @brief Structure holding information about socket-based network abstraction. From 03fe8adc5f2d4615c8c691ebdf11da6b45f1b0f5 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Fri, 6 Feb 2026 12:36:59 -0700 Subject: [PATCH 047/105] Add SST_ctx_t as global variable, to not init_SST multiple times. SST_ctx is only needed per process. && Fix purpose to target group Federates, when called in lf_connect_to_federate. --- network/impl/src/lf_sst_support.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 2ec659d15..6716a84a5 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -1,5 +1,6 @@ #include // malloc() #include // strncpy() +#include #include "net_abstraction.h" #include "lf_sst_support.h" @@ -7,6 +8,8 @@ const char* sst_config_path; // The SST's configuration file path. +SST_ctx_t* ctx; + net_abstraction_t initialize_net() { // Initialize sst_priv. sst_priv_t* sst_priv = malloc(sizeof(sst_priv_t)); @@ -52,7 +55,9 @@ void free_net(net_abstraction_t net_abs) { int create_server(net_abstraction_t net_abs) { LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; - SST_ctx_t* ctx = init_SST(sst_config_path); + if (ctx == NULL) { + ctx = init_SST(sst_config_path); + } priv->sst_ctx = ctx; return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, &priv->socket_priv->port, TCP); @@ -91,7 +96,9 @@ void create_client(net_abstraction_t net_abs) { LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); - SST_ctx_t* ctx = init_SST(sst_config_path); + if (ctx == NULL) { + ctx = init_SST(sst_config_path); + } priv->sst_ctx = ctx; } @@ -99,9 +106,9 @@ net_abstraction_t connect_to_net(net_params_t* params) { // Create a network abstraction. net_abstraction_t net = initialize_net(); sst_priv_t* priv = (sst_priv_t*)net; - socket_connection_parameters_t* sock_params = (socket_connection_parameters_t*)params; - priv->socket_priv->server_port = sock_params->port; - memcpy(priv->socket_priv->server_hostname, sock_params->server_hostname, INET_ADDRSTRLEN); + sst_connection_params_t* sst_params = (sst_connection_params_t*)params; + priv->socket_priv->server_port = sst_params->socket_params.port; + memcpy(priv->socket_priv->server_hostname, sst_params->socket_params.server_hostname, INET_ADDRSTRLEN); // Create the client network abstraction. create_client(net); // Connect to the target server. @@ -109,6 +116,10 @@ net_abstraction_t connect_to_net(net_params_t* params) { lf_print_error("Failed to connect to socket."); return NULL; } + if (sst_params->target == 1) { + //Override target group to federates. + snprintf(priv->sst_ctx->config.purpose[ctx->config.purpose_index], sizeof(ctx->config.purpose[ctx->config.purpose_index]), "{\"group\":\"Federates\"}"); + } session_key_list_t* s_key_list = get_session_key(priv->sst_ctx, NULL); SST_session_ctx_t* session_ctx = secure_connect_to_server_with_socket(&s_key_list->s_key[0], priv->socket_priv->socket_descriptor); From 122e3b014a330527564136d23d582d54a7b5667c Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Tue, 10 Feb 2026 09:43:42 -0700 Subject: [PATCH 048/105] Minor fix. --- network/api/net_abstraction.h | 2 +- network/impl/src/lf_socket_support.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index 4149f7269..a23aab8fc 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -35,7 +35,7 @@ typedef void* net_abstraction_t; * * This type is an void pointer used to pass implementation-specific * connection parameters to the network abstraction layer. - * For example, it may point to a socket_connection_parameters_t structure + * For example, it may point to a socket_connection_params_t structure * when using a socket-based network implementation. */ typedef void* net_params_t; diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 189eb5998..4c97897c2 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -81,7 +81,7 @@ net_abstraction_t connect_to_net(net_params_t* params) { // Create a network abstraction. net_abstraction_t net = initialize_net(); socket_priv_t* priv = (socket_priv_t*)net; - socket_connection_parameters_t* sock_params = (socket_connection_parameters_t*)params; + socket_connection_params_t* sock_params = (socket_connection_params_t*)params; priv->server_port = sock_params->port; memcpy(priv->server_hostname, sock_params->server_hostname, INET_ADDRSTRLEN); // Create the client network abstraction. From 90fabf94e2d3afce026f117bbb381a8fbd814bc0 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Tue, 10 Feb 2026 13:01:28 -0700 Subject: [PATCH 049/105] Fix an error in the return value of `lf_check_deadline` --- lib/schedule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schedule.c b/lib/schedule.c index 9c37213de..fbab00393 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -84,8 +84,8 @@ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { if (lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline)) { if (invoke_deadline_handler && reaction->deadline_violation_handler != NULL) { reaction->deadline_violation_handler(self); - return true; } + return true; } return false; } From 88de99e9a1ec131683c12f29c222b7f6975427ed Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Tue, 10 Feb 2026 15:56:29 -0700 Subject: [PATCH 050/105] Match type with int and size_t. --- network/impl/src/lf_sst_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 6716a84a5..29516171e 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -135,7 +135,7 @@ int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* bu lf_print_error("Unable to handle message. Expected: %zu, Maximum: %d", num_bytes, MAX_SECURE_COMM_MSG_LENGTH); return -1; } - int copied = 0; + size_t copied = 0; // 1) First use buffered data. if (priv->buf_off < priv->buf_filled) { size_t avail = priv->buf_filled - priv->buf_off; From c8777a0fdd37bf52672739539da4151d54d142f4 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Tue, 10 Feb 2026 19:19:35 -0700 Subject: [PATCH 051/105] Do not check deadline for reacions with no deadline --- lib/schedule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/schedule.c b/lib/schedule.c index fbab00393..112542c80 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -81,8 +81,8 @@ trigger_handle_t lf_schedule_value(void* action, interval_t extra_delay, void* v */ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { reaction_t* reaction = ((self_base_t*)self)->executing_reaction; - if (lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline)) { - if (invoke_deadline_handler && reaction->deadline_violation_handler != NULL) { + if (lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline) && reaction->deadline_violation_handler != NULL) { + if (invoke_deadline_handler) { reaction->deadline_violation_handler(self); } return true; From e2ed06c46ba6b29f28b765b34f3996aabdc208e5 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Tue, 10 Feb 2026 19:21:57 -0700 Subject: [PATCH 052/105] Clang format --- lib/schedule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/schedule.c b/lib/schedule.c index 112542c80..0df7a41cf 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -81,7 +81,8 @@ trigger_handle_t lf_schedule_value(void* action, interval_t extra_delay, void* v */ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { reaction_t* reaction = ((self_base_t*)self)->executing_reaction; - if (lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline) && reaction->deadline_violation_handler != NULL) { + if (lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline) && + reaction->deadline_violation_handler != NULL) { if (invoke_deadline_handler) { reaction->deadline_violation_handler(self); } From dfdd581c8e300e11b7dedf80f8e4377df2f4f13a Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Wed, 11 Feb 2026 15:15:12 -0700 Subject: [PATCH 053/105] Add get/set socket related functions to support different net_abs_t types. --- core/federated/RTI/rti_remote.c | 13 +++-- core/federated/federate.c | 4 +- network/api/net_abstraction.h | 84 ++++++++++++++++++++++++++++ network/impl/src/lf_socket_support.c | 43 ++++++++++++++ network/impl/src/lf_sst_support.c | 42 ++++++++++++++ 5 files changed, 178 insertions(+), 8 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 3ba6727f4..622e2fd5f 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -650,9 +650,9 @@ void handle_address_query(uint16_t fed_id) { // The network abstraction is initialized, but the RTI might still not know the port number. This can happen if the // RTI has not yet received a MSG_TYPE_ADDRESS_ADVERTISEMENT message from the remote federate. In such cases, the // returned port number might still be -1. - server_port = (((sst_priv_t*)remote_fed->net)->socket_priv)->server_port; - ip_address = (uint32_t*)&(((sst_priv_t*)remote_fed->net)->socket_priv)->server_ip_addr; - server_host_name = (((sst_priv_t*)remote_fed->net)->socket_priv)->server_hostname; + server_port = get_server_port(remote_fed->net); + ip_address = (uint32_t*)get_ip_addr(remote_fed->net); + server_host_name = get_server_hostname(remote_fed->net); } encode_int32(server_port, (unsigned char*)&buffer[1]); @@ -683,7 +683,8 @@ void handle_address_ad(uint16_t federate_id) { assert(server_port < 65536); LF_MUTEX_LOCK(&rti_mutex); - (((sst_priv_t*)fed->net)->socket_priv)->server_port = server_port; + // (((sst_priv_t*)fed->net)->socket_priv)->server_port = server_port; + set_server_port(fed->net, server_port); LF_MUTEX_UNLOCK(&rti_mutex); LF_PRINT_LOG("Received address advertisement with port %d from federate %d.", server_port, federate_id); @@ -1317,7 +1318,7 @@ static int receive_udp_message_and_set_up_clock_sync(net_abstraction_t fed_net, // Initialize the UDP_addr field of the federate struct fed->UDP_addr.sin_family = AF_INET; fed->UDP_addr.sin_port = htons(federate_UDP_port_number); - fed->UDP_addr.sin_addr = ((socket_priv_t*)fed_net)->server_ip_addr; + fed->UDP_addr.sin_addr = *get_ip_addr(fed_net); } } else { // Disable clock sync after initial round. @@ -1503,7 +1504,7 @@ int start_rti_server() { // Initialize RTI's network abstraction. rti_remote->rti_net = initialize_net(); // Set the user specified port to the network abstraction. - (((sst_priv_t*)rti_remote->rti_net)->socket_priv)->user_specified_port = rti_remote->user_specified_port; + set_my_port(rti_remote->rti_net, rti_remote->user_specified_port); // Create the server if (create_server(rti_remote->rti_net)) { lf_print_error_system_failure("RTI failed to create TCP server: %s.", strerror(errno)); diff --git a/core/federated/federate.c b/core/federated/federate.c index 62aa7c6d7..2f1daab6e 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1934,13 +1934,13 @@ void lf_create_server(int specified_port) { assert(specified_port <= UINT16_MAX && specified_port >= 0); net_abstraction_t* server_net = initialize_net(); - ((sst_priv_t*)server_net)->socket_priv->port = (uint16_t)specified_port; + set_my_port(server_net, specified_port); if (create_server(server_net)) { lf_print_error_system_failure("Failed to create server: %s.", strerror(errno)); }; _fed.server_net = server_net; // Get the final server port to send to the RTI on an MSG_TYPE_ADDRESS_ADVERTISEMENT message. - int32_t server_port = ((sst_priv_t*)server_net)->socket_priv->port; + int32_t server_port = get_my_port(server_net); LF_PRINT_LOG("Server for communicating with other federates started using port %d.", server_port); diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index a23aab8fc..8f2e3e90a 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -222,4 +222,88 @@ bool is_net_open(net_abstraction_t net_abs); */ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing); +/** + * @brief Get the server port number of this network abstraction. + * @ingroup Network + * + * Get the open port number from the network abstraction. + * This is used when the federate sends a MSG_TYPE_ADDRESS_ADVERTISEMENT to the RTI, informing its port number. The RTI + * will save this port number, and send it to the other federate in a MSG_TYPE_ADDRESS_QUERY_REPLY message. + * + * @param net_abs The network abstraction. + * @return The port number of a server network abstraction. + */ +int32_t get_my_port(net_abstraction_t net_abs); + +/** + * @brief Get the connected peer's port number. + * @ingroup Network + * + * Get the port number of the connected peer. + * This is used by the RTI, when there is a request from the federate to the RTI, for the MSG_TYPE_ADDRESS_QUERY + * message. + * + * @param net_abs The network abstraction. + * @return Port number of the connected peer. + */ +int32_t get_server_port(net_abstraction_t net_abs); + +/** + * @brief Get the connected peer's IP address. + * @ingroup Network + * + * Get the IP address of the connected peer. + * + * @param net_abs The network abstraction. + * @return Pointer to the server IP address. + */ +struct in_addr* get_ip_addr(net_abstraction_t net_abs); + +/** + * @brief Get the connected peer's hostname. + * @ingroup Network + * + * Get the hostname of the connected peer. + * + * @param net_abs The network abstraction. + * @return Pointer to the server hostname. + */ +char* get_server_hostname(net_abstraction_t net_abs); + +/** + * @brief Set the user-specified port for this network abstraction. + * @ingroup Network + * + * Set the user specified port to the created network abstraction. + * + * @param net_abs The network abstraction. + * @param port The user specified port. + */ +void set_my_port(net_abstraction_t net_abs, int32_t port); + +/** + * @brief Set the target server's port number for this network abstraction. + * @ingroup Network + * + * Set server port number to the target network abstraction. + * The federate and RTI receives the port number from another + * federate MSG_TYPE_ADDRESS_ADVERTISEMENT message. + * This function is used to set the network abstraction's target server port number. + * + * @param net_abs The network abstraction. + * @param port The target server's port. + */ +void set_server_port(net_abstraction_t net_abs, int32_t port); + +/** + * @brief Set the target server's port number for this network abstraction. + * @ingroup Network + * + * Set the target server's hostname to the network abstraction. + * + * @param net_abs The network abstraction. + * @param hostname The target server's hostname. + */ +void set_server_hostname(net_abstraction_t net_abs, const char* hostname); + #endif /* NET_ABSTRACTION_H */ diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 4c97897c2..4165d9d58 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -184,3 +184,46 @@ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { free_net(net_abs); return ret; } + + +int32_t get_my_port(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + return priv->port; +} + +int32_t get_server_port(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + return priv->server_port; +} + +struct in_addr* get_ip_addr(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + return &priv->server_ip_addr; +} + +char* get_server_hostname(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + return priv->server_hostname; +} + +void set_my_port(net_abstraction_t net_abs, int32_t port) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + priv->user_specified_port = port; +} + +void set_server_port(net_abstraction_t net_abs, int32_t port) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + priv->server_port = port; +} + +void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { + LF_ASSERT_NON_NULL(net_abs); + socket_priv_t* priv = (socket_priv_t*)net_abs; + memcpy(priv->server_hostname, hostname, INET_ADDRSTRLEN); +} diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 29516171e..b726f2aed 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -57,6 +57,9 @@ int create_server(net_abstraction_t net_abs) { sst_priv_t* priv = (sst_priv_t*)net_abs; if (ctx == NULL) { ctx = init_SST(sst_config_path); + if (ctx == NULL) { + lf_print_error_and_exit("Failed to initialze SST settings."); + } } priv->sst_ctx = ctx; return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, @@ -98,6 +101,9 @@ void create_client(net_abstraction_t net_abs) { priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); if (ctx == NULL) { ctx = init_SST(sst_config_path); + if (ctx == NULL) { + lf_print_error_and_exit("Failed to initialze SST settings."); + } } priv->sst_ctx = ctx; } @@ -276,3 +282,39 @@ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } + +// Get/set functions. +int32_t get_my_port(net_abstraction_t net_abs) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + return priv->socket_priv->port; +} + +int32_t get_server_port(net_abstraction_t net_abs) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + return priv->socket_priv->server_port; +} + +struct in_addr* get_ip_addr(net_abstraction_t net_abs) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + return &priv->socket_priv->server_ip_addr; +} + +char* get_server_hostname(net_abstraction_t net_abs) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + return priv->socket_priv->server_hostname; +} + +void set_my_port(net_abstraction_t net_abs, int32_t port) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + priv->socket_priv->user_specified_port = port; +} + +void set_server_port(net_abstraction_t net_abs, int32_t port) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + priv->socket_priv->server_port = port; +} + +void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { + sst_priv_t* priv = (sst_priv_t*)net_abs; + memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); +} From 35e8ca1be1921fc80b5b0238581d31b9561c6dd8 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Wed, 11 Feb 2026 15:29:52 -0700 Subject: [PATCH 054/105] Minor cleanup. --- network/impl/src/lf_sst_support.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index b726f2aed..1c1da3b1e 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -66,7 +66,7 @@ int create_server(net_abstraction_t net_abs) { &priv->socket_priv->port, TCP); } -// TODO: check new implementation. + net_abstraction_t accept_net(net_abstraction_t server_chan) { LF_ASSERT_NON_NULL(server_chan); sst_priv_t* serv_priv = (sst_priv_t*)server_chan; @@ -226,7 +226,6 @@ int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buf LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; return send_secure_message((char *)buffer, (unsigned int) num_bytes, priv->session_ctx); - // return write_to_socket(priv->socket_priv->socket_descriptor, num_bytes, buffer); } int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { @@ -278,7 +277,7 @@ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { free_net(net_abs); return ret; } -// END of TODO: + // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } From c9211d25bfdbbb603cb01f1c9de5c853bbc6f941 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 14:44:46 -0700 Subject: [PATCH 055/105] Add tls support including, and setting certificate and private key path. --- core/federated/RTI/main.c | 26 ++ core/reactor_common.c | 28 +++ network/api/lf_tls_support.h | 38 +++ network/api/net_abstraction.h | 5 +- network/impl/src/lf_tls_support.c | 382 ++++++++++++++++++++++++++++++ 5 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 network/api/lf_tls_support.h create mode 100644 network/impl/src/lf_tls_support.c diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index ea47a866f..a45dbb6eb 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -261,6 +261,32 @@ int process_args(int argc, const char* argv[]) { #else i++; lf_set_sst_config_path(argv[i]); + } else if (strcmp(argv[i], "-tls") == 0 || strcmp(argv[i], "--tls") == 0) { +#ifndef COMM_TYPE_TLS + lf_print_error("--tls requires the RTI to be built with the -DCOMM_TYPE=TLS option."); + usage(argc, argv); + return 0; +#else + // Need two arguments: cert path and key path + if (argc < i + 3) { + lf_print_error("--tls needs two arguments: ."); + usage(argc, argv); + return 0; + } + const char* cert_path = argv[i + 1]; + const char* key_path = argv[i + 2]; + + // Optional: basic sanity check (avoid empty strings) + if (cert_path[0] == '\0' || key_path[0] == '\0') { + lf_print_error("--tls certificate_path and private_key_path must be non-empty."); + usage(argc, argv); + return 0; + } + + lf_set_tls_configuration(cert_path, key_path); + lf_print_debug("RTI: TLS cert path: %s", cert_path); + lf_print_debug("RTI: TLS key path : %s", key_path); + i += 2; #endif } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--tracing") == 0) { rti.base.tracing_enabled = true; diff --git a/core/reactor_common.c b/core/reactor_common.c index 9a2f90ff2..c00e5989b 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -976,6 +976,11 @@ void usage(int argc, const char* argv[]) { printf(" Send stdout to individual log files for each federate.\n\n"); #ifdef COMM_TYPE_SST printf(" -sst, --sst \n"); + printf(" Path to the SST configuration file.\n\n"); +#endif +#ifdef COMM_TYPE_TLS + printf(" -tls, --tls \n"); + printf(" Paths to the TLS certificate and private key to use.\n\n"); #endif #endif @@ -1137,6 +1142,29 @@ int process_args(int argc, const char* argv[]) { const char* fid = argv[i++]; lf_set_sst_config_path(fid); } +#endif +#ifdef COMM_TYPE_TLS + else if (strcmp(arg, "-tls") == 0 || strcmp(arg, "--tls") == 0) { + // Need two arguments: cert path and key path + if (argc < i + 2) { + lf_print_error("--tls needs two arguments: ."); + usage(argc, argv); + return 0; + } + + const char* cert_path = argv[i++]; + const char* key_path = argv[i++]; + + if (cert_path[0] == '\0' || key_path[0] == '\0') { + lf_print_error("--tls certificate_path and private_key_path must be non-empty."); + usage(argc, argv); + return 0; + } + + lf_set_tls_configuration(cert_path, key_path); + lf_print("TLS cert path: %s", cert_path); + lf_print("TLS key path : %s", key_path); + } #endif else if (strcmp(arg, "--ros-args") == 0) { // FIXME: Ignore ROS arguments for now diff --git a/network/api/lf_tls_support.h b/network/api/lf_tls_support.h new file mode 100644 index 000000000..7666bf3cd --- /dev/null +++ b/network/api/lf_tls_support.h @@ -0,0 +1,38 @@ +#ifndef LF_TLS_SUPPORT_H +#define LF_TLS_SUPPORT_H + +#include "socket_common.h" +#include +#include + +/** + * @brief Structure holding information about TLS-based network abstraction. + * @ingroup Network + */ +typedef struct tls_priv_t { + socket_priv_t* socket_priv; + SSL_CTX* ctx; + SSL* ssl; +} tls_priv_t; + +/** + * @brief Structure for TLS connection parameters. + * @ingroup Network + */ +typedef struct tls_connection_params_t { + /** @brief Common socket parameters. */ + socket_connection_params_t socket_params; + + // 0 for RTI, 1 for federates. + int target; +} tls_connection_params_t; + +/** + * @brief Set the path to the certificate and private key for TLS configuration. + * + * @param cert_path Path to the certificate file. + * @param key_path Path to the private key file. + */ +void lf_set_tls_configuration(const char* cert_path, const char* key_path); + +#endif /* LF_TLS_SUPPORT_H */ diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index 8f2e3e90a..c28f9b3d0 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -16,9 +16,12 @@ #define NET_ABSTRACTION_H #include "socket_common.h" -#if defined(COMM_TYPE_SST) +#ifdef(COMM_TYPE_SST) #include "lf_sst_support.h" #endif +#ifdef COMM_TYPE_TLS +#include "lf_tls_support.h" +#endif /** * @brief Pointer to whatever data structure is used to maintain the state of a network connection or service. diff --git a/network/impl/src/lf_tls_support.c b/network/impl/src/lf_tls_support.c new file mode 100644 index 000000000..f00dc3741 --- /dev/null +++ b/network/impl/src/lf_tls_support.c @@ -0,0 +1,382 @@ +#include +#include +#include +#include +#include + +#include "net_abstraction.h" +#include "lf_tls_support.h" +#include "util.h" +#include "logging.h" + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +#error "OpenSSL 3.0 or higher is required." +#endif + +// Global configuration for TLS (cert and key paths) +static const char* tls_cert_path = NULL; +static const char* tls_key_path = NULL; + +// Global SSL context for the server side (listening) or client side (connecting) +// In a simple model, we might share one context or recreate per connection. +// For efficiency, a global context is better if configuration is static. +static SSL_CTX* global_ctx = NULL; + +void lf_set_tls_configuration(const char* cert_path, const char* key_path) { + tls_cert_path = cert_path; + tls_key_path = key_path; +} + +// Helper to initialize OpenSSL context +static SSL_CTX* create_ssl_context(const SSL_METHOD* method) { + SSL_CTX* ctx = SSL_CTX_new(method); + if (!ctx) { + lf_print_error("Unable to create SSL context"); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + return ctx; +} + +static void configure_ssl_context(SSL_CTX* ctx) { + if (tls_cert_path && tls_key_path) { + if (SSL_CTX_use_certificate_file(ctx, tls_cert_path, SSL_FILETYPE_PEM) <= 0) { + lf_print_error("Failed to load certificate file: %s", tls_cert_path); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + if (SSL_CTX_use_PrivateKey_file(ctx, tls_key_path, SSL_FILETYPE_PEM) <= 0) { + lf_print_error("Failed to load private key file: %s", tls_key_path); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + } +} + +net_abstraction_t initialize_net() { + tls_priv_t* priv = (tls_priv_t*)malloc(sizeof(tls_priv_t)); + if (priv == NULL) { + lf_print_error_and_exit("Failed to allocate memory for tls_priv_t."); + } + + // Initialize socket_priv + priv->socket_priv = (socket_priv_t*)malloc(sizeof(socket_priv_t)); + if (priv->socket_priv == NULL) { + free(priv); + lf_print_error_and_exit("Failed to allocate memory for socket_priv_t."); + } + + // Default initialization for socket_priv + priv->socket_priv->port = 0; + priv->socket_priv->user_specified_port = 0; + priv->socket_priv->socket_descriptor = -1; + strncpy(priv->socket_priv->server_hostname, "localhost", INET_ADDRSTRLEN); + priv->socket_priv->server_ip_addr.s_addr = 0; + priv->socket_priv->server_port = -1; + + priv->ctx = NULL; + priv->ssl = NULL; + + return (net_abstraction_t)priv; +} + +void free_net(net_abstraction_t net_abs) { + if (net_abs == NULL) + return; + tls_priv_t* priv = (tls_priv_t*)net_abs; + + if (priv->ssl) { + SSL_free(priv->ssl); + } + // Note: We generally don't free the global context here if it's shared, + // but if it's per-connection, we should. + // Assuming global context is managed separately or lives until exit. + + if (priv->socket_priv) { + free(priv->socket_priv); + } + free(priv); +} + +int create_server(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + + // Initialize Global Context if not already done + if (global_ctx == NULL) { + global_ctx = create_ssl_context(TLS_server_method()); + configure_ssl_context(global_ctx); + } + priv->ctx = global_ctx; + + // Create the underlying socket server + return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, + &priv->socket_priv->port, TCP); +} + +net_abstraction_t accept_net(net_abstraction_t server_chan) { + LF_ASSERT_NON_NULL(server_chan); + tls_priv_t* server_priv = (tls_priv_t*)server_chan; + + // Accept TCP connection + int client_sock = accept_socket(server_priv->socket_priv->socket_descriptor); + if (client_sock < 0) { + return NULL; + } + + // Initialize new network abstraction for the client + net_abstraction_t client_net = initialize_net(); + tls_priv_t* client_priv = (tls_priv_t*)client_net; + client_priv->socket_priv->socket_descriptor = client_sock; + + // Share the context (or create new if needed, but sharing is standard for server) + client_priv->ctx = server_priv->ctx; + + // Create SSL structure + client_priv->ssl = SSL_new(client_priv->ctx); + SSL_set_fd(client_priv->ssl, client_sock); + + // Perform TLS handshake (accept) + if (SSL_accept(client_priv->ssl) <= 0) { + lf_print_error("SSL_accept failed."); + ERR_print_errors_fp(stderr); + SSL_free(client_priv->ssl); + client_priv->ssl = NULL; + // Close socket and free memory + // close(client_sock); // socket_priv destructor relies on this being closed? + // We should cleanup properly. + // For now, let's assume free_net handles it if we call shutdown_net later, + // but here we just return NULL, so we leak if we don't cleanup. + // Let's rely on caller or do minimal cleanup. + close(client_sock); + free(client_priv->socket_priv); + free(client_priv); + return NULL; + } + + // Create generic socket info (peer address) + if (get_peer_address(client_priv->socket_priv) != 0) { + lf_print_error("Failed to save peer address."); + } + + return client_net; +} + +void create_client(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + + // Create the underlying TCP socket + priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); + + if (global_ctx == NULL) { + global_ctx = create_ssl_context(TLS_client_method()); + } + priv->ctx = global_ctx; +} + +net_abstraction_t connect_to_net(net_params_t* params) { + tls_connection_params_t* tls_params = (tls_connection_params_t*)params; + + net_abstraction_t net = initialize_net(); + tls_priv_t* priv = (tls_priv_t*)net; + + // Set socket params + priv->socket_priv->server_port = tls_params->socket_params.port; + memcpy(priv->socket_priv->server_hostname, tls_params->socket_params.server_hostname, INET_ADDRSTRLEN); + + create_client(net); + + // TCP Connect + if (connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, + priv->socket_priv->server_port) != 0) { + lf_print_error("Failed to connect to socket."); + free_net(net); + return NULL; + } + + // SSL Connect + priv->ssl = SSL_new(priv->ctx); + SSL_set_fd(priv->ssl, priv->socket_priv->socket_descriptor); + + if (SSL_connect(priv->ssl) <= 0) { + lf_print_error("SSL_connect failed."); + ERR_print_errors_fp(stderr); + shutdown_net(net, false); + return NULL; + } + + return net; +} + +int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + + size_t bytes_read = 0; + while (bytes_read < num_bytes) { + int ret = SSL_read(priv->ssl, buffer + bytes_read, num_bytes - bytes_read); + if (ret > 0) { + bytes_read += ret; + } else { + int err = SSL_get_error(priv->ssl, ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + // Retry logic for blocking behavior + lf_sleep(DELAY_BETWEEN_SOCKET_RETRIES); + continue; + } + if (err == SSL_ERROR_ZERO_RETURN) { + // Connection closed gracefully + return 1; // EOF + } + // Error + lf_print_error("SSL_read failed with error %d", err); + ERR_print_errors_fp(stderr); + return -1; + } + } + return 0; +} + +int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + tls_priv_t* priv = (tls_priv_t*)net_abs; + int ret = read_from_net(net_abs, num_bytes, buffer); + if (ret < 0) { + shutdown_net(net_abs, false); + return -1; + } + return ret; // 0 for success, 1 for EOF +} + +void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, char* format, + ...) { + va_list args; + int read_failed = read_from_net_close_on_error(net_abs, num_bytes, buffer); + if (read_failed) { + // Read failed. + if (format != NULL) { + va_start(args, format); + lf_print_error_system_failure(format, args); + va_end(args); + } else { + lf_print_error_system_failure("Failed to read from socket."); + } + } +} + +int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + + size_t bytes_written = 0; + while (bytes_written < num_bytes) { + int ret = SSL_write(priv->ssl, buffer + bytes_written, num_bytes - bytes_written); + if (ret > 0) { + bytes_written += ret; + } else { + int err = SSL_get_error(priv->ssl, ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + continue; + } + lf_print_error("SSL_write failed with error %d", err); + ERR_print_errors_fp(stderr); + return -1; + } + } + return 0; +} + +int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { + int ret = write_to_net(net_abs, num_bytes, buffer); + if (ret < 0) { + shutdown_net(net_abs, false); + return -1; + } + return 0; +} + +void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer, lf_mutex_t* mutex, + char* format, ...) { + va_list args; + int ret = write_to_net_close_on_error(net_abs, num_bytes, buffer); + if (ret < 0) { + if (mutex) + LF_MUTEX_UNLOCK(mutex); + + if (format != NULL) { + va_start(args, format); + lf_print_error_system_failure(format, args); + va_end(args); + } else { + lf_print_error_system_failure("Failed to write to TLS connection."); + } + } +} + +bool is_net_open(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + return is_socket_open(priv->socket_priv->socket_descriptor); +} + +int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { + if (net_abs == NULL) + return 0; + tls_priv_t* priv = (tls_priv_t*)net_abs; + + if (priv->ssl) { + SSL_shutdown(priv->ssl); + // We might want to read pending data here if read_before_closing is true, + // but SSL_shutdown usually sends notify_close. + } + + // Shutdown underlying socket + if (priv->socket_priv) { + shutdown_socket(&priv->socket_priv->socket_descriptor, read_before_closing); + } + + free_net(net_abs); + return 0; +} + +int32_t get_my_port(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + return priv->socket_priv->port; +} + +int32_t get_server_port(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + return priv->socket_priv->server_port; +} + +struct in_addr* get_ip_addr(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + return &priv->socket_priv->server_ip_addr; +} + +char* get_server_hostname(net_abstraction_t net_abs) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + return priv->socket_priv->server_hostname; +} + +void set_my_port(net_abstraction_t net_abs, int32_t port) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + priv->socket_priv->user_specified_port = port; +} + +void set_server_port(net_abstraction_t net_abs, int32_t port) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + priv->socket_priv->server_port = port; +} + +void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { + LF_ASSERT_NON_NULL(net_abs); + tls_priv_t* priv = (tls_priv_t*)net_abs; + memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); +} From ba0f7cd8fa4ea15b3e53524e93f0bb5dbd8f983d Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 14:46:28 -0700 Subject: [PATCH 056/105] Minor fix. --- network/api/net_abstraction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index c28f9b3d0..14a02ea62 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -16,7 +16,7 @@ #define NET_ABSTRACTION_H #include "socket_common.h" -#ifdef(COMM_TYPE_SST) +#ifdef COMM_TYPE_SST #include "lf_sst_support.h" #endif #ifdef COMM_TYPE_TLS From 7ca576374349de7e23183f90d0220c8f4bdb3d38 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 14:54:11 -0700 Subject: [PATCH 057/105] Minor fix. --- core/federated/RTI/main.c | 1 + network/impl/src/lf_tls_support.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index a45dbb6eb..e7489b6d0 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -261,6 +261,7 @@ int process_args(int argc, const char* argv[]) { #else i++; lf_set_sst_config_path(argv[i]); +#endif } else if (strcmp(argv[i], "-tls") == 0 || strcmp(argv[i], "--tls") == 0) { #ifndef COMM_TYPE_TLS lf_print_error("--tls requires the RTI to be built with the -DCOMM_TYPE=TLS option."); diff --git a/network/impl/src/lf_tls_support.c b/network/impl/src/lf_tls_support.c index f00dc3741..668025a21 100644 --- a/network/impl/src/lf_tls_support.c +++ b/network/impl/src/lf_tls_support.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -239,7 +240,6 @@ int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* bu } int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { - tls_priv_t* priv = (tls_priv_t*)net_abs; int ret = read_from_net(net_abs, num_bytes, buffer); if (ret < 0) { shutdown_net(net_abs, false); From 9bf85ea92155e012642aa30d511746b94ad38036 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 14:54:33 -0700 Subject: [PATCH 058/105] Fix cmake to enable TLS comm type. --- network/impl/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/network/impl/CMakeLists.txt b/network/impl/CMakeLists.txt index 116f7db1e..c6afcf943 100644 --- a/network/impl/CMakeLists.txt +++ b/network/impl/CMakeLists.txt @@ -15,6 +15,15 @@ elseif(COMM_TYPE MATCHES SST) find_package(sst-lib REQUIRED) target_sources(lf-network-impl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lf_sst_support.c) target_link_libraries(lf-network-impl PUBLIC sst-lib::sst-c-api) +elseif(COMM_TYPE MATCHES TLS) + find_package(OpenSSL REQUIRED) + target_sources(lf-network-impl PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/src/lf_tls_support.c + ) + target_link_libraries(lf-network-impl PUBLIC + OpenSSL::SSL + OpenSSL::Crypto + ) else() message(FATAL_ERROR "Your communication type is not supported! The C target supports TCP.") endif() From 1ebeb252d3504db7b75959b5d3b38b10566221c4 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 15:16:13 -0700 Subject: [PATCH 059/105] Minor fix on adding -tls options. --- core/federated/RTI/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index e7489b6d0..93205eab2 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -116,6 +116,7 @@ void usage(int argc, const char* argv[]) { lf_print(" -t, --tracing Turn on tracing.\n"); lf_print(" -d, --disable_dnet Turn off the use of DNET signals.\n"); lf_print(" -sst, --sst SST config path for RTI.\n"); + lf_print(" -tls, --tls TLS certificate and private key paths.\n"); lf_print("Command given:"); for (int i = 0; i < argc; i++) { @@ -221,7 +222,7 @@ int process_args(int argc, const char* argv[]) { rti.base.number_of_scheduling_nodes = (int32_t)num_federates; // FIXME: Loses numbers on 64-bit machines lf_print("RTI: Number of federates: %d", rti.base.number_of_scheduling_nodes); } else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) { -#if defined(COMM_TYPE_TCP) || defined(COMM_TYPE_SST) +#if defined(COMM_TYPE_TCP) || defined(COMM_TYPE_SST) || defined(COMM_TYPE_TLS) if (argc < i + 2) { lf_print_error("--port needs a short unsigned integer argument ( > 0 and < %d).", UINT16_MAX); usage(argc, argv); From af0274f28314442e1e09f9f9c4d59a27d7f4cde3 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 15:16:27 -0700 Subject: [PATCH 060/105] Add ifdefs for connection_parameters_t --- core/federated/federate.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 2f1daab6e..accb11d4a 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1736,12 +1736,23 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { char hostname[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &host_ip_addr, hostname, INET_ADDRSTRLEN); +#ifdef COMM_TYPE_TCP + socket_connection_parameters_t params; + params.type = TCP; + params.port = uport; + params.server_hostname = hostname; +#elif defined(COMM_TYPE_SST) sst_connection_params_t params; - params.socket_params.type = TCP; params.socket_params.port = uport; params.socket_params.server_hostname = hostname; params.target = 1; +#elif defined(COMM_TYPE_TLS) + tls_connection_params_t params; + params.socket_params.type = TCP; + params.socket_params.port = uport; + params.socket_params.server_hostname = hostname; +#endif net_abstraction_t net = connect_to_net((net_params_t*)¶ms); if (net == NULL) { From 0a85506c0f833796ea00b3963c4461d7669f33cb Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 16:26:14 -0700 Subject: [PATCH 061/105] Minor fix. --- core/federated/federate.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index accb11d4a..e21fd4c43 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1737,7 +1737,7 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { inet_ntop(AF_INET, &host_ip_addr, hostname, INET_ADDRSTRLEN); #ifdef COMM_TYPE_TCP - socket_connection_parameters_t params; + socket_connection_params_t params; params.type = TCP; params.port = uport; params.server_hostname = hostname; @@ -1831,12 +1831,24 @@ void lf_connect_to_rti(const char* hostname, int port) { hostname = federation_metadata.rti_host ? federation_metadata.rti_host : hostname; port = federation_metadata.rti_port >= 0 ? federation_metadata.rti_port : port; +#ifdef COMM_TYPE_TCP + socket_connection_params_t params; + params.type = TCP; + params.port = port; + params.server_hostname = hostname; +#elif defined(COMM_TYPE_SST) sst_connection_params_t params; - params.socket_params.type = TCP; params.socket_params.port = port; params.socket_params.server_hostname = hostname; - params.target = 0; + params.target = 1; +#elif defined(COMM_TYPE_TLS) + tls_connection_params_t params; + params.socket_params.type = TCP; + params.socket_params.port = port; + params.socket_params.server_hostname = hostname; +#endif + net_abstraction_t net = connect_to_net((net_params_t*)¶ms); if (net == NULL) { lf_print_error_and_exit("Failed to connect to RTI."); From 8bea08e62058e3990189a9c3b6efbed7876ed210 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 16:26:22 -0700 Subject: [PATCH 062/105] Minor fix. --- network/api/lf_tls_support.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/network/api/lf_tls_support.h b/network/api/lf_tls_support.h index 7666bf3cd..6c38407cd 100644 --- a/network/api/lf_tls_support.h +++ b/network/api/lf_tls_support.h @@ -22,9 +22,6 @@ typedef struct tls_priv_t { typedef struct tls_connection_params_t { /** @brief Common socket parameters. */ socket_connection_params_t socket_params; - - // 0 for RTI, 1 for federates. - int target; } tls_connection_params_t; /** From 05f978cae0a15cc36e8fd5305f5963a491e25be9 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 17:09:31 -0700 Subject: [PATCH 063/105] Minor bug fix.. Fixing invalid key request... --- core/federated/federate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index e21fd4c43..1b5458378 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1841,7 +1841,7 @@ void lf_connect_to_rti(const char* hostname, int port) { params.socket_params.type = TCP; params.socket_params.port = port; params.socket_params.server_hostname = hostname; - params.target = 1; + params.target = 0; #elif defined(COMM_TYPE_TLS) tls_connection_params_t params; params.socket_params.type = TCP; From f5d04815934e13355457a19c90ea4045c970ba62 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 20:35:00 -0700 Subject: [PATCH 064/105] Fixed accept error in TLS. Created two separate SSL_CTX for client and server each. --- network/impl/src/lf_tls_support.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/network/impl/src/lf_tls_support.c b/network/impl/src/lf_tls_support.c index 668025a21..23c754ee1 100644 --- a/network/impl/src/lf_tls_support.c +++ b/network/impl/src/lf_tls_support.c @@ -18,10 +18,8 @@ static const char* tls_cert_path = NULL; static const char* tls_key_path = NULL; -// Global SSL context for the server side (listening) or client side (connecting) -// In a simple model, we might share one context or recreate per connection. -// For efficiency, a global context is better if configuration is static. -static SSL_CTX* global_ctx = NULL; +static SSL_CTX* global_client_ctx = NULL; +static SSL_CTX* global_server_ctx = NULL; void lf_set_tls_configuration(const char* cert_path, const char* key_path) { tls_cert_path = cert_path; @@ -104,11 +102,11 @@ int create_server(net_abstraction_t net_abs) { tls_priv_t* priv = (tls_priv_t*)net_abs; // Initialize Global Context if not already done - if (global_ctx == NULL) { - global_ctx = create_ssl_context(TLS_server_method()); - configure_ssl_context(global_ctx); + if (global_server_ctx == NULL) { + global_server_ctx = create_ssl_context(TLS_server_method()); + configure_ssl_context(global_server_ctx); } - priv->ctx = global_ctx; + priv->ctx = global_server_ctx; // Create the underlying socket server return create_socket_server(priv->socket_priv->user_specified_port, &priv->socket_priv->socket_descriptor, @@ -137,6 +135,7 @@ net_abstraction_t accept_net(net_abstraction_t server_chan) { client_priv->ssl = SSL_new(client_priv->ctx); SSL_set_fd(client_priv->ssl, client_sock); + SSL_set_accept_state(client_priv->ssl); // Perform TLS handshake (accept) if (SSL_accept(client_priv->ssl) <= 0) { lf_print_error("SSL_accept failed."); @@ -170,10 +169,10 @@ void create_client(net_abstraction_t net_abs) { // Create the underlying TCP socket priv->socket_priv->socket_descriptor = create_real_time_tcp_socket_errexit(); - if (global_ctx == NULL) { - global_ctx = create_ssl_context(TLS_client_method()); + if (global_client_ctx == NULL) { + global_client_ctx = create_ssl_context(TLS_client_method()); } - priv->ctx = global_ctx; + priv->ctx = global_client_ctx; } net_abstraction_t connect_to_net(net_params_t* params) { From a4481669310b5f64a0aa68e926135aeb8e7ce027 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 12 Feb 2026 21:06:24 -0700 Subject: [PATCH 065/105] Fix memory free problems, and set EOF returns to 1 following Lingua Franca EOF handling logic. --- network/impl/src/lf_tls_support.c | 70 ++++++++++++++++++------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/network/impl/src/lf_tls_support.c b/network/impl/src/lf_tls_support.c index 23c754ee1..8bab4b4c2 100644 --- a/network/impl/src/lf_tls_support.c +++ b/network/impl/src/lf_tls_support.c @@ -140,17 +140,8 @@ net_abstraction_t accept_net(net_abstraction_t server_chan) { if (SSL_accept(client_priv->ssl) <= 0) { lf_print_error("SSL_accept failed."); ERR_print_errors_fp(stderr); - SSL_free(client_priv->ssl); - client_priv->ssl = NULL; - // Close socket and free memory - // close(client_sock); // socket_priv destructor relies on this being closed? - // We should cleanup properly. - // For now, let's assume free_net handles it if we call shutdown_net later, - // but here we just return NULL, so we leak if we don't cleanup. - // Let's rely on caller or do minimal cleanup. - close(client_sock); - free(client_priv->socket_priv); - free(client_priv); + + shutdown_net(client_net, false); return NULL; } @@ -209,6 +200,22 @@ net_abstraction_t connect_to_net(net_params_t* params) { return net; } +static int is_disconnect_syscall(int err, int ret) { + if (err != SSL_ERROR_SYSCALL) return 0; + + if (ret == 0) { + // Often: "unexpected EOF while reading" / peer closed without close_notify + return 1; + } + if (ret == -1) { + // RST/timeout/pipe, treat as disconnect if you want EOF semantics + if (errno == ECONNRESET || errno == EPIPE || errno == ETIMEDOUT || errno == ENOTCONN) { + return 1; + } + } + return 0; +} + int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { LF_ASSERT_NON_NULL(net_abs); tls_priv_t* priv = (tls_priv_t*)net_abs; @@ -217,27 +224,34 @@ int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* bu while (bytes_read < num_bytes) { int ret = SSL_read(priv->ssl, buffer + bytes_read, num_bytes - bytes_read); if (ret > 0) { - bytes_read += ret; - } else { - int err = SSL_get_error(priv->ssl, ret); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { - // Retry logic for blocking behavior - lf_sleep(DELAY_BETWEEN_SOCKET_RETRIES); - continue; - } - if (err == SSL_ERROR_ZERO_RETURN) { - // Connection closed gracefully - return 1; // EOF - } - // Error - lf_print_error("SSL_read failed with error %d", err); - ERR_print_errors_fp(stderr); - return -1; + bytes_read += (size_t)ret; + continue; + } + + int err = SSL_get_error(priv->ssl, ret); + + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { + lf_sleep(DELAY_BETWEEN_SOCKET_RETRIES); + continue; + } + + if (err == SSL_ERROR_ZERO_RETURN) { + // close_notify received + return 1; // EOF } + + if (is_disconnect_syscall(err, ret)) { + // peer disconnected without close_notify (or reset) + return 1; // treat as EOF + } + + // Real TLS/protocol error + lf_print_error("SSL_read failed (ret=%d, err=%d, errno=%d)", ret, err, errno); + ERR_print_errors_fp(stderr); + return -1; } return 0; } - int read_from_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { int ret = read_from_net(net_abs, num_bytes, buffer); if (ret < 0) { From 3f9182b0a371086a15b4061f140ef703ecce079b Mon Sep 17 00:00:00 2001 From: Byeonggil Jun <78055940+byeonggiljun@users.noreply.github.com> Date: Fri, 27 Mar 2026 15:25:12 -0700 Subject: [PATCH 066/105] Apply suggestions from code review Co-authored-by: Edward A. Lee --- python/include/pythontarget.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/include/pythontarget.h b/python/include/pythontarget.h index 47ae981c7..dd1da1ce5 100644 --- a/python/include/pythontarget.h +++ b/python/include/pythontarget.h @@ -108,14 +108,14 @@ PyObject* py_check_deadline(PyObject* self, PyObject* args); * Updating the deadline with this function does not affect * the deadline check that has been performed (at the beginning * of the caller reaction or check_deadline called before). - * Therefore, you need to invoke check_deadline after - * update the deadline through this function to confirm + * Therefore, you may want to invoke check_deadline after + * updating the deadline through this function to confirm * whether the newly updated deadline has been violated. * * @param self The Python object of the reactor. * @param args contains: * - updated_deadline: The updated deadline. - * @return Py_None + * @return Py_None or NULL if an error occurs. */ PyObject* py_update_deadline(PyObject* self, PyObject* args); From d3142bd3ccded91764474ea72eb50a04191df3c7 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 6 Apr 2026 15:46:46 -0700 Subject: [PATCH 067/105] Update lingua-franca-ref.txt --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index b756b406f..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -networkdriver +master From 9e4e4cba91f0fcc2efc400050b990c3c4dbb73f9 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Tue, 7 Apr 2026 16:33:12 -0700 Subject: [PATCH 068/105] Formatting. --- core/federated/RTI/main.c | 2 +- core/reactor_common.c | 2 +- network/api/lf_sst_support.h | 2 +- network/api/lf_tls_support.h | 2 +- network/impl/src/lf_socket_support.c | 1 - network/impl/src/lf_sst_support.c | 94 ++++++++++++++-------------- network/impl/src/lf_tls_support.c | 3 +- 7 files changed, 53 insertions(+), 53 deletions(-) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index 6913b988e..0a184a1eb 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -276,7 +276,7 @@ int process_args(int argc, const char* argv[]) { return 0; } const char* cert_path = argv[i + 1]; - const char* key_path = argv[i + 2]; + const char* key_path = argv[i + 2]; // Optional: basic sanity check (avoid empty strings) if (cert_path[0] == '\0' || key_path[0] == '\0') { diff --git a/core/reactor_common.c b/core/reactor_common.c index 68b5cc0d9..89f66718d 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1241,7 +1241,7 @@ int process_args(int argc, const char* argv[]) { } const char* cert_path = argv[i++]; - const char* key_path = argv[i++]; + const char* key_path = argv[i++]; if (cert_path[0] == '\0' || key_path[0] == '\0') { lf_print_error("--tls certificate_path and private_key_path must be non-empty."); diff --git a/network/api/lf_sst_support.h b/network/api/lf_sst_support.h index f4ed2709f..3dffa3b93 100644 --- a/network/api/lf_sst_support.h +++ b/network/api/lf_sst_support.h @@ -10,7 +10,7 @@ typedef struct sst_priv_t { SST_session_ctx_t* session_ctx; unsigned char buffer[MAX_SECURE_COMM_MSG_LENGTH]; size_t buf_filled; - size_t buf_off; + size_t buf_off; } sst_priv_t; typedef struct sst_connection_params_t { diff --git a/network/api/lf_tls_support.h b/network/api/lf_tls_support.h index 6c38407cd..c107fdedb 100644 --- a/network/api/lf_tls_support.h +++ b/network/api/lf_tls_support.h @@ -18,7 +18,7 @@ typedef struct tls_priv_t { /** * @brief Structure for TLS connection parameters. * @ingroup Network - */ + */ typedef struct tls_connection_params_t { /** @brief Common socket parameters. */ socket_connection_params_t socket_params; diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 656ecbeb1..36c69b8c6 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -187,7 +187,6 @@ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { return ret; } - int32_t get_my_port(net_abstraction_t net_abs) { LF_ASSERT_NON_NULL(net_abs); socket_priv_t* priv = (socket_priv_t*)net_abs; diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 1c1da3b1e..0c70d8f2e 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -66,7 +66,6 @@ int create_server(net_abstraction_t net_abs) { &priv->socket_priv->port, TCP); } - net_abstraction_t accept_net(net_abstraction_t server_chan) { LF_ASSERT_NON_NULL(server_chan); sst_priv_t* serv_priv = (sst_priv_t*)server_chan; @@ -118,13 +117,15 @@ net_abstraction_t connect_to_net(net_params_t* params) { // Create the client network abstraction. create_client(net); // Connect to the target server. - if (connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, priv->socket_priv->server_port) != 0) { + if (connect_to_socket(priv->socket_priv->socket_descriptor, priv->socket_priv->server_hostname, + priv->socket_priv->server_port) != 0) { lf_print_error("Failed to connect to socket."); return NULL; } if (sst_params->target == 1) { - //Override target group to federates. - snprintf(priv->sst_ctx->config.purpose[ctx->config.purpose_index], sizeof(ctx->config.purpose[ctx->config.purpose_index]), "{\"group\":\"Federates\"}"); + // Override target group to federates. + snprintf(priv->sst_ctx->config.purpose[ctx->config.purpose_index], + sizeof(ctx->config.purpose[ctx->config.purpose_index]), "{\"group\":\"Federates\"}"); } session_key_list_t* s_key_list = get_session_key(priv->sst_ctx, NULL); SST_session_ctx_t* session_ctx = @@ -138,54 +139,54 @@ int read_from_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* bu sst_priv_t* priv = (sst_priv_t*)net_abs; if (num_bytes > MAX_SECURE_COMM_MSG_LENGTH) { - lf_print_error("Unable to handle message. Expected: %zu, Maximum: %d", num_bytes, MAX_SECURE_COMM_MSG_LENGTH); - return -1; + lf_print_error("Unable to handle message. Expected: %zu, Maximum: %d", num_bytes, MAX_SECURE_COMM_MSG_LENGTH); + return -1; } size_t copied = 0; // 1) First use buffered data. if (priv->buf_off < priv->buf_filled) { - size_t avail = priv->buf_filled - priv->buf_off; - size_t to_copy = (avail < num_bytes) ? avail : num_bytes; - memcpy(buffer, priv->buffer + priv->buf_off, to_copy); - priv->buf_off += to_copy; - copied += to_copy; - - // Reset buffer offset when the buffer is all used. - if (priv->buf_off == priv->buf_filled) { - priv->buf_off = priv->buf_filled = 0; - } - - // Return when the buffered data is enough. - if (copied == num_bytes) { - return 0; - } + size_t avail = priv->buf_filled - priv->buf_off; + size_t to_copy = (avail < num_bytes) ? avail : num_bytes; + memcpy(buffer, priv->buffer + priv->buf_off, to_copy); + priv->buf_off += to_copy; + copied += to_copy; + + // Reset buffer offset when the buffer is all used. + if (priv->buf_off == priv->buf_filled) { + priv->buf_off = priv->buf_filled = 0; } + // Return when the buffered data is enough. + if (copied == num_bytes) { + return 0; + } + } + // 2) Additionally try to read more bytes. while (copied < num_bytes) { - int ret = read_secure_message(priv->buffer, priv->session_ctx); - if (ret == 0) { - // EOF received. - return 1; - } else if (ret < 0) { - lf_print_error("read_secure_message failed: %d", ret); - return -1; - } - - // Mark the filled length and reset offset. - priv->buf_filled = (size_t)ret; - priv->buf_off = 0; - - size_t need = num_bytes - copied; - size_t to_copy = (priv->buf_filled < need) ? priv->buf_filled : need; - memcpy(buffer + copied, priv->buffer + priv->buf_off, to_copy); - priv->buf_off += to_copy; - copied += to_copy; - - // Reset buffer offset when meets the end of the filled buffer. - if (priv->buf_off == priv->buf_filled) { - priv->buf_off = priv->buf_filled = 0; - } + int ret = read_secure_message(priv->buffer, priv->session_ctx); + if (ret == 0) { + // EOF received. + return 1; + } else if (ret < 0) { + lf_print_error("read_secure_message failed: %d", ret); + return -1; + } + + // Mark the filled length and reset offset. + priv->buf_filled = (size_t)ret; + priv->buf_off = 0; + + size_t need = num_bytes - copied; + size_t to_copy = (priv->buf_filled < need) ? priv->buf_filled : need; + memcpy(buffer + copied, priv->buffer + priv->buf_off, to_copy); + priv->buf_off += to_copy; + copied += to_copy; + + // Reset buffer offset when meets the end of the filled buffer. + if (priv->buf_off == priv->buf_filled) { + priv->buf_off = priv->buf_filled = 0; + } } return 0; @@ -225,7 +226,7 @@ void read_from_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, un int write_to_net(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { LF_ASSERT_NON_NULL(net_abs); sst_priv_t* priv = (sst_priv_t*)net_abs; - return send_secure_message((char *)buffer, (unsigned int) num_bytes, priv->session_ctx); + return send_secure_message((char*)buffer, (unsigned int)num_bytes, priv->session_ctx); } int write_to_net_close_on_error(net_abstraction_t net_abs, size_t num_bytes, unsigned char* buffer) { @@ -278,7 +279,6 @@ int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { return ret; } - // Helper function. void lf_set_sst_config_path(const char* config_path) { sst_config_path = config_path; } @@ -311,7 +311,7 @@ void set_my_port(net_abstraction_t net_abs, int32_t port) { void set_server_port(net_abstraction_t net_abs, int32_t port) { sst_priv_t* priv = (sst_priv_t*)net_abs; priv->socket_priv->server_port = port; -} +} void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { sst_priv_t* priv = (sst_priv_t*)net_abs; diff --git a/network/impl/src/lf_tls_support.c b/network/impl/src/lf_tls_support.c index 8bab4b4c2..93f4481bc 100644 --- a/network/impl/src/lf_tls_support.c +++ b/network/impl/src/lf_tls_support.c @@ -201,7 +201,8 @@ net_abstraction_t connect_to_net(net_params_t* params) { } static int is_disconnect_syscall(int err, int ret) { - if (err != SSL_ERROR_SYSCALL) return 0; + if (err != SSL_ERROR_SYSCALL) + return 0; if (ret == 0) { // Often: "unexpected EOF while reading" / peer closed without close_notify From 3f8508610517974845023f388cf8ee1cec5e5556 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 10 Apr 2026 10:08:05 -0700 Subject: [PATCH 069/105] Typos in instructions --- util/deque.c | 2 +- util/deque.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/util/deque.c b/util/deque.c index 4dca52f20..584fa00a7 100644 --- a/util/deque.c +++ b/util/deque.c @@ -11,7 +11,7 @@ * To use this, include the following in your target properties: *
  * target C {
- *     cmake-include: "/lib/c/reactor-c/util/deque.cmake"
+ *     cmake-include: "/lib/c/reactor-c/util/deque.cmake",
  *     files: ["/lib/c/reactor-c/util/deque.c", "/lib/c/reactor-c/util/deque.h"]
  * };
  * 
diff --git a/util/deque.h b/util/deque.h index 658ee456d..5acee93b9 100644 --- a/util/deque.h +++ b/util/deque.h @@ -13,7 +13,7 @@ * * ``` * target C { - * cmake-include: "/lib/c/reactor-c/util/deque.cmake" + * cmake-include: "/lib/c/reactor-c/util/deque.cmake", * files: ["/lib/c/reactor-c/util/deque.c", "/lib/c/reactor-c/util/deque.h"] * }; * ``` From 1c8fccea69c73ff1100ac25cc603a1a7fee784cd Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 10 Apr 2026 10:08:36 -0700 Subject: [PATCH 070/105] First version of initilize from file utility --- util/initialize_from_file.c | 91 ++++++++++++++++++++++++++++++++ util/initialize_from_file.cmake | 1 + util/initialize_from_file.h | 92 +++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 util/initialize_from_file.c create mode 100644 util/initialize_from_file.cmake create mode 100644 util/initialize_from_file.h diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c new file mode 100644 index 000000000..0c2d4a103 --- /dev/null +++ b/util/initialize_from_file.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#include "logging/api/logging.h" +#include "initialize_from_file.h" + +/** Remove leading and trailing whitespace from the string. */ +static void sc_csv_trim(char* s) { + char* p = s; + while (*p && isspace((unsigned char)*p)) { + p++; + } + if (p != s) { + memmove(s, p, strlen(p) + 1); + } + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) { + s[--n] = '\0'; + } +} + +/** Replace the specified delimiter with a null character and return the number of fields. */ +static int sc_csv_split(char* line, char delimiter, char** fields, int max_fields) { + int n = 0; + char* cur = line; + while (n < max_fields) { + fields[n++] = cur; + char* sep = strchr(cur, delimiter); + if (!sep) { + break; + } + *sep = '\0'; + cur = sep + 1; + } + return n; +} + +int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...) { + va_list ap; + size_t pointer_count = 0; + FILE* f = fopen(filename, "r"); + if (!f) { + lf_print_error("Could not open file \"%s\".", filename); + return -1; + } + + char line[SC_CSV_LINE_MAX]; + size_t row_count = 0; + while (fgets(line, sizeof(line), f)) { + if (row_count == row_number) { + char* row = &line[0]; + // Remove the UTF-8 BOM (byte-order mark) if it exists. + if ((unsigned char)line[0] == 0xEF && (unsigned char)line[1] == 0xBB && (unsigned char)line[2] == 0xBF) { + row += 3; + } + // Terminate the last item in the line with a null character. + row[strcspn(row, "\r\n")] = '\0'; + + char* fields[SC_CSV_MAX_COLS]; + int field_count = sc_csv_split(row, delimiter, fields, SC_CSV_MAX_COLS); + va_start(ap, row_number); + for (size_t i = 0; i < (size_t)field_count; i++) { + double* out = va_arg(ap, double*); + if (out == NULL) { + break; + } + pointer_count++; + sc_csv_trim(fields[i]); + char* end = NULL; + double parsed = strtod(fields[i], &end); + if (end != fields[i] && *end == '\0') { + *out = parsed; + } else { + lf_print_error( + "Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", + fields[i], row_number, i, filename); + } + } + va_end(ap); + fclose(f); + return (int)pointer_count; + } + row_count++; + } + lf_print_error("Requested row %zu not found in file \"%s\".", row_number, filename); + fclose(f); + return -1; +} diff --git a/util/initialize_from_file.cmake b/util/initialize_from_file.cmake new file mode 100644 index 000000000..48f973069 --- /dev/null +++ b/util/initialize_from_file.cmake @@ -0,0 +1 @@ +target_sources(${LF_MAIN_TARGET} PRIVATE initialize_from_file.c) diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h new file mode 100644 index 000000000..c9c7b83a5 --- /dev/null +++ b/util/initialize_from_file.h @@ -0,0 +1,92 @@ +/** + * @file + * @author Edward A. Lee + * + * @brief Utlitity functions for initializing parameters and state variables from a file. + * + * To use these functions, create a file that contains the parameter or state variable + * values, separated by a delimiter of your choice. For example, if you have parameters + * `x`, `y`, and `z` of type doublethat you want to initialize from a file `params.csv`, + * you can create a file `params.csv` that contains the values for `x`, `y`, and `z`: + * + * ```csv + * x,y,z + * 1.0,2.0,3.0 + * 4.0,5.0,6.0 + * ``` + * Including a header row with the names of the parameters is optional (but recommended). + * + * Then, you can initialize the parameters from the file `params.csv` as follows: + * + * ```lf-c + * main reactor MyReactor(x: double = 0.0, y: double = 0.0, z: double = 0.0, row_number: int = 0) { + * reaction(startup) {= + * lf_initialize_double("params.csv", ',', self->row_number, &x->value, &y->value, &z->value, NULL); + * =} + * } + * ``` + * The `row_number` parameter is the row number of the file to initialize from. + * If the `row_number` is a top-level parameter (of the main reactor), then you + * can override this parameter on the command line when running the program as follows: + * + * ``` + * ./MyReactor --row_number=1 + * ``` + * + * If you want to initialize state variables rather than parameters, then you can + * initialize them in the startup reaction as follows: + * + * ```lf-c + * reaction(startup) {= + * lf_initialize_double("params.csv", ',', self->row_number, &self->x, &self->y, &self->z, NULL); + * =} + * + * If you have reactors within a bank, then you can declare a `bank_index` parameter + * and use it to calculate the row number of the file to initialize from. For example: + * ```lf-c + * reactor MyReactor(bank_index: int = 0) { + * reaction(startup) {= + * lf_initialize_double("params.csv", ',', self->bank_index + 1, &self->x, &self->y, &self->z, NULL); + * =} + * } + * ``` + * The `bank_index` parameter is the index within the bank, starting from 0. + * The `+ 1` specifies to skip the header row. + * This way, each bank member can have a different set of paramter values. + * + * To use this, include the following in your target properties: + * ``` + * target C { + * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", + * files: ["/lib/c/reactor-c/util/initialize_from_file.c", "/lib/c/reactor-c/util/initialize_from_file.h"] + * }; + * ``` + * In addition, you need this in your Lingua Franca file: + * ``` + * preamble {= + * #include "initialize_from_file.h" + * =} + * ``` + */ +#ifndef INITIALIZE_FROM_FILE_H +#define INITIALIZE_FROM_FILE_H + +#include // Defines size_t + +#define SC_CSV_LINE_MAX 256 +#define SC_CSV_MAX_COLS 256 + +/** + * @brief Read one delimited row and parse as doubles. + * @ingroup Utilities + * + * The variadic arguments are double* pointers, terminated with NULL. + * Example: + * ``` + * double a, b; + * lf_read_numeric_row("x.csv", ',', 3, &a, &b, NULL); + * ``` + */ +int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...); + +#endif // INITIALIZE_FROM_FILE_H \ No newline at end of file From ae198f25411ea266fd63dde93f2a9f35883138ca Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 10 Apr 2026 10:14:11 -0700 Subject: [PATCH 071/105] Format --- util/initialize_from_file.c | 5 ++--- util/initialize_from_file.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c index 0c2d4a103..4d37b9afb 100644 --- a/util/initialize_from_file.c +++ b/util/initialize_from_file.c @@ -74,9 +74,8 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number if (end != fields[i] && *end == '\0') { *out = parsed; } else { - lf_print_error( - "Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", - fields[i], row_number, i, filename); + lf_print_error("Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], + row_number, i, filename); } } va_end(ap); diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index c9c7b83a5..b16e97409 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -4,20 +4,20 @@ * * @brief Utlitity functions for initializing parameters and state variables from a file. * - * To use these functions, create a file that contains the parameter or state variable + * To use these functions, create a file that contains the parameter or state variable * values, separated by a delimiter of your choice. For example, if you have parameters * `x`, `y`, and `z` of type doublethat you want to initialize from a file `params.csv`, * you can create a file `params.csv` that contains the values for `x`, `y`, and `z`: - * + * * ```csv * x,y,z * 1.0,2.0,3.0 * 4.0,5.0,6.0 * ``` * Including a header row with the names of the parameters is optional (but recommended). - * + * * Then, you can initialize the parameters from the file `params.csv` as follows: - * + * * ```lf-c * main reactor MyReactor(x: double = 0.0, y: double = 0.0, z: double = 0.0, row_number: int = 0) { * reaction(startup) {= @@ -28,19 +28,19 @@ * The `row_number` parameter is the row number of the file to initialize from. * If the `row_number` is a top-level parameter (of the main reactor), then you * can override this parameter on the command line when running the program as follows: - * + * * ``` * ./MyReactor --row_number=1 * ``` * - * If you want to initialize state variables rather than parameters, then you can + * If you want to initialize state variables rather than parameters, then you can * initialize them in the startup reaction as follows: - * + * * ```lf-c * reaction(startup) {= * lf_initialize_double("params.csv", ',', self->row_number, &self->x, &self->y, &self->z, NULL); * =} - * + * * If you have reactors within a bank, then you can declare a `bank_index` parameter * and use it to calculate the row number of the file to initialize from. For example: * ```lf-c From 863c0e0e245c8b280a9d80cc4044bf1822adc08f Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 14:45:46 -0700 Subject: [PATCH 072/105] Added ability to read int values --- util/initialize_from_file.c | 65 ++++++++++---- util/initialize_from_file.h | 170 ++++++++++++++++++++++++------------ 2 files changed, 163 insertions(+), 72 deletions(-) diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c index 4d37b9afb..cfbcaeb11 100644 --- a/util/initialize_from_file.c +++ b/util/initialize_from_file.c @@ -7,6 +7,8 @@ #include "logging/api/logging.h" #include "initialize_from_file.h" +typedef enum { LF_TYPE_DOUBLE, LF_TYPE_INT } lf_numeric_type; + /** Remove leading and trailing whitespace from the string. */ static void sc_csv_trim(char* s) { char* p = s; @@ -38,8 +40,12 @@ static int sc_csv_split(char* line, char delimiter, char** fields, int max_field return n; } -int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...) { - va_list ap; +/** + * Shared implementation for lf_initialize_double and lf_initialize_int. + * The `type` parameter selects whether va_arg pointers are double* or int*. + */ +static int lf_initialize_numeric(const char* filename, char delimiter, size_t row_number, lf_numeric_type type, + va_list ap) { size_t pointer_count = 0; FILE* f = fopen(filename, "r"); if (!f) { @@ -61,24 +67,35 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number char* fields[SC_CSV_MAX_COLS]; int field_count = sc_csv_split(row, delimiter, fields, SC_CSV_MAX_COLS); - va_start(ap, row_number); for (size_t i = 0; i < (size_t)field_count; i++) { - double* out = va_arg(ap, double*); - if (out == NULL) { - break; - } - pointer_count++; - sc_csv_trim(fields[i]); - char* end = NULL; - double parsed = strtod(fields[i], &end); - if (end != fields[i] && *end == '\0') { - *out = parsed; + if (type == LF_TYPE_DOUBLE) { + double* out = va_arg(ap, double*); + if (out == NULL) break; + pointer_count++; + sc_csv_trim(fields[i]); + char* end = NULL; + double parsed = strtod(fields[i], &end); + if (end != fields[i] && *end == '\0') { + *out = parsed; + } else { + lf_print_error("Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], + row_number, i, filename); + } } else { - lf_print_error("Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], - row_number, i, filename); + int* out = va_arg(ap, int*); + if (out == NULL) break; + pointer_count++; + sc_csv_trim(fields[i]); + char* end = NULL; + long parsed = strtol(fields[i], &end, 10); + if (end != fields[i] && *end == '\0') { + *out = (int)parsed; + } else { + lf_print_error("Failed to parse integer value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], + row_number, i, filename); + } } } - va_end(ap); fclose(f); return (int)pointer_count; } @@ -88,3 +105,19 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number fclose(f); return -1; } + +int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...) { + va_list ap; + va_start(ap, row_number); + int result = lf_initialize_numeric(filename, delimiter, row_number, LF_TYPE_DOUBLE, ap); + va_end(ap); + return result; +} + +int lf_initialize_int(const char* filename, char delimiter, size_t row_number, ...) { + va_list ap; + va_start(ap, row_number); + int result = lf_initialize_numeric(filename, delimiter, row_number, LF_TYPE_INT, ap); + va_end(ap); + return result; +} diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index b16e97409..ee1a2d23e 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -3,90 +3,148 @@ * @author Edward A. Lee * * @brief Utlitity functions for initializing parameters and state variables from a file. + * @ingroup Utilities + */ +#ifndef INITIALIZE_FROM_FILE_H +#define INITIALIZE_FROM_FILE_H + +#include // Defines size_t + +#define SC_CSV_LINE_MAX 256 +#define SC_CSV_MAX_COLS 256 + +/** + * @brief Read one delimited row from a file and parse as doubles. + * @ingroup Utilities * - * To use these functions, create a file that contains the parameter or state variable - * values, separated by a delimiter of your choice. For example, if you have parameters - * `x`, `y`, and `z` of type doublethat you want to initialize from a file `params.csv`, - * you can create a file `params.csv` that contains the values for `x`, `y`, and `z`: - * + * Given a file path (either absolute or relative to the current working directory), + * this function reads the specified row, which it assumes is a list of doubles separated by a delimiter, + * and parses the values into a list of specified variables given as a list of double* pointers + * terminated with NULL. + * Example: + * ``` + * double a, b; + * int count = lf_initialize_double("x.csv", ',', 2, &a, &b, NULL); + * ``` + * This will read the third row of the file "x.csv" (row numbers start from 0) + * and parse the values into the variables `a` and `b`. + * The file "x.csv" may look like this:: * ```csv - * x,y,z - * 1.0,2.0,3.0 - * 4.0,5.0,6.0 + * a,b + * 1.0,2.0 + * 3.0,4.0 * ``` - * Including a header row with the names of the parameters is optional (but recommended). - * - * Then, you can initialize the parameters from the file `params.csv` as follows: + * Including a header row with the names of the variables is optional (but recommended). * + * The return value is the number of values parsed (2 in this case), or -1 if an error occurred, + * for example if the file does not exist or the row number is out of range. + * + * To use this to initialize parameters and/or state variables of a reactor, you can do the following: + * * ```lf-c - * main reactor MyReactor(x: double = 0.0, y: double = 0.0, z: double = 0.0, row_number: int = 0) { + * main reactor MyReactor(x: double = 0.0, row_number: int = 0) { + * state y: double = 0.0; * reaction(startup) {= - * lf_initialize_double("params.csv", ',', self->row_number, &x->value, &y->value, &z->value, NULL); + * lf_initialize_double("params.csv", ',', self->row_number, &self->x, &self->y, NULL); * =} * } * ``` - * The `row_number` parameter is the row number of the file to initialize from. - * If the `row_number` is a top-level parameter (of the main reactor), then you + * + * If the `row_number` is a top-level parameter (of the main reactor), as it is above, then you * can override this parameter on the command line when running the program as follows: - * + * * ``` - * ./MyReactor --row_number=1 + * bin/MyReactor --row_number 1 * ``` - * - * If you want to initialize state variables rather than parameters, then you can - * initialize them in the startup reaction as follows: - * - * ```lf-c - * reaction(startup) {= - * lf_initialize_double("params.csv", ',', self->row_number, &self->x, &self->y, &self->z, NULL); - * =} - * - * If you have reactors within a bank, then you can declare a `bank_index` parameter - * and use it to calculate the row number of the file to initialize from. For example: + * This gives an easy way to compile once and run with different parameter values. + * + * If you wish to initialize parameters or state variables of a reactor within a bank, you + * can create a CSV file with one row per bank member and use the `bank_index` parameter to + * select the row to read. For example: * ```lf-c * reactor MyReactor(bank_index: int = 0) { * reaction(startup) {= - * lf_initialize_double("params.csv", ',', self->bank_index + 1, &self->x, &self->y, &self->z, NULL); + * lf_initialize_double("params.csv", ',', self->bank_index + 1, &self->x, &self->y, NULL); * =} * } * ``` * The `bank_index` parameter is the index within the bank, starting from 0. * The `+ 1` specifies to skip the header row. - * This way, each bank member can have a different set of paramter values. - * - * To use this, include the following in your target properties: - * ``` - * target C { - * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", - * files: ["/lib/c/reactor-c/util/initialize_from_file.c", "/lib/c/reactor-c/util/initialize_from_file.h"] - * }; - * ``` - * In addition, you need this in your Lingua Franca file: - * ``` - * preamble {= - * #include "initialize_from_file.h" - * =} - * ``` + * This way, each bank member can have a different set of parameter values. + * + * @param filename The name of the file to read. + * @param delimiter The delimiter character to use. + * @param row_number The row number in the file to read. + * @param ... The double* pointers to the variables to store the values in, terminated with NULL. + * @return The number of values parsed, or -1 if an error occurred. */ -#ifndef INITIALIZE_FROM_FILE_H -#define INITIALIZE_FROM_FILE_H - -#include // Defines size_t - -#define SC_CSV_LINE_MAX 256 -#define SC_CSV_MAX_COLS 256 +int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...); /** - * @brief Read one delimited row and parse as doubles. + * @brief Read one delimited row from a file and parse as integers. * @ingroup Utilities * - * The variadic arguments are double* pointers, terminated with NULL. + * Given a file path (either absolute or relative to the current working directory), + * this function reads the specified row, which it assumes is a list of integers separated by a delimiter, + * and parses the values into a list of specified variables given as a list of int* pointers + * terminated with NULL. * Example: * ``` - * double a, b; - * lf_read_numeric_row("x.csv", ',', 3, &a, &b, NULL); + * int a, b; + * int count = lf_initialize_int("x.csv", ',', 2, &a, &b, NULL); + * ``` + * This will read the third row of the file "x.csv" (row numbers start from 0) + * and parse the values into the variables `a` and `b`. + * The file "x.csv" may look like this:: + * ```csv + * a,b + * 1,2 + * 3,4 + * ``` + * Including a header row with the names of the variables is optional (but recommended). + * + * The return value is the number of values parsed (2 in this case), or -1 if an error occurred, + * for example if the file does not exist or the row number is out of range. + * + * To use this to initialize parameters and/or state variables of a reactor, you can do the following: + * + * ```lf-c + * main reactor MyReactor(x: int = 0, row_number: int = 0) { + * state y: int = 0; + * reaction(startup) {= + * lf_initialize_int("params.csv", ',', self->row_number, &self->x, &self->y, NULL); + * =} + * } + * ``` + * + * If the `row_number` is a top-level parameter (of the main reactor), as it is above, then you + * can override this parameter on the command line when running the program as follows: + * + * ``` + * bin/MyReactor --row_number 1 + * ``` + * This gives an easy way to compile once and run with different parameter values. + * + * If you wish to initialize parameters or state variables of a reactor within a bank, you + * can create a CSV file with one row per bank member and use the `bank_index` parameter to + * select the row to read. For example: + * ```lf-c + * reactor MyReactor(bank_index: int = 0) { + * reaction(startup) {= + * lf_initialize_int("params.csv", ',', self->bank_index + 1, &self->x, &self->y, NULL); + * =} + * } * ``` + * The `bank_index` parameter is the index within the bank, starting from 0. + * The `+ 1` specifies to skip the header row. + * This way, each bank member can have a different set of parameter values. + * + * @param filename The name of the file to read. + * @param delimiter The delimiter character to use. + * @param row_number The row number in the file to read. + * @param ... The int* pointers to the variables to store the values in, terminated with NULL. + * @return The number of values parsed, or -1 if an error occurred. */ -int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...); +int lf_initialize_int(const char* filename, char delimiter, size_t row_number, ...); #endif // INITIALIZE_FROM_FILE_H \ No newline at end of file From 2c7c4a7de4cc2c02846392e96403ea7be2bd2583 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 15:20:56 -0700 Subject: [PATCH 073/105] Added capability to initialize string parameters and state from a file --- util/initialize_from_file.c | 52 +++++++++--- util/initialize_from_file.h | 159 +++++++++++++++++++++++++++++++++--- 2 files changed, 187 insertions(+), 24 deletions(-) diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c index cfbcaeb11..a97acd9af 100644 --- a/util/initialize_from_file.c +++ b/util/initialize_from_file.c @@ -5,9 +5,10 @@ #include #include "logging/api/logging.h" +#include "reactor.h" #include "initialize_from_file.h" -typedef enum { LF_TYPE_DOUBLE, LF_TYPE_INT } lf_numeric_type; +typedef enum { LF_TYPE_DOUBLE, LF_TYPE_INT, LF_TYPE_STRING } lf_field_type; /** Remove leading and trailing whitespace from the string. */ static void sc_csv_trim(char* s) { @@ -41,11 +42,12 @@ static int sc_csv_split(char* line, char delimiter, char** fields, int max_field } /** - * Shared implementation for lf_initialize_double and lf_initialize_int. - * The `type` parameter selects whether va_arg pointers are double* or int*. + * Shared implementation for lf_initialize_double, lf_initialize_int, and _lf_initialize_string. + * The `type` parameter selects the expected va_arg pointer type (double*, int*, or char**). + * The `allocations` parameter is used only for LF_TYPE_STRING to record allocated memory. */ -static int lf_initialize_numeric(const char* filename, char delimiter, size_t row_number, lf_numeric_type type, - va_list ap) { +static int lf_initialize_fields(const char* filename, char delimiter, size_t row_number, lf_field_type type, + struct allocation_record_t** allocations, va_list ap) { size_t pointer_count = 0; FILE* f = fopen(filename, "r"); if (!f) { @@ -68,11 +70,12 @@ static int lf_initialize_numeric(const char* filename, char delimiter, size_t ro char* fields[SC_CSV_MAX_COLS]; int field_count = sc_csv_split(row, delimiter, fields, SC_CSV_MAX_COLS); for (size_t i = 0; i < (size_t)field_count; i++) { + sc_csv_trim(fields[i]); if (type == LF_TYPE_DOUBLE) { double* out = va_arg(ap, double*); - if (out == NULL) break; + if (out == NULL) + break; pointer_count++; - sc_csv_trim(fields[i]); char* end = NULL; double parsed = strtod(fields[i], &end); if (end != fields[i] && *end == '\0') { @@ -81,11 +84,11 @@ static int lf_initialize_numeric(const char* filename, char delimiter, size_t ro lf_print_error("Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], row_number, i, filename); } - } else { + } else if (type == LF_TYPE_INT) { int* out = va_arg(ap, int*); - if (out == NULL) break; + if (out == NULL) + break; pointer_count++; - sc_csv_trim(fields[i]); char* end = NULL; long parsed = strtol(fields[i], &end, 10); if (end != fields[i] && *end == '\0') { @@ -94,6 +97,22 @@ static int lf_initialize_numeric(const char* filename, char delimiter, size_t ro lf_print_error("Failed to parse integer value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], row_number, i, filename); } + } else { + char** out = va_arg(ap, char**); + if (out == NULL) + break; + pointer_count++; + char* field = fields[i]; + size_t len = strlen(field); + if (len >= 2 && + ((field[0] == '"' && field[len - 1] == '"') || (field[0] == '\'' && field[len - 1] == '\''))) { + field++; + len -= 2; + } + char* str = (char*)lf_allocate(len + 1, sizeof(char), allocations); + memcpy(str, field, len); + str[len] = '\0'; + *out = str; } } fclose(f); @@ -109,7 +128,7 @@ static int lf_initialize_numeric(const char* filename, char delimiter, size_t ro int lf_initialize_double(const char* filename, char delimiter, size_t row_number, ...) { va_list ap; va_start(ap, row_number); - int result = lf_initialize_numeric(filename, delimiter, row_number, LF_TYPE_DOUBLE, ap); + int result = lf_initialize_fields(filename, delimiter, row_number, LF_TYPE_DOUBLE, NULL, ap); va_end(ap); return result; } @@ -117,7 +136,16 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number int lf_initialize_int(const char* filename, char delimiter, size_t row_number, ...) { va_list ap; va_start(ap, row_number); - int result = lf_initialize_numeric(filename, delimiter, row_number, LF_TYPE_INT, ap); + int result = lf_initialize_fields(filename, delimiter, row_number, LF_TYPE_INT, NULL, ap); + va_end(ap); + return result; +} + +int _lf_initialize_string(const char* filename, char delimiter, size_t row_number, + struct allocation_record_t** allocations, ...) { + va_list ap; + va_start(ap, allocations); + int result = lf_initialize_fields(filename, delimiter, row_number, LF_TYPE_STRING, allocations, ap); va_end(ap); return result; } diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index ee1a2d23e..d300fc5d4 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -38,9 +38,9 @@ * * The return value is the number of values parsed (2 in this case), or -1 if an error occurred, * for example if the file does not exist or the row number is out of range. - * + * * To use this to initialize parameters and/or state variables of a reactor, you can do the following: - * + * * ```lf-c * main reactor MyReactor(x: double = 0.0, row_number: int = 0) { * state y: double = 0.0; @@ -49,15 +49,15 @@ * =} * } * ``` - * + * * If the `row_number` is a top-level parameter (of the main reactor), as it is above, then you * can override this parameter on the command line when running the program as follows: - * + * * ``` * bin/MyReactor --row_number 1 * ``` * This gives an easy way to compile once and run with different parameter values. - * + * * If you wish to initialize parameters or state variables of a reactor within a bank, you * can create a CSV file with one row per bank member and use the `bank_index` parameter to * select the row to read. For example: @@ -71,7 +71,27 @@ * The `bank_index` parameter is the index within the bank, starting from 0. * The `+ 1` specifies to skip the header row. * This way, each bank member can have a different set of parameter values. - * + * + * To use this in a Lingua Franca program, you must include the following in the target declaration: + * ```lf-c + * target C { + * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", + * files: [ + * "/lib/c/reactor-c/util/initialize_from_file.c", + * "/lib/c/reactor-c/util/initialize_from_file.h"] + * } + * ``` + * + * Then, in the reactor, you can include the header file as follows: + * ```lf-c + * reactor MyReactor { + * preamble {= + * #include "initialize_from_file.h" + * =} + * ... + * } + * ``` + * * @param filename The name of the file to read. * @param delimiter The delimiter character to use. * @param row_number The row number in the file to read. @@ -105,9 +125,9 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * * The return value is the number of values parsed (2 in this case), or -1 if an error occurred, * for example if the file does not exist or the row number is out of range. - * + * * To use this to initialize parameters and/or state variables of a reactor, you can do the following: - * + * * ```lf-c * main reactor MyReactor(x: int = 0, row_number: int = 0) { * state y: int = 0; @@ -116,15 +136,15 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * =} * } * ``` - * + * * If the `row_number` is a top-level parameter (of the main reactor), as it is above, then you * can override this parameter on the command line when running the program as follows: - * + * * ``` * bin/MyReactor --row_number 1 * ``` * This gives an easy way to compile once and run with different parameter values. - * + * * If you wish to initialize parameters or state variables of a reactor within a bank, you * can create a CSV file with one row per bank member and use the `bank_index` parameter to * select the row to read. For example: @@ -138,7 +158,27 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * The `bank_index` parameter is the index within the bank, starting from 0. * The `+ 1` specifies to skip the header row. * This way, each bank member can have a different set of parameter values. - * + * + * To use this in a Lingua Franca program, you must include the following in the target declaration: + * ```lf-c + * target C { + * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", + * files: [ + * "/lib/c/reactor-c/util/initialize_from_file.c", + * "/lib/c/reactor-c/util/initialize_from_file.h"] + * } + * ``` + * + * Then, in the reactor, you can include the header file as follows: + * ```lf-c + * reactor MyReactor { + * preamble {= + * #include "initialize_from_file.h" + * =} + * ... + * } + * ``` + * * @param filename The name of the file to read. * @param delimiter The delimiter character to use. * @param row_number The row number in the file to read. @@ -147,4 +187,99 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number */ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, ...); +/** + * @brief Read one delimited row from a file and parse as strings. + * @ingroup Utilities + * + * Given a file path (either absolute or relative to the current working directory), + * this function reads the specified row, which it assumes is a list of strings separated by a delimiter, + * and parses the values into a list of specified variables given as a list of char** pointers + * terminated with NULL. If a field is enclosed in quotation marks (double or single), the marks + * are stripped. Memory for each string is allocated using `lf_allocate` and recorded in the + * reactor's allocation list so that it is freed automatically when the reactor is freed. + * Example: + * ``` + * char* a; + * char* b; + * int count = lf_initialize_string("x.csv", ',', 2, &a, &b, NULL); + * ``` + * This will read the third row of the file "x.csv" (row numbers start from 0) + * and parse the values into the variables `a` and `b`. + * The file "x.csv" may look like this:: + * ```csv + * a,b + * "hello","world" + * foo,bar + * ``` + * The quotation marks are optional and will be stripped if present. + * Including a header row with the names of the variables is optional (but recommended). + * + * The return value is the number of values parsed (2 in this case), or -1 if an error occurred, + * for example if the file does not exist or the row number is out of range. + * + * To use this to initialize parameters and/or state variables of a reactor, you can do the following: + * + * ```lf-c + * main reactor MyReactor(row_number: int = 0) { + * state name: string = ""; + * reaction(startup) {= + * lf_initialize_string("params.csv", ',', self->row_number, &self->name, NULL); + * =} + * } + * ``` + * + * If the `row_number` is a top-level parameter (of the main reactor), as it is above, then you + * can override this parameter on the command line when running the program as follows: + * + * ``` + * bin/MyReactor --row_number 1 + * ``` + * This gives an easy way to compile once and run with different parameter values. + * + * If you wish to initialize parameters or state variables of a reactor within a bank, you + * can create a CSV file with one row per bank member and use the `bank_index` parameter to + * select the row to read. For example: + * ```lf-c + * reactor MyReactor(bank_index: int = 0) { + * reaction(startup) {= + * lf_initialize_string("params.csv", ',', self->bank_index + 1, &self->name, NULL); + * =} + * } + * ``` + * The `bank_index` parameter is the index within the bank, starting from 0. + * The `+ 1` specifies to skip the header row. + * This way, each bank member can have a different set of parameter values. + * + * To use this in a Lingua Franca program, you must include the following in the target declaration: + * ```lf-c + * target C { + * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", + * files: [ + * "/lib/c/reactor-c/util/initialize_from_file.c", + * "/lib/c/reactor-c/util/initialize_from_file.h"] + * } + * ``` + * + * Then, in the reactor, you can include the header file as follows: + * ```lf-c + * reactor MyReactor { + * preamble {= + * #include "initialize_from_file.h" + * =} + * ... + * } + * ``` + * + * @param filename The name of the file to read. + * @param delimiter The delimiter character to use. + * @param row_number The row number in the file to read. + * @param ... The char** pointers to the variables to store the values in, terminated with NULL. + * @return The number of values parsed, or -1 if an error occurred. + */ +#define lf_initialize_string(filename, delimiter, row_number, ...) \ + _lf_initialize_string(filename, delimiter, row_number, &((self_base_t*)self)->allocations, __VA_ARGS__) + +int _lf_initialize_string(const char* filename, char delimiter, size_t row_number, + struct allocation_record_t** allocations, ...); + #endif // INITIALIZE_FROM_FILE_H \ No newline at end of file From a9509a48527676d1488ba9f0604b39f258c366a2 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 15:35:02 -0700 Subject: [PATCH 074/105] Response to Copilot reviews --- util/initialize_from_file.c | 14 ++++++++++++-- util/initialize_from_file.h | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c index a97acd9af..50b2f431d 100644 --- a/util/initialize_from_file.c +++ b/util/initialize_from_file.c @@ -61,12 +61,20 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row if (row_count == row_number) { char* row = &line[0]; // Remove the UTF-8 BOM (byte-order mark) if it exists. - if ((unsigned char)line[0] == 0xEF && (unsigned char)line[1] == 0xBB && (unsigned char)line[2] == 0xBF) { + size_t line_length = strlen(row); + if (line_length >= 3 && (unsigned char)row[0] == 0xEF && (unsigned char)row[1] == 0xBB && + (unsigned char)line[2] == 0xBF) { row += 3; + line_length -= 3; } // Terminate the last item in the line with a null character. row[strcspn(row, "\r\n")] = '\0'; - + line_length = strcspn(row, "\r\n"); + if (line_length >= SC_CSV_LINE_MAX) { + lf_print_error("Line too long in file \"%s\".", filename); + fclose(f); + return -1; + } char* fields[SC_CSV_MAX_COLS]; int field_count = sc_csv_split(row, delimiter, fields, SC_CSV_MAX_COLS); for (size_t i = 0; i < (size_t)field_count; i++) { @@ -83,6 +91,7 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row } else { lf_print_error("Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], row_number, i, filename); + return -1; } } else if (type == LF_TYPE_INT) { int* out = va_arg(ap, int*); @@ -96,6 +105,7 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row } else { lf_print_error("Failed to parse integer value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], row_number, i, filename); + return -1; } } else { char** out = va_arg(ap, char**); diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index d300fc5d4..9136c4c8f 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -2,7 +2,7 @@ * @file * @author Edward A. Lee * - * @brief Utlitity functions for initializing parameters and state variables from a file. + * @brief Utility functions for initializing parameters and state variables from a file. * @ingroup Utilities */ #ifndef INITIALIZE_FROM_FILE_H From e16ec15257cd04d418b9e52234676f8ac7c3fef2 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 16:11:57 -0700 Subject: [PATCH 075/105] Respond to Copilot reviews and point to utility-functions branch of lingua-franca --- lingua-franca-ref.txt | 2 +- util/initialize_from_file.c | 34 ++++++++++++++++++++++------------ util/initialize_from_file.h | 17 ++++++++++++++++- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 1f7391f92..0edbf7fc9 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master +utility-functions diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c index 50b2f431d..6ff7bbac0 100644 --- a/util/initialize_from_file.c +++ b/util/initialize_from_file.c @@ -58,23 +58,24 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row char line[SC_CSV_LINE_MAX]; size_t row_count = 0; while (fgets(line, sizeof(line), f)) { + // Detect truncation: fgets didn't capture a newline and we're not at EOF. + size_t len = strlen(line); + int truncated = (len > 0 && line[len - 1] != '\n' && !feof(f)); + if (row_count == row_number) { + if (truncated) { + lf_print_error("Row %zu exceeds maximum line length of %d in file \"%s\".", row_number, SC_CSV_LINE_MAX - 1, + filename); + fclose(f); + return -1; + } char* row = &line[0]; - // Remove the UTF-8 BOM (byte-order mark) if it exists. - size_t line_length = strlen(row); - if (line_length >= 3 && (unsigned char)row[0] == 0xEF && (unsigned char)row[1] == 0xBB && - (unsigned char)line[2] == 0xBF) { + if (len >= 3 && (unsigned char)row[0] == 0xEF && (unsigned char)row[1] == 0xBB && + (unsigned char)row[2] == 0xBF) { row += 3; - line_length -= 3; } - // Terminate the last item in the line with a null character. row[strcspn(row, "\r\n")] = '\0'; - line_length = strcspn(row, "\r\n"); - if (line_length >= SC_CSV_LINE_MAX) { - lf_print_error("Line too long in file \"%s\".", filename); - fclose(f); - return -1; - } + char* fields[SC_CSV_MAX_COLS]; int field_count = sc_csv_split(row, delimiter, fields, SC_CSV_MAX_COLS); for (size_t i = 0; i < (size_t)field_count; i++) { @@ -91,6 +92,7 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row } else { lf_print_error("Failed to parse numeric value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], row_number, i, filename); + fclose(f); return -1; } } else if (type == LF_TYPE_INT) { @@ -105,6 +107,7 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row } else { lf_print_error("Failed to parse integer value \"%s\" at row %zu, column %zu in \"%s\".", fields[i], row_number, i, filename); + fclose(f); return -1; } } else { @@ -128,6 +131,13 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row fclose(f); return (int)pointer_count; } + if (truncated) { + // Consume the rest of this over-long line so it counts as one row. + while (fgets(line, sizeof(line), f)) { + len = strlen(line); + if ((len > 0 && line[len - 1] == '\n') || feof(f)) break; + } + } row_count++; } lf_print_error("Requested row %zu not found in file \"%s\".", row_number, filename); diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index 9136c4c8f..34d57e81a 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -9,6 +9,8 @@ #define INITIALIZE_FROM_FILE_H #include // Defines size_t +#include "reactor.h" +#include "lf_types.h" #define SC_CSV_LINE_MAX 256 #define SC_CSV_MAX_COLS 256 @@ -197,12 +199,24 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * terminated with NULL. If a field is enclosed in quotation marks (double or single), the marks * are stripped. Memory for each string is allocated using `lf_allocate` and recorded in the * reactor's allocation list so that it is freed automatically when the reactor is freed. + * + * This macro is meant to be called from a reaction, not directly. If you wish to call it from + * somewhere other than a reaction, you can use the following function: + * ```lf-c + * int _lf_initialize_string(const char* filename, char delimiter, size_t row_number, + * struct allocation_record_t** allocations, ...); + * ``` + * If you pass NULL for the allocations parameter, then you will be responsible for freeing the allocated memory. * Example: * ``` * char* a; * char* b; - * int count = lf_initialize_string("x.csv", ',', 2, &a, &b, NULL); + * int count = _lf_initialize_string("x.csv", ',', 2, NULL, &a, &b, NULL); + * ... + * free(a); + * free(b); * ``` + * * This will read the third row of the file "x.csv" (row numbers start from 0) * and parse the values into the variables `a` and `b`. * The file "x.csv" may look like this:: @@ -212,6 +226,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * foo,bar * ``` * The quotation marks are optional and will be stripped if present. + * Note that putting a delimiter within the quotation marks is not supported and will give unpredictable results. * Including a header row with the names of the variables is optional (but recommended). * * The return value is the number of values parsed (2 in this case), or -1 if an error occurred, From 6422f1538c624fefd43afb2866880d09d1e74789 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Sat, 11 Apr 2026 16:59:06 -0700 Subject: [PATCH 076/105] Correctly return py_update_deadline and update the LF reference --- lingua-franca-ref.txt | 2 +- python/lib/pythontarget.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 01d44e951..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -python-update-deadline +master diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index f16928e4d..73fbdd971 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -266,6 +266,8 @@ PyObject* py_update_deadline(PyObject* self, PyObject* args) { return NULL; } lf_update_deadline(self_ptr, updated_deadline); + + Py_INCREF(Py_None); return Py_None; } From ac025b262aa5de1a8cd91519b3576001e07a5d2b Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 17:00:50 -0700 Subject: [PATCH 077/105] Make compatible with CCpp --- util/initialize_from_file.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index 34d57e81a..5b3707a08 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -12,6 +12,10 @@ #include "reactor.h" #include "lf_types.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SC_CSV_LINE_MAX 256 #define SC_CSV_MAX_COLS 256 @@ -297,4 +301,8 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . int _lf_initialize_string(const char* filename, char delimiter, size_t row_number, struct allocation_record_t** allocations, ...); +#ifdef __cplusplus +} +#endif + #endif // INITIALIZE_FROM_FILE_H \ No newline at end of file From d757b19026a73e5ff5c0a4abc6a4961f93a5f8db Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 17:02:26 -0700 Subject: [PATCH 078/105] Format --- util/initialize_from_file.c | 6 +++--- util/initialize_from_file.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/util/initialize_from_file.c b/util/initialize_from_file.c index 6ff7bbac0..d945d8197 100644 --- a/util/initialize_from_file.c +++ b/util/initialize_from_file.c @@ -70,8 +70,7 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row return -1; } char* row = &line[0]; - if (len >= 3 && (unsigned char)row[0] == 0xEF && (unsigned char)row[1] == 0xBB && - (unsigned char)row[2] == 0xBF) { + if (len >= 3 && (unsigned char)row[0] == 0xEF && (unsigned char)row[1] == 0xBB && (unsigned char)row[2] == 0xBF) { row += 3; } row[strcspn(row, "\r\n")] = '\0'; @@ -135,7 +134,8 @@ static int lf_initialize_fields(const char* filename, char delimiter, size_t row // Consume the rest of this over-long line so it counts as one row. while (fgets(line, sizeof(line), f)) { len = strlen(line); - if ((len > 0 && line[len - 1] == '\n') || feof(f)) break; + if ((len > 0 && line[len - 1] == '\n') || feof(f)) + break; } } row_count++; diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index 5b3707a08..595902dee 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -203,7 +203,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * terminated with NULL. If a field is enclosed in quotation marks (double or single), the marks * are stripped. Memory for each string is allocated using `lf_allocate` and recorded in the * reactor's allocation list so that it is freed automatically when the reactor is freed. - * + * * This macro is meant to be called from a reaction, not directly. If you wish to call it from * somewhere other than a reaction, you can use the following function: * ```lf-c @@ -220,7 +220,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * free(a); * free(b); * ``` - * + * * This will read the third row of the file "x.csv" (row numbers start from 0) * and parse the values into the variables `a` and `b`. * The file "x.csv" may look like this:: From 3c94571d4f7658f477e6fb46785d734a36cfb695 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 17:18:00 -0700 Subject: [PATCH 079/105] Avoid freeing a token that has gone on the reaction queue. --- core/federated/federate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index c5a94ae4e..b6666e294 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -642,7 +642,8 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { env->current_tag.time - start_time, env->current_tag.microstep, intended_tag.time - start_time, intended_tag.microstep); // Free the allocated memory before returning - _lf_done_using(message_token); + // Can't free message_token here because it has been sent to the reaction queue. + // _lf_done_using(message_token); // Close network abstraction, reading any incoming data and discarding it. shutdown_net(_fed.net_for_inbound_p2p_connections[fed_id], false); _fed.net_for_inbound_p2p_connections[fed_id] = NULL; From 986d8544f509f8f0bfe379437666e29961671094 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 17:21:04 -0700 Subject: [PATCH 080/105] Comments only --- core/federated/federate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index b6666e294..32b92263c 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -641,7 +641,6 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { " Discarding message and closing the network connection.", env->current_tag.time - start_time, env->current_tag.microstep, intended_tag.time - start_time, intended_tag.microstep); - // Free the allocated memory before returning // Can't free message_token here because it has been sent to the reaction queue. // _lf_done_using(message_token); // Close network abstraction, reading any incoming data and discarding it. From 79a3a674e5b42eeb882ea0724cd80bdaf58755de Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 17:22:12 -0700 Subject: [PATCH 081/105] Attempt to fix double-free error --- core/federated/federate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index c5a94ae4e..32b92263c 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -641,8 +641,8 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { " Discarding message and closing the network connection.", env->current_tag.time - start_time, env->current_tag.microstep, intended_tag.time - start_time, intended_tag.microstep); - // Free the allocated memory before returning - _lf_done_using(message_token); + // Can't free message_token here because it has been sent to the reaction queue. + // _lf_done_using(message_token); // Close network abstraction, reading any incoming data and discarding it. shutdown_net(_fed.net_for_inbound_p2p_connections[fed_id], false); _fed.net_for_inbound_p2p_connections[fed_id] = NULL; From b1766e53305d98417b22b6832dd28641d0bf7473 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 11 Apr 2026 17:33:49 -0700 Subject: [PATCH 082/105] Reverting previous attempt, which didn't work. --- core/federated/federate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 32b92263c..c5a94ae4e 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -641,8 +641,8 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { " Discarding message and closing the network connection.", env->current_tag.time - start_time, env->current_tag.microstep, intended_tag.time - start_time, intended_tag.microstep); - // Can't free message_token here because it has been sent to the reaction queue. - // _lf_done_using(message_token); + // Free the allocated memory before returning + _lf_done_using(message_token); // Close network abstraction, reading any incoming data and discarding it. shutdown_net(_fed.net_for_inbound_p2p_connections[fed_id], false); _fed.net_for_inbound_p2p_connections[fed_id] = NULL; From a0142009b180ab46d942de91e4d5cb3022992339 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 Apr 2026 10:57:32 -0700 Subject: [PATCH 083/105] Check calloc result --- core/lf_token.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/lf_token.c b/core/lf_token.c index 41a4c8c0f..ca729813a 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -228,6 +228,7 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { if (result == NULL) { // Nothing found on the recycle bin. result = (lf_token_t*)calloc(1, sizeof(lf_token_t)); + LF_ASSERT_NON_NULL(result); LF_PRINT_DEBUG("_lf_new_token: Allocated memory for token: %p", (void*)result); } result->type = type; From 7253f5f5b339ed9bc242e1b9f7fc03b2eec65d10 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sun, 12 Apr 2026 14:12:24 -0700 Subject: [PATCH 084/105] Fix to not set pointers in stack to NULL. --- core/federated/RTI/rti_remote.c | 3 --- core/federated/federate.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 0f06b6c50..dbeac7ae5 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -1057,7 +1057,6 @@ void send_reject(net_abstraction_t net_abs, unsigned char error_code) { } // Close the network abstraction without reading until EOF. shutdown_net(net_abs, false); - net_abs = NULL; LF_MUTEX_UNLOCK(&rti_mutex); } @@ -1427,7 +1426,6 @@ void lf_connect_to_federates(net_abstraction_t rti_net) { lf_print_warning("RTI failed to authenticate the incoming federate."); // Close the network abstraction without reading until EOF. shutdown_net(fed_net, false); - fed_net = NULL; // Ignore the federate that failed authentication. i--; continue; @@ -1496,7 +1494,6 @@ void* respond_to_erroneous_connections(void* nothing) { } // Close the network abstraction without reading until EOF. shutdown_net(fed_net, false); - fed_net = NULL; } return NULL; } diff --git a/core/federated/federate.c b/core/federated/federate.c index c5a94ae4e..6ed1efc46 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2034,7 +2034,6 @@ void* lf_handle_p2p_connections_from_federates(void* env_arg) { write_to_net(net, 2, response); } shutdown_net(net, false); - net = NULL; continue; } @@ -2055,7 +2054,6 @@ void* lf_handle_p2p_connections_from_federates(void* env_arg) { write_to_net(net, 2, response); } shutdown_net(net, false); - net = NULL; continue; } From 53aee73860c4142dcb27a3fc1d84bd6fb7a3b63a Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sun, 12 Apr 2026 14:14:01 -0700 Subject: [PATCH 085/105] Fix lf_handle_p2p_connections_from_federates() to not return NULL when accept fails. --- core/federated/federate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 6ed1efc46..5f8f8cfb8 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2013,7 +2013,7 @@ void* lf_handle_p2p_connections_from_federates(void* env_arg) { net_abstraction_t net = accept_net(_fed.server_net); if (net == NULL) { lf_print_warning("Federate failed to accept the network abstraction."); - return NULL; + continue; } LF_PRINT_LOG("Accepted new connection from remote federate."); From c0d284cba2218d0a83426f06b31cd6fa85335076 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sun, 12 Apr 2026 14:54:25 -0700 Subject: [PATCH 086/105] Remove server_hostname from socket_priv_t, and following usages. --- core/federated/RTI/rti_remote.c | 8 ++------ core/federated/RTI/rti_remote.h | 2 +- network/api/socket_common.h | 4 +--- network/impl/src/lf_socket_support.c | 4 +--- network/impl/src/socket_common.c | 8 ++------ 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index dbeac7ae5..848628e3d 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -636,23 +636,20 @@ void handle_address_query(uint16_t fed_id) { int32_t server_port; uint32_t* ip_address; - char* server_host_name; + uint32_t temp = 0; LF_MUTEX_LOCK(&rti_mutex); // Check if the RTI has initialized the remote federate's network abstraction. if (remote_fed->net == NULL) { // RTI has not set up the remote federate. Respond with -1 to indicate an unknown port number. server_port = -1; - uint32_t temp = 0; ip_address = &temp; - server_host_name = "localhost"; } else { // The network abstraction is initialized, but the RTI might still not know the port number. This can happen if the // RTI has not yet received a MSG_TYPE_ADDRESS_ADVERTISEMENT message from the remote federate. In such cases, the // returned port number might still be -1. server_port = ((socket_priv_t*)remote_fed->net)->server_port; ip_address = (uint32_t*)&((socket_priv_t*)remote_fed->net)->server_ip_addr; - server_host_name = ((socket_priv_t*)remote_fed->net)->server_hostname; } encode_int32(server_port, (unsigned char*)&buffer[1]); @@ -669,8 +666,7 @@ void handle_address_query(uint16_t fed_id) { tracepoint_rti_to_federate(send_ADR_QR_REP, fed_id, NULL); } - LF_PRINT_DEBUG("Replied to address query from federate %d with address %s:%d.", fed_id, server_host_name, - server_port); + LF_PRINT_DEBUG("Replied to address query from federate %d", fed_id); } void handle_address_ad(uint16_t federate_id) { diff --git a/core/federated/RTI/rti_remote.h b/core/federated/RTI/rti_remote.h index 0fcb4bfda..f6a7a9751 100644 --- a/core/federated/RTI/rti_remote.h +++ b/core/federated/RTI/rti_remote.h @@ -271,7 +271,7 @@ void handle_address_query(uint16_t fed_id); * byte. The RTI will keep a record of this number in the .server_port * field of the _RTI.federates[federate_id] array of structs. * - * The server_hostname and server_ip_addr fields are assigned + * The server_ip_addr field is assigned * in lf_connect_to_federates() upon accepting the socket * from the remote federate. * diff --git a/network/api/socket_common.h b/network/api/socket_common.h index edab21dd8..d026d05fb 100644 --- a/network/api/socket_common.h +++ b/network/api/socket_common.h @@ -149,8 +149,6 @@ typedef struct socket_priv_t { uint16_t port; /** @brief The desired port specified by the user on the command line. */ uint16_t user_specified_port; - /** @brief Human-readable IP address of the federate's socket server. */ - char server_hostname[INET_ADDRSTRLEN]; /** @brief Port number of the socket server of the federate. The port number will be -1 if there is no server or if * the RTI has not been informed of the port number. */ int32_t server_port; @@ -296,7 +294,7 @@ bool is_socket_open(int socket); * @ingroup Network * * Get the connected peer name from the connected socket. - * Set it to the server_ip_addr. Also, set server_hostname if LOG_LEVEL is higher than LOG_LEVEL_DEBUG. + * Set it to the server_ip_addr. Also, print server's hostname if LOG_LEVEL is higher than LOG_LEVEL_DEBUG. * * @param priv The socket_priv struct. * @return 0 for success, -1 for failure. diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 76aee2308..37240c606 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -30,7 +30,6 @@ net_abstraction_t initialize_net() { priv->socket_descriptor = -1; // Federate initialization - strncpy(priv->server_hostname, "localhost", INET_ADDRSTRLEN); priv->server_ip_addr.s_addr = 0; priv->server_port = -1; @@ -83,11 +82,10 @@ net_abstraction_t connect_to_net(net_params_t params) { socket_priv_t* priv = (socket_priv_t*)net; socket_connection_params_t* sock_params = (socket_connection_params_t*)params; priv->server_port = sock_params->port; - memcpy(priv->server_hostname, sock_params->server_hostname, INET_ADDRSTRLEN); // Create the client network abstraction. create_client(net); // Connect to the target server. - if (connect_to_socket(priv->socket_descriptor, priv->server_hostname, priv->server_port) != 0) { + if (connect_to_socket(priv->socket_descriptor, sock_params->server_hostname, priv->server_port) != 0) { lf_print_error("Failed to connect to socket."); return NULL; } diff --git a/network/impl/src/socket_common.c b/network/impl/src/socket_common.c index 53c78c68d..7942472ca 100644 --- a/network/impl/src/socket_common.c +++ b/network/impl/src/socket_common.c @@ -177,14 +177,10 @@ int get_peer_address(socket_priv_t* priv) { priv->server_ip_addr = peer_addr.sin_addr; #if LOG_LEVEL >= LOG_LEVEL_DEBUG - // Create the human readable format and copy that into - // the .server_hostname field of the federate. + // Create the human readable format for logging purposes char str[INET_ADDRSTRLEN + 1]; inet_ntop(AF_INET, &priv->server_ip_addr, str, INET_ADDRSTRLEN); - strncpy(priv->server_hostname, str, INET_ADDRSTRLEN - 1); // Copy up to INET_ADDRSTRLEN - 1 characters - priv->server_hostname[INET_ADDRSTRLEN - 1] = '\0'; // Null-terminate explicitly - - LF_PRINT_DEBUG("Got address %s", priv->server_hostname); + LF_PRINT_DEBUG("Got address %s", str); #endif return 0; } From 736f4b71cb66aac34ae814e2d70f60473051d951 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 Apr 2026 15:12:01 -0700 Subject: [PATCH 087/105] Add include guard. --- logging/api/logging.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/logging/api/logging.h b/logging/api/logging.h index d926f92eb..4afd501e8 100644 --- a/logging/api/logging.h +++ b/logging/api/logging.h @@ -10,6 +10,9 @@ * It provides functions for different log levels (error, warning, info, log, debug) * and allows for custom message handling through function registration. */ +#ifndef LOGGING_H +#define LOGGING_H + #include // To silence warnings about a function being a candidate for format checking @@ -198,3 +201,5 @@ typedef void(print_message_function_t)(const char*, va_list); * @param log_level The level of messages to redirect. */ void lf_register_print_function(print_message_function_t* function, int log_level); + +#endif // LOGGING_H From 80f97300fdaff449127b2b6f148250c127722251 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 Apr 2026 15:16:25 -0700 Subject: [PATCH 088/105] Reverse incorrect patch --- core/federated/federate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 32b92263c..c5a94ae4e 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -641,8 +641,8 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { " Discarding message and closing the network connection.", env->current_tag.time - start_time, env->current_tag.microstep, intended_tag.time - start_time, intended_tag.microstep); - // Can't free message_token here because it has been sent to the reaction queue. - // _lf_done_using(message_token); + // Free the allocated memory before returning + _lf_done_using(message_token); // Close network abstraction, reading any incoming data and discarding it. shutdown_net(_fed.net_for_inbound_p2p_connections[fed_id], false); _fed.net_for_inbound_p2p_connections[fed_id] = NULL; From ca778628e2d5f2d1e6d92516a560e0e2507cbeec Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 Apr 2026 15:22:14 -0700 Subject: [PATCH 089/105] Removed redundant docs --- util/deque.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/util/deque.c b/util/deque.c index 584fa00a7..8b6807992 100644 --- a/util/deque.c +++ b/util/deque.c @@ -44,10 +44,6 @@ typedef struct deque_node_t { void* value; } deque_node_t; -/** - * Initialize the specified deque to an empty deque. - * @param d The deque. - */ void deque_initialize(deque_t* d) { if (d != NULL) { d->front = NULL; @@ -56,10 +52,6 @@ void deque_initialize(deque_t* d) { } } -/** - * Return true if the queue is empty. - * @param d The deque. - */ bool deque_is_empty(deque_t* d) { if (d != NULL) { return (d->front == NULL); @@ -67,11 +59,6 @@ bool deque_is_empty(deque_t* d) { return true; } -/** - * Return the size of the queue. - * @param d The deque. - * @return The size of the queue. - */ size_t deque_size(deque_t* d) { return d->size; } /** @@ -87,11 +74,6 @@ deque_node_t* _deque_create_node(void* value) { return new_node; } -/** - * Push a value to the front of the queue. - * @param d The queue. - * @param value The value to push. - */ void deque_push_front(deque_t* d, void* value) { deque_node_t* n = _deque_create_node(value); if (d->front == NULL) { @@ -105,11 +87,6 @@ void deque_push_front(deque_t* d, void* value) { } } -/** - * Push a value to the back of the queue. - * @param d The queue. - * @param value The value to push. - */ void deque_push_back(deque_t* d, void* value) { deque_node_t* n = _deque_create_node(value); if (d->back == NULL) { @@ -123,11 +100,6 @@ void deque_push_back(deque_t* d, void* value) { } } -/** - * Pop a value from the front of the queue, removing it from the queue. - * @param d The queue. - * @return The value on the front of the queue or NULL if the queue is empty. - */ void* deque_pop_front(deque_t* d) { if (d == NULL || d->front == NULL) { return NULL; @@ -147,11 +119,6 @@ void* deque_pop_front(deque_t* d) { return value; } -/** - * Pop a value from the back of the queue, removing it from the queue. - * @param d The queue. - * @return The value on the back of the queue or NULL if the queue is empty. - */ void* deque_pop_back(deque_t* d) { if (d == NULL || d->back == NULL) { return NULL; @@ -170,11 +137,6 @@ void* deque_pop_back(deque_t* d) { return value; } -/** - * Peek at the value on the front of the queue, leaving it on the queue. - * @param d The queue. - * @return The value on the front of the queue or NULL if the queue is empty. - */ void* deque_peek_back(deque_t* d) { if (d == NULL || d->back == NULL) { return NULL; @@ -182,11 +144,6 @@ void* deque_peek_back(deque_t* d) { return d->back->value; } -/** - * Peek at the value on the back of the queue, leaving it on the queue. - * @param d The queue. - * @return The value on the back of the queue or NULL if the queue is empty. - */ void* deque_peek_front(deque_t* d) { if (d == NULL || d->front == NULL) { return NULL; From 14f01c753c9bd76fa67b9beb01f237eea91d8ae8 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 Apr 2026 15:44:07 -0700 Subject: [PATCH 090/105] Reset lingua-franca-ref to point to master --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 0edbf7fc9..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -utility-functions +master From 0bf11da8177a6489c3a577f07b5ff71c35ed384d Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 Apr 2026 15:44:53 -0700 Subject: [PATCH 091/105] Trigger CI From a930ffd145285533956f92e4c9d3d2e68c0dc499 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sun, 12 Apr 2026 18:35:38 -0700 Subject: [PATCH 092/105] Optimized `connect_to_socket()` to bypass redundant `getaddrinfo` DNS resolution if the IP address (`struct in_addr`) is already provided. --- core/federated/federate.c | 9 ++-- network/api/socket_common.h | 6 ++- network/impl/src/lf_socket_support.c | 2 +- network/impl/src/socket_common.c | 67 ++++++++++++++++++---------- 4 files changed, 53 insertions(+), 31 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 5f8f8cfb8..e2971b40d 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1753,13 +1753,10 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { assert(port > 0); uint16_t uport = (uint16_t)port; - char hostname[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &host_ip_addr, hostname, INET_ADDRSTRLEN); - - socket_connection_params_t params; + socket_connection_params_t params = {0}; params.type = TCP; params.port = uport; - params.server_hostname = hostname; + params.server_ip_addr = &host_ip_addr; net_abstraction_t net = connect_to_net((net_params_t)¶ms); if (net == NULL) { lf_print_error_and_exit("Failed to connect to federate."); @@ -1837,7 +1834,7 @@ void lf_connect_to_rti(const char* hostname, int port) { hostname = federation_metadata.rti_host ? federation_metadata.rti_host : hostname; port = federation_metadata.rti_port >= 0 ? federation_metadata.rti_port : port; - socket_connection_params_t params; + socket_connection_params_t params = {0}; params.type = TCP; params.port = port; params.server_hostname = hostname; diff --git a/network/api/socket_common.h b/network/api/socket_common.h index d026d05fb..e6c1bc0f5 100644 --- a/network/api/socket_common.h +++ b/network/api/socket_common.h @@ -133,6 +133,9 @@ typedef struct socket_connection_params_t { /** @brief Hostname of the remote server. */ const char* server_hostname; + + /** @brief IP address of the remote server. If provided, bypasses DNS resolution. */ + struct in_addr* server_ip_addr; } socket_connection_params_t; /** @@ -213,10 +216,11 @@ int accept_socket(int socket); * * @param sock The socket file descriptor that has already been created (using `socket()`). * @param hostname The hostname or IP address of the server to connect to. + * @param ip_addr The IPv4 address to connect to. If non-NULL, bypasses DNS lookup of hostname. * @param port The port number to connect to. If 0 is specified, a default port range will be used. * @return 0 on success, -1 on failure, and `errno` is set to indicate the specific error. */ -int connect_to_socket(int sock, const char* hostname, int port); +int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, int port); /** * @brief Read the specified number of bytes from the specified socket into the specified buffer. diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 37240c606..242256384 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -85,7 +85,7 @@ net_abstraction_t connect_to_net(net_params_t params) { // Create the client network abstraction. create_client(net); // Connect to the target server. - if (connect_to_socket(priv->socket_descriptor, sock_params->server_hostname, priv->server_port) != 0) { + if (connect_to_socket(priv->socket_descriptor, sock_params->server_hostname, sock_params->server_ip_addr, priv->server_port) != 0) { lf_print_error("Failed to connect to socket."); return NULL; } diff --git a/network/impl/src/socket_common.c b/network/impl/src/socket_common.c index 7942472ca..ecb8c7e8d 100644 --- a/network/impl/src/socket_common.c +++ b/network/impl/src/socket_common.c @@ -214,20 +214,28 @@ int accept_socket(int socket) { return socket_id; } -int connect_to_socket(int sock, const char* hostname, int port) { +int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, int port) { struct addrinfo hints; - struct addrinfo* result; + struct addrinfo* result = NULL; int ret = -1; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; /* Allow IPv4 */ - hints.ai_socktype = SOCK_STREAM; /* Stream socket */ - hints.ai_protocol = IPPROTO_TCP; /* TCP protocol */ - hints.ai_addr = NULL; - hints.ai_next = NULL; - hints.ai_flags = AI_NUMERICSERV; /* Allow only numeric port numbers */ - uint16_t used_port = (port == 0) ? DEFAULT_PORT : (uint16_t)port; + struct sockaddr_in direct_addr; + + if (ip_addr == NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; /* Allow IPv4 */ + hints.ai_socktype = SOCK_STREAM; /* Stream socket */ + hints.ai_protocol = IPPROTO_TCP; /* TCP protocol */ + hints.ai_addr = NULL; + hints.ai_next = NULL; + hints.ai_flags = AI_NUMERICSERV; /* Allow only numeric port numbers */ + } else { + memset(&direct_addr, 0, sizeof(direct_addr)); + direct_addr.sin_family = AF_INET; + direct_addr.sin_port = htons(used_port); + direct_addr.sin_addr = *ip_addr; + } instant_t start_connect = lf_time_physical(); // while (!_lf_termination_executed) { // Not working... @@ -236,30 +244,43 @@ int connect_to_socket(int sock, const char* hostname, int port) { lf_print_error("Failed to connect with timeout: " PRINTF_TIME ". Giving up.", CONNECT_TIMEOUT); break; } - // Convert port number to string. - char str[6]; - snprintf(str, sizeof(str), "%u", used_port); + + if (ip_addr != NULL) { + // Safe to type cast specific protocols (e.g., sockaddr_in) to the generic sockaddr. + ret = connect(sock, (struct sockaddr*)&direct_addr, sizeof(direct_addr)); + } else { + // Convert port number to string. + char str[6]; + snprintf(str, sizeof(str), "%u", used_port); - // Get address structure matching hostname and hints criteria, and - // set port to the port number provided in str. There should only - // ever be one matching address structure, and we connect to that. - if (getaddrinfo(hostname, (const char*)&str, &hints, &result)) { - lf_print_error("No host matching given hostname: %s", hostname); - break; + // Get address structure matching hostname and hints criteria, and + // set port to the port number provided in str. There should only + // ever be one matching address structure, and we connect to that. + if (getaddrinfo(hostname, (const char*)&str, &hints, &result)) { + lf_print_error("No host matching given hostname: %s", hostname); + break; + } + ret = connect(sock, result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); } - ret = connect(sock, result->ai_addr, result->ai_addrlen); + if (ret < 0) { lf_sleep(CONNECT_RETRY_INTERVAL); lf_print_warning("Could not connect. Will try again every " PRINTF_TIME " nanoseconds. Connecting to port %d.\n", CONNECT_RETRY_INTERVAL, used_port); - freeaddrinfo(result); continue; } else { break; } } - freeaddrinfo(result); - lf_print_info("Connected to %s:%d.", hostname, used_port); + + if (ip_addr != NULL) { + char host_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, ip_addr, host_str, INET_ADDRSTRLEN); + lf_print_info("Connected to %s:%d.", host_str, used_port); + } else { + lf_print_info("Connected to %s:%d.", hostname, used_port); + } return ret; } From fa343e0bde5d9599f9322f94b81f3515f750c11c Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Sun, 12 Apr 2026 19:12:29 -0700 Subject: [PATCH 093/105] Formatting. --- network/impl/src/lf_socket_support.c | 3 ++- network/impl/src/socket_common.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 242256384..0e1f8c39d 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -85,7 +85,8 @@ net_abstraction_t connect_to_net(net_params_t params) { // Create the client network abstraction. create_client(net); // Connect to the target server. - if (connect_to_socket(priv->socket_descriptor, sock_params->server_hostname, sock_params->server_ip_addr, priv->server_port) != 0) { + if (connect_to_socket(priv->socket_descriptor, sock_params->server_hostname, sock_params->server_ip_addr, + priv->server_port) != 0) { lf_print_error("Failed to connect to socket."); return NULL; } diff --git a/network/impl/src/socket_common.c b/network/impl/src/socket_common.c index ecb8c7e8d..91976ac1c 100644 --- a/network/impl/src/socket_common.c +++ b/network/impl/src/socket_common.c @@ -244,7 +244,7 @@ int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, i lf_print_error("Failed to connect with timeout: " PRINTF_TIME ". Giving up.", CONNECT_TIMEOUT); break; } - + if (ip_addr != NULL) { // Safe to type cast specific protocols (e.g., sockaddr_in) to the generic sockaddr. ret = connect(sock, (struct sockaddr*)&direct_addr, sizeof(direct_addr)); @@ -263,7 +263,7 @@ int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, i ret = connect(sock, result->ai_addr, result->ai_addrlen); freeaddrinfo(result); } - + if (ret < 0) { lf_sleep(CONNECT_RETRY_INTERVAL); lf_print_warning("Could not connect. Will try again every " PRINTF_TIME " nanoseconds. Connecting to port %d.\n", From e71af80c80aaac0ca2c7f85e6d83af7330ccf00b Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 13 Apr 2026 08:50:22 -0700 Subject: [PATCH 094/105] Fixes to prevent segfault on shutting down network connections --- core/federated/federate.c | 38 +++++++++++++++++----------- network/api/net_abstraction.h | 35 +++++++++++++++++++++++-- network/impl/src/lf_socket_support.c | 9 ++++--- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index c5a94ae4e..26729ffab 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -641,11 +641,16 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { " Discarding message and closing the network connection.", env->current_tag.time - start_time, env->current_tag.microstep, intended_tag.time - start_time, intended_tag.microstep); - // Free the allocated memory before returning - _lf_done_using(message_token); - // Close network abstraction, reading any incoming data and discarding it. - shutdown_net(_fed.net_for_inbound_p2p_connections[fed_id], false); - _fed.net_for_inbound_p2p_connections[fed_id] = NULL; + // The token was freshly allocated by _lf_new_token with ref_count 0 and was never + // scheduled, so _lf_done_using would incorrectly treat it as already freed. + // Use _lf_free_token directly, which handles ref_count == 0 correctly. + _lf_free_token(message_token); +#ifdef FEDERATED_DECENTRALIZED + _lf_decrement_tag_barrier_locked(env); +#endif + // Close the connection to unblock the listener, but do not free the memory; + // lf_terminate_execution will free it after joining the listener thread. + close_net(_fed.net_for_inbound_p2p_connections[fed_id], false); LF_MUTEX_UNLOCK(&env->mutex); return -1; } else { @@ -1517,13 +1522,13 @@ static void* listen_to_rti_net(void* args) { int read_failed = read_from_net(_fed.net_to_RTI, 1, buffer); if (read_failed < 0) { lf_print_error("Connection to the RTI was closed by the RTI with an error. Considering this a soft error."); - shutdown_net(_fed.net_to_RTI, false); + close_net(_fed.net_to_RTI, false); _fed.net_to_RTI = NULL; return NULL; } else if (read_failed > 0) { // EOF received. lf_print_info("Connection to the RTI closed with an EOF."); - shutdown_net(_fed.net_to_RTI, false); + close_net(_fed.net_to_RTI, false); _fed.net_to_RTI = NULL; return NULL; } @@ -1647,11 +1652,10 @@ void lf_terminate_execution(environment_t* env) { } LF_PRINT_DEBUG("Closing incoming P2P network abstractions."); - // Close any incoming P2P network abstractions that are still open. + // Close connections to unblock any listener threads that are blocking on reads, + // but do NOT free the memory yet because listener threads hold local pointers. for (int i = 0; i < NUMBER_OF_FEDERATES; i++) { - shutdown_net(_fed.net_for_inbound_p2p_connections[i], false); - // Ignore errors. Mark the network abstraction closed. - _fed.net_for_inbound_p2p_connections[i] = NULL; + close_net(_fed.net_for_inbound_p2p_connections[i], false); } // Check for all outgoing physical connections in @@ -1659,10 +1663,6 @@ void lf_terminate_execution(environment_t* env) { // if the network abstraction ID is not NULL, the connection is still open. // Send an EOF by closing the network abstraction here. for (int i = 0; i < NUMBER_OF_FEDERATES; i++) { - - // Close outbound connections, in case they have not closed themselves. - // This will result in EOF being sent to the remote federate, except for - // abnormal termination, in which case it will just close the network abstraction. close_outbound_net(i); } @@ -1681,6 +1681,14 @@ void lf_terminate_execution(environment_t* env) { // Wait for the thread listening for messages from the RTI to close. lf_thread_join(_fed.RTI_net_listener, NULL); + // All listener threads have now exited. Safe to free network abstraction memory. + for (int i = 0; i < NUMBER_OF_FEDERATES; i++) { + free_net(_fed.net_for_inbound_p2p_connections[i]); + _fed.net_for_inbound_p2p_connections[i] = NULL; + } + free_net(_fed.net_to_RTI); + _fed.net_to_RTI = NULL; + // For abnormal termination, there is no need to free memory. if (_lf_normal_termination) { LF_PRINT_DEBUG("Freeing memory occupied by the federate."); diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index 884d6bb16..0317a6b3a 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -204,13 +204,44 @@ void write_to_net_fail_on_error(net_abstraction_t net_abs, size_t num_bytes, uns bool is_net_open(net_abstraction_t net_abs); /** - * @brief Gracefully shut down and close a network abstraction. + * @brief Close the underlying connection of a network abstraction without freeing its memory. * @ingroup Network * + * This function closes the connection (making it unusable for I/O) but leaves the + * net_abstraction_t memory allocated. This is needed when another thread may still hold + * a pointer to the same network abstraction; the socket is closed to unblock any pending + * reads, but the memory remains valid. Call free_net() to release the memory after ensuring + * no other thread holds a reference. This function is idempotent. + * + * @param net_abs The network abstraction whose connection should be closed, or NULL (no-op). + * @param read_before_closing If true, read until EOF before closing. + * @return int Returns 0 on success, -1 on failure. + */ +int close_net(net_abstraction_t net_abs, bool read_before_closing); + +/** + * @brief Free the memory associated with a network abstraction. + * @ingroup Network + * + * The connection should already have been closed via close_net() or shutdown_net(). + * Safe to call with NULL (no-op). + * + * @param net_abs The network abstraction to free, or NULL. + */ +void free_net(net_abstraction_t net_abs); + +/** + * @brief Gracefully shut down, close, and free a network abstraction. + * @ingroup Network + * + * Equivalent to calling close_net() followed by free_net(). Do not use this function + * if another thread may still be using the same net_abstraction_t pointer; use close_net() + * to unblock the other thread first, join it, and then call free_net(). + * * If read_before_closing is false, call shutdown() with SHUT_RDWR and then close(). If true, call shutdown() with * SHUT_WR, then read() until EOF and discard received bytes before closing. * - * @param net_abs The network abstraction to shut down and close. + * @param net_abs The network abstraction to shut down and close, or NULL (no-op). * @param read_before_closing If true, read until EOF before closing the network abstraction. * @return int Returns 0 on success, -1 on failure (errno will indicate the error). */ diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 76aee2308..ce22590b0 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -176,13 +176,16 @@ bool is_net_open(net_abstraction_t net_abs) { return is_socket_open(priv->socket_descriptor); } -int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { +int close_net(net_abstraction_t net_abs, bool read_before_closing) { if (net_abs == NULL) { - LF_PRINT_LOG("Socket already closed."); return 0; } socket_priv_t* priv = (socket_priv_t*)net_abs; - int ret = shutdown_socket(&priv->socket_descriptor, read_before_closing); + return shutdown_socket(&priv->socket_descriptor, read_before_closing); +} + +int shutdown_net(net_abstraction_t net_abs, bool read_before_closing) { + int ret = close_net(net_abs, read_before_closing); free_net(net_abs); return ret; } From 8a1effa1a191d5a5a3acf4f96d51856f0cfdfd0f Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 13 Apr 2026 08:53:06 -0700 Subject: [PATCH 095/105] Typos in comments --- util/initialize_from_file.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/util/initialize_from_file.h b/util/initialize_from_file.h index 595902dee..73510d571 100644 --- a/util/initialize_from_file.h +++ b/util/initialize_from_file.h @@ -47,7 +47,7 @@ extern "C" { * * To use this to initialize parameters and/or state variables of a reactor, you can do the following: * - * ```lf-c + * ```lf * main reactor MyReactor(x: double = 0.0, row_number: int = 0) { * state y: double = 0.0; * reaction(startup) {= @@ -67,7 +67,7 @@ extern "C" { * If you wish to initialize parameters or state variables of a reactor within a bank, you * can create a CSV file with one row per bank member and use the `bank_index` parameter to * select the row to read. For example: - * ```lf-c + * ```lf * reactor MyReactor(bank_index: int = 0) { * reaction(startup) {= * lf_initialize_double("params.csv", ',', self->bank_index + 1, &self->x, &self->y, NULL); @@ -79,7 +79,7 @@ extern "C" { * This way, each bank member can have a different set of parameter values. * * To use this in a Lingua Franca program, you must include the following in the target declaration: - * ```lf-c + * ```lf * target C { * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", * files: [ @@ -89,7 +89,7 @@ extern "C" { * ``` * * Then, in the reactor, you can include the header file as follows: - * ```lf-c + * ```lf * reactor MyReactor { * preamble {= * #include "initialize_from_file.h" @@ -134,7 +134,7 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * * To use this to initialize parameters and/or state variables of a reactor, you can do the following: * - * ```lf-c + * ```lf * main reactor MyReactor(x: int = 0, row_number: int = 0) { * state y: int = 0; * reaction(startup) {= @@ -154,7 +154,7 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * If you wish to initialize parameters or state variables of a reactor within a bank, you * can create a CSV file with one row per bank member and use the `bank_index` parameter to * select the row to read. For example: - * ```lf-c + * ```lf * reactor MyReactor(bank_index: int = 0) { * reaction(startup) {= * lf_initialize_int("params.csv", ',', self->bank_index + 1, &self->x, &self->y, NULL); @@ -166,7 +166,7 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * This way, each bank member can have a different set of parameter values. * * To use this in a Lingua Franca program, you must include the following in the target declaration: - * ```lf-c + * ```lf * target C { * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", * files: [ @@ -176,7 +176,7 @@ int lf_initialize_double(const char* filename, char delimiter, size_t row_number * ``` * * Then, in the reactor, you can include the header file as follows: - * ```lf-c + * ```lf * reactor MyReactor { * preamble {= * #include "initialize_from_file.h" @@ -206,7 +206,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * * This macro is meant to be called from a reaction, not directly. If you wish to call it from * somewhere other than a reaction, you can use the following function: - * ```lf-c + * ```lf * int _lf_initialize_string(const char* filename, char delimiter, size_t row_number, * struct allocation_record_t** allocations, ...); * ``` @@ -238,7 +238,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * * To use this to initialize parameters and/or state variables of a reactor, you can do the following: * - * ```lf-c + * ```lf * main reactor MyReactor(row_number: int = 0) { * state name: string = ""; * reaction(startup) {= @@ -258,7 +258,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * If you wish to initialize parameters or state variables of a reactor within a bank, you * can create a CSV file with one row per bank member and use the `bank_index` parameter to * select the row to read. For example: - * ```lf-c + * ```lf * reactor MyReactor(bank_index: int = 0) { * reaction(startup) {= * lf_initialize_string("params.csv", ',', self->bank_index + 1, &self->name, NULL); @@ -270,7 +270,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * This way, each bank member can have a different set of parameter values. * * To use this in a Lingua Franca program, you must include the following in the target declaration: - * ```lf-c + * ```lf * target C { * cmake-include: "/lib/c/reactor-c/util/initialize_from_file.cmake", * files: [ @@ -280,7 +280,7 @@ int lf_initialize_int(const char* filename, char delimiter, size_t row_number, . * ``` * * Then, in the reactor, you can include the header file as follows: - * ```lf-c + * ```lf * reactor MyReactor { * preamble {= * #include "initialize_from_file.h" From 4a38791152f774136d83cedb7531343c0c6386a2 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Mon, 13 Apr 2026 11:37:36 -0700 Subject: [PATCH 096/105] Check the presence of deadline with the value of the deadline field --- lib/schedule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/schedule.c b/lib/schedule.c index 6c4511ffc..6031fa349 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -81,8 +81,7 @@ trigger_handle_t lf_schedule_value(void* action, interval_t extra_delay, void* v */ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { reaction_t* reaction = ((self_base_t*)self)->executing_reaction; - if (lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline) && - reaction->deadline_violation_handler != NULL) { + if (reaction->deadline != NEVER && lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline)) { if (invoke_deadline_handler) { reaction->deadline_violation_handler(self); } From 8d60428f63695e9de0371c37e3d10075149b729e Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Mon, 13 Apr 2026 11:40:40 -0700 Subject: [PATCH 097/105] Apply formatter --- lib/schedule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/schedule.c b/lib/schedule.c index 6031fa349..166dc09d4 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -81,7 +81,8 @@ trigger_handle_t lf_schedule_value(void* action, interval_t extra_delay, void* v */ bool lf_check_deadline(void* self, bool invoke_deadline_handler) { reaction_t* reaction = ((self_base_t*)self)->executing_reaction; - if (reaction->deadline != NEVER && lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline)) { + if (reaction->deadline != NEVER && + lf_time_physical() > (lf_time_logical(((self_base_t*)self)->environment) + reaction->deadline)) { if (invoke_deadline_handler) { reaction->deadline_violation_handler(self); } From 1416d01f37da329f09a4726d3e6c6747942f7bc6 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 14 Apr 2026 07:43:41 -0700 Subject: [PATCH 098/105] Apply Copilot suggestions --- core/federated/federate.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 26729ffab..9c74ee2ba 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -650,7 +650,7 @@ static int handle_tagged_message(net_abstraction_t net, int fed_id) { #endif // Close the connection to unblock the listener, but do not free the memory; // lf_terminate_execution will free it after joining the listener thread. - close_net(_fed.net_for_inbound_p2p_connections[fed_id], false); + close_net(net, false); LF_MUTEX_UNLOCK(&env->mutex); return -1; } else { @@ -1513,8 +1513,8 @@ static void* listen_to_rti_net(void* args) { // Listen for messages from the federate. while (!_lf_termination_executed) { // Check whether the RTI network abstraction is still valid. - if (_fed.net_to_RTI == NULL) { - lf_print_warning("network abstraction to the RTI unexpectedly closed."); + if (_fed.net_to_RTI == NULL || !is_net_open(_fed.net_to_RTI)) { + lf_print_warning("network connection to the RTI unexpectedly closed."); return NULL; } // Read one byte to get the message type. @@ -1523,13 +1523,11 @@ static void* listen_to_rti_net(void* args) { if (read_failed < 0) { lf_print_error("Connection to the RTI was closed by the RTI with an error. Considering this a soft error."); close_net(_fed.net_to_RTI, false); - _fed.net_to_RTI = NULL; return NULL; } else if (read_failed > 0) { // EOF received. lf_print_info("Connection to the RTI closed with an EOF."); close_net(_fed.net_to_RTI, false); - _fed.net_to_RTI = NULL; return NULL; } switch (buffer[0]) { From f6b6b8a91cf6192d4d976b07baaa7d60b7bf7c85 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Tue, 14 Apr 2026 16:43:14 -0700 Subject: [PATCH 099/105] Add copilot's suggestions. --- core/federated/federate.c | 2 +- network/api/socket_common.h | 4 ++-- network/impl/src/socket_common.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 3bd383186..55233c8c4 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2010,7 +2010,7 @@ void* lf_handle_p2p_connections_from_federates(void* env_arg) { _fed.inbound_net_listeners = (lf_thread_t*)calloc(_fed.number_of_inbound_p2p_connections, sizeof(lf_thread_t)); while (received_federates < _fed.number_of_inbound_p2p_connections && !_lf_termination_executed) { if (rti_failed()) { - break; + return NULL; } // Wait for an incoming connection request. net_abstraction_t net = accept_net(_fed.server_net); diff --git a/network/api/socket_common.h b/network/api/socket_common.h index e6c1bc0f5..f48d1dbf7 100644 --- a/network/api/socket_common.h +++ b/network/api/socket_common.h @@ -135,7 +135,7 @@ typedef struct socket_connection_params_t { const char* server_hostname; /** @brief IP address of the remote server. If provided, bypasses DNS resolution. */ - struct in_addr* server_ip_addr; + const struct in_addr* server_ip_addr; } socket_connection_params_t; /** @@ -220,7 +220,7 @@ int accept_socket(int socket); * @param port The port number to connect to. If 0 is specified, a default port range will be used. * @return 0 on success, -1 on failure, and `errno` is set to indicate the specific error. */ -int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, int port); +int connect_to_socket(int sock, const char* hostname, const struct in_addr* ip_addr, int port); /** * @brief Read the specified number of bytes from the specified socket into the specified buffer. diff --git a/network/impl/src/socket_common.c b/network/impl/src/socket_common.c index 91976ac1c..b80a17d6d 100644 --- a/network/impl/src/socket_common.c +++ b/network/impl/src/socket_common.c @@ -214,7 +214,7 @@ int accept_socket(int socket) { return socket_id; } -int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, int port) { +int connect_to_socket(int sock, const char* hostname, const struct in_addr* ip_addr, int port) { struct addrinfo hints; struct addrinfo* result = NULL; int ret = -1; @@ -256,7 +256,7 @@ int connect_to_socket(int sock, const char* hostname, struct in_addr* ip_addr, i // Get address structure matching hostname and hints criteria, and // set port to the port number provided in str. There should only // ever be one matching address structure, and we connect to that. - if (getaddrinfo(hostname, (const char*)&str, &hints, &result)) { + if (getaddrinfo(hostname, str, &hints, &result)) { lf_print_error("No host matching given hostname: %s", hostname); break; } From bb0d53dabc39395fdc094dda676ac9fbb62bb789 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Tue, 14 Apr 2026 18:33:10 -0700 Subject: [PATCH 100/105] Add sleep before accept retries. --- core/federated/federate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/federated/federate.c b/core/federated/federate.c index 55233c8c4..418568474 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2016,6 +2016,7 @@ void* lf_handle_p2p_connections_from_federates(void* env_arg) { net_abstraction_t net = accept_net(_fed.server_net); if (net == NULL) { lf_print_warning("Federate failed to accept the network abstraction."); + lf_sleep(MSEC(100)); continue; } LF_PRINT_LOG("Accepted new connection from remote federate."); From a8368c305dab54c8b57e43049c6310d3afca85fd Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 15 Apr 2026 10:06:00 -0700 Subject: [PATCH 101/105] Changed to use CONNECT_RETRY_INTERVAL rather than hardwired constant --- core/federated/federate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 418568474..0f0fb6718 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2016,7 +2016,7 @@ void* lf_handle_p2p_connections_from_federates(void* env_arg) { net_abstraction_t net = accept_net(_fed.server_net); if (net == NULL) { lf_print_warning("Federate failed to accept the network abstraction."); - lf_sleep(MSEC(100)); + lf_sleep(CONNECT_RETRY_INTERVAL); continue; } LF_PRINT_LOG("Accepted new connection from remote federate."); From 0b932aa81cc0d5a09cc20f4ef763a174f973a8c2 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 17 Apr 2026 09:01:04 -0700 Subject: [PATCH 102/105] Decrement reference count of old token when template token is replaced. --- core/lf_token.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index ca729813a..f4c9907e8 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -243,15 +243,24 @@ lf_token_t* _lf_get_token(token_template_t* tmplt) { if (tmplt->token != NULL && tmplt->token->ref_count == 1) { LF_PRINT_DEBUG("_lf_get_token: Reusing template token: %p with ref_count %zu", (void*)tmplt->token, tmplt->token->ref_count); - // Free any previous value in the token. _lf_free_token_value(tmplt->token); LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); return tmplt->token; } + // The existing template token is shared (ref_count > 1) or NULL. + // Drop the template's reference to the old token and install a new one + // so that the invariant "template holds exactly one reference" is preserved. + // Without this, the old token is left with an unreleasable extra reference + // and its payload leaks on every subsequent cycle. + lf_token_t* old = tmplt->token; LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); - // If we get here, we need a new token. + lf_token_t* result = _lf_new_token((token_type_t*)tmplt, NULL, 0); result->ref_count = 1; + tmplt->token = result; + if (old != NULL) { + _lf_done_using(old); + } return result; } From d33eca805f408b4fa7abb28c94ba52a5cd2d0497 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 17 Apr 2026 10:58:20 -0700 Subject: [PATCH 103/105] Fix race condition identified by Copilot --- core/lf_token.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index f4c9907e8..cf93dcef3 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -202,10 +202,10 @@ token_freed _lf_free_token(lf_token_t* token) { return result; } -lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { +/** Implementation of _lf_new_token that is called only within a critical section. */ +static lf_token_t* _lf_new_token_locked(token_type_t* type, void* value, size_t length) { lf_token_t* result = NULL; // Check the recycling bin. - LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); if (_lf_token_recycling_bin != NULL) { hashset_itr_t iterator = hashset_iterator(_lf_token_recycling_bin); if (hashset_iterator_next(iterator) >= 0) { @@ -223,8 +223,6 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { _lf_count_token_allocations++; #endif - LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); - if (result == NULL) { // Nothing found on the recycle bin. result = (lf_token_t*)calloc(1, sizeof(lf_token_t)); @@ -238,6 +236,13 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { return result; } +lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { + LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); + lf_token_t* result = _lf_new_token_locked(type, value, length); + LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); + return result; +} + lf_token_t* _lf_get_token(token_template_t* tmplt) { LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); if (tmplt->token != NULL && tmplt->token->ref_count == 1) { @@ -253,11 +258,11 @@ lf_token_t* _lf_get_token(token_template_t* tmplt) { // Without this, the old token is left with an unreleasable extra reference // and its payload leaks on every subsequent cycle. lf_token_t* old = tmplt->token; - LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); - lf_token_t* result = _lf_new_token((token_type_t*)tmplt, NULL, 0); + lf_token_t* result = _lf_new_token_locked((token_type_t*)tmplt, NULL, 0); result->ref_count = 1; tmplt->token = result; + LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); if (old != NULL) { _lf_done_using(old); } From af10061c943e2505bb7f2f81a4b326d02acfa37d Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 17 Apr 2026 10:58:35 -0700 Subject: [PATCH 104/105] Fixed race condition exposed by previous fixes --- python/lib/pythontarget.c | 42 +++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 73fbdd971..ad4a44661 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -53,25 +53,51 @@ PyObject* py_schedule(PyObject* self, PyObject* args) { } trigger_t* trigger = action->trigger; + environment_t* env = action->parent->environment; lf_token_t* t = NULL; - // Check to see if value exists and token is not NULL - if (value && (trigger->tmplt.token != NULL)) { - // DEBUG: adjust the element_size (might not be necessary) - trigger->tmplt.token->type->element_size = sizeof(PyObject*); + LF_CRITICAL_SECTION_ENTER(env); + + // Check to see if value exists + if (value) { + // Allocate a fresh token for this schedule call rather than routing through + // _lf_initialize_token_with_value / _lf_get_token. Those paths may reuse + // or replace trigger->tmplt.token, which races with the reaction prologue + // that reads trigger->tmplt.token->value after an event pop: + // + // 1. The scheduler pops an event, sets trigger->tmplt.token = T, and + // drops T->ref_count to 1 before releasing the environment lock. + // 2. A concurrent schedule acquires the environment lock and enters + // _lf_get_token, which sees ref_count == 1 and reuses T, freeing + // its payload and overwriting it with the new value. + // 3. The pending reaction finally runs and reads the corrupted value. + // + // Allocating a fresh token that lives only on the event queue until + // _lf_pop_events installs it into the template means schedule paths + // never write to trigger->tmplt.token, so concurrent schedulers cannot + // corrupt the payload of a token about to be consumed by a reaction. trigger->tmplt.type.element_size = sizeof(PyObject*); - t = _lf_initialize_token_with_value(&trigger->tmplt, value, 1); + t = lf_new_token((void*)&trigger->tmplt, value, 1); +#if !defined NDEBUG + // Keep the payload allocation counter balanced with the decrement that + // occurs when the token's value is eventually freed. + LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); + extern int _lf_count_payload_allocations; + _lf_count_payload_allocations++; + LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); +#endif // Also give the new value back to the Python action itself Py_INCREF(value); act->value = value; } - // Pass the token along - lf_schedule_token(action, offset, t); + lf_schedule_trigger(env, trigger, offset, t); + lf_notify_of_event(env); - // FIXME: handle is not passed to the Python side + LF_CRITICAL_SECTION_EXIT(env); + // FIXME: handle is not passed to the Python side Py_INCREF(Py_None); return Py_None; } From f948a47b657621b4366d66b66ab613bd9488e542 Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Wed, 29 Apr 2026 17:22:28 -0700 Subject: [PATCH 105/105] Remove get/set on server_hostname. --- core/federated/RTI/rti_remote.c | 1 - network/api/net_abstraction.h | 22 ---------------------- network/impl/src/lf_socket_support.c | 12 ------------ network/impl/src/lf_sst_support.c | 10 ---------- network/impl/src/lf_tls_support.c | 12 ------------ 5 files changed, 57 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 71d34f8d4..e4da2012c 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -650,7 +650,6 @@ void handle_address_query(uint16_t fed_id) { // returned port number might still be -1. server_port = get_server_port(remote_fed->net); ip_address = (uint32_t*)get_ip_addr(remote_fed->net); - server_host_name = get_server_hostname(remote_fed->net); } encode_int32(server_port, (unsigned char*)&buffer[1]); diff --git a/network/api/net_abstraction.h b/network/api/net_abstraction.h index 4e34609e6..0acf78071 100644 --- a/network/api/net_abstraction.h +++ b/network/api/net_abstraction.h @@ -290,17 +290,6 @@ int32_t get_server_port(net_abstraction_t net_abs); */ struct in_addr* get_ip_addr(net_abstraction_t net_abs); -/** - * @brief Get the connected peer's hostname. - * @ingroup Network - * - * Get the hostname of the connected peer. - * - * @param net_abs The network abstraction. - * @return Pointer to the server hostname. - */ -char* get_server_hostname(net_abstraction_t net_abs); - /** * @brief Set the user-specified port for this network abstraction. * @ingroup Network @@ -326,15 +315,4 @@ void set_my_port(net_abstraction_t net_abs, int32_t port); */ void set_server_port(net_abstraction_t net_abs, int32_t port); -/** - * @brief Set the target server's port number for this network abstraction. - * @ingroup Network - * - * Set the target server's hostname to the network abstraction. - * - * @param net_abs The network abstraction. - * @param hostname The target server's hostname. - */ -void set_server_hostname(net_abstraction_t net_abs, const char* hostname); - #endif /* NET_ABSTRACTION_H */ diff --git a/network/impl/src/lf_socket_support.c b/network/impl/src/lf_socket_support.c index 8f637c994..ebd1d98cb 100644 --- a/network/impl/src/lf_socket_support.c +++ b/network/impl/src/lf_socket_support.c @@ -207,12 +207,6 @@ struct in_addr* get_ip_addr(net_abstraction_t net_abs) { return &priv->server_ip_addr; } -char* get_server_hostname(net_abstraction_t net_abs) { - LF_ASSERT_NON_NULL(net_abs); - socket_priv_t* priv = (socket_priv_t*)net_abs; - return priv->server_hostname; -} - void set_my_port(net_abstraction_t net_abs, int32_t port) { LF_ASSERT_NON_NULL(net_abs); socket_priv_t* priv = (socket_priv_t*)net_abs; @@ -224,9 +218,3 @@ void set_server_port(net_abstraction_t net_abs, int32_t port) { socket_priv_t* priv = (socket_priv_t*)net_abs; priv->server_port = port; } - -void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { - LF_ASSERT_NON_NULL(net_abs); - socket_priv_t* priv = (socket_priv_t*)net_abs; - memcpy(priv->server_hostname, hostname, INET_ADDRSTRLEN); -} diff --git a/network/impl/src/lf_sst_support.c b/network/impl/src/lf_sst_support.c index 0c70d8f2e..3d931f31a 100644 --- a/network/impl/src/lf_sst_support.c +++ b/network/impl/src/lf_sst_support.c @@ -298,11 +298,6 @@ struct in_addr* get_ip_addr(net_abstraction_t net_abs) { return &priv->socket_priv->server_ip_addr; } -char* get_server_hostname(net_abstraction_t net_abs) { - sst_priv_t* priv = (sst_priv_t*)net_abs; - return priv->socket_priv->server_hostname; -} - void set_my_port(net_abstraction_t net_abs, int32_t port) { sst_priv_t* priv = (sst_priv_t*)net_abs; priv->socket_priv->user_specified_port = port; @@ -312,8 +307,3 @@ void set_server_port(net_abstraction_t net_abs, int32_t port) { sst_priv_t* priv = (sst_priv_t*)net_abs; priv->socket_priv->server_port = port; } - -void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { - sst_priv_t* priv = (sst_priv_t*)net_abs; - memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); -} diff --git a/network/impl/src/lf_tls_support.c b/network/impl/src/lf_tls_support.c index 93f4481bc..57901b51b 100644 --- a/network/impl/src/lf_tls_support.c +++ b/network/impl/src/lf_tls_support.c @@ -371,12 +371,6 @@ struct in_addr* get_ip_addr(net_abstraction_t net_abs) { return &priv->socket_priv->server_ip_addr; } -char* get_server_hostname(net_abstraction_t net_abs) { - LF_ASSERT_NON_NULL(net_abs); - tls_priv_t* priv = (tls_priv_t*)net_abs; - return priv->socket_priv->server_hostname; -} - void set_my_port(net_abstraction_t net_abs, int32_t port) { LF_ASSERT_NON_NULL(net_abs); tls_priv_t* priv = (tls_priv_t*)net_abs; @@ -388,9 +382,3 @@ void set_server_port(net_abstraction_t net_abs, int32_t port) { tls_priv_t* priv = (tls_priv_t*)net_abs; priv->socket_priv->server_port = port; } - -void set_server_hostname(net_abstraction_t net_abs, const char* hostname) { - LF_ASSERT_NON_NULL(net_abs); - tls_priv_t* priv = (tls_priv_t*)net_abs; - memcpy(priv->socket_priv->server_hostname, hostname, INET_ADDRSTRLEN); -}