Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Create network driver. #508

Draft
wants to merge 168 commits into
base: main
Choose a base branch
from
Draft

Draft: Create network driver. #508

wants to merge 168 commits into from

Conversation

Jakio815
Copy link
Collaborator

@Jakio815 Jakio815 commented Jan 15, 2025

lf-lang/lingua-franca#2455

Summary

This PR adds a network interface layer to support interoperability in terms of network protocols, and security, using the netdrv.

The original code is very tied up with sockets, making it hard to add different network features.
However, I clarify that this PR does not remove all socket related functions out of the main flow from the RTI and federate, for two reasons.

  1. The RTI and federate support user-specified port numbers and also IP addresses for the federate.
  2. The MSG_TYPE_ADDRESS_ADVERTISEMENT and MSG_TYPE_ADDRESS_QUERY uses the port and IP address in the protocol itself.

We can completely take these socket-related stuff using #ifdef COMM_TYPE_TCP; however, I highlight that this PR is more concentrated on supporting end-to-end pluggable network security based on TCP. Thus, in this PR, I have not added the #ifdef guards, and have not changed the protocol for MSG_TYPE_ADDRESS_ADVERTISEMENT and MSG_TYPE_ADDRESS_QUERY.

Features

Plugin API for network

This PR creates a separate-compiled library on the network instead of a part of the core runtime.
I followed the prior work on low_level_platform.h and platform.h.
All source files related to network is moved under network/impl/src, and all headers are under network/api. Also there are separate CMakelists.txt for each.

Add COMM_TYPE target property.

The comm-type keyword is available in the C target as follows.

target C {
  comm-type: TCP
}

Currently only supports TCP, and plan to support SST for security.

Refactoring on clock-synchronization.

There is no other reason to do clock synchronization besides UDP. So, I left all clock-sync functions to directly use UDP sockets, and refactored these functions.

rti_remote.c

  • send_physical_clock()andhandle_physical_clock_sync_message(): Uses boolean flaguse_UDP` when UDP socket used.

clock-sync.c

  • handle_T4_clock_sync_message() : Uses boolean flag use_UDP when UDP socket used.
  • handle_T1_clock_sync_message(): Use void* socket_or_netdrv as parameter to support both socket and network driver.

handle_address_ad() and handle_address_query()

There are no changes in the protocol.

As explained in the summary, MSG_TYPE_ADDRESS_ADVERTISEMENT and MSG_TYPE_ADDRESS_QUERY uses port numbers and IP addresses in the protocol itself. To explain further, for physical connections or decentralized coordination, the federateA has to know the peer federateB's port number and IP address to directly connect to it. This is done by federateA sending a MSG_TYPE_ADDRESS_ADVERTISEMENT to the RTI it's port, and the RTI sends a MSG_TYPE_ADDRESS_QUERY_REPLY message to the peer federateB, including the port number and IP address. Thus, the port number and IP address itself cannot be encapsulated under the network driver layer, as it is included in the protocol.

Therefore, there are some get() and set() calls to the network interface.

  1. FedA - > RTI: MSG_TYPE_ADDRESS_ADVERTISEMENT: FedA calls get_my_port() to send its own port to the RTI.
  2. FedB -> RTI: MSG_TYPE_ADDRESS_QUERY : No changes.
  3. RTI -> FedB: MSG_TYPE_ADDRESS_QUERY_REPLY : RTI calls get_server_port() and get_ip_addr() to encode it to the message to send to FedB.
  4. FedB: Sets the received port and IP address by set_server_port() and set_server_host_name() to directly connect to FedA.

Minor logic change: Move getpeername() logic to accept_netdrv()

The RTI should know the connected federate(FedA)'s IP address, to pass the IP address to the other federate(FedB), as explained above.

Before, this was done in rti_remote.c's receive_and_check_fed_id_message(). I moved this to lf_socket_support.c's accept_netdrv(), because it looks more appropriate to set the connected peer's information inside this function.

One inefficiency that happens is that in decentralized coordination, the server federate does not need to save the connected peer federate's IP address. However, I think this will barely affect the performance.

Add default UDP port number as 15061.

The UDP port was usually set to the RTI's port + 1, in rti_remote.c's create_server() function call. However, I did not want to expose the port number in the create_server() interface, so I took the parameter port out from create_server().

Minor changes

  • The start_rti_server() function does not get the port as a parameter. The port will be saved in rti_remote_t;s user_specified_port, with a default value when not set up.

@Jakio815 Jakio815 changed the base branch from main to shutdown January 15, 2025 17:32
Comment on lines +109 to 112
/** The desired port specified by the user on the command line.
* This should be not moved to the net_driver, because the user can configure this as -p or --port.
*/
uint16_t user_specified_port;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check minor changes section in PR description for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant