nasa / trick

Trick Simulation Environment. Trick provides a common set of simulation capabilities and utilities to build simulations automatically.
Other
34 stars 19 forks source link

Trick Sim Control Panel not functional if host name does not resolve to IP address in computer. #1677

Closed dandexter closed 5 months ago

dandexter commented 6 months ago

For more than a year this bug has prevented me from being able to work onsite because of how Trick treats hosts names and does not validate the IP address it resolves to. There is no workaround to this problem (i.e. by disabling the control panel) because I need the sim control panel to manually mode the simulations between run and freeze.

This is having a big impact on my ability to work. Please fix as soon as possible.

The issue is that Trick does not validate the IP address that a host name resolves to. I have noticed at hotels, conference centers as well as onsite the IP address assigned to a host name does not correspond to any IP address assigned to any of the network adapters in the computer. This is not a DNS problem and this is being done on purpose. The host name resolves to a public IP address but all the host network adapters have private IP addresses for the case of hotels and conference centers.

It is not clear if the issue is with the variable server, Sim Control Panel, or both.

Proposed fix:

  1. Verify the IP address the host name resolves to by enumerating the network adapters in the computer and verifying an IP address match.
  2. If there is no match between the host name resolved IP address and network adapters then default to using 'localhost' for the host name.

Here is some Java code I wrote that does work that shows how to verify the host name and defaults to 'localhost' if the host not does not resolve to an IP address assigned to a network adapter..

// The hostname of this computer is valid if we can map the IP address this
// hostname resolves to from DNS to an IP address of a network interface
// adapter in this computer. If there is not a match then use "localhost"
// for the hostname.
//
// Dan Dexter/NASA JSC ER6
//
import java.io.*;
import java.net.*;
import java.util.*;

public class JavaHostname {

   public static void main(String args[]) throws SocketException {
      String validHostname = getValidLocalHostname();
      System.out.println("Valid hostname:" + validHostname);
   }

   // Returns either the real hostname of this computer if the name resolves
   // by DNS to an IP address that matches a real network interface. Otherwise,
   // return "localhost" as the name.
   // Dan Dexter/NASA JSC ER6
   static String getValidLocalHostname() {
      try {
         InetAddress hostInetAddress = InetAddress.getLocalHost();
         String hostname = hostInetAddress.getHostName();
         String hostAddress = hostInetAddress.getHostAddress();

         // Search all the network interfaces for a match to our host address.
         Enumeration<NetworkInterface> netAdapters = NetworkInterface.getNetworkInterfaces();
         for (NetworkInterface netintf : Collections.list(netAdapters)) {

            // Searce all the addresses associated with this interface.
            Enumeration<InetAddress> inetAddresses = netintf.getInetAddresses();
            for (InetAddress inetAddress : Collections.list(inetAddresses)) {
               // The local hostname is valid if we can match the host IP address
               // resolved through DNS to an IP address of a local network interface
               // adapter in this computer.
               if (hostAddress.equals( inetAddress.getHostAddress() )) {
                  return hostname;
               }
            }
         }
      } catch (SocketException e) {
         System.out.println("getValidLocalHostname() SocketException:" + e);
      } catch (UnknownHostException e) {
         System.out.println("getValidLocalHostname() UnknownHostException:" + e);
      }
      return "localhost";
   }
}

NOTE: Updated the IP address compare to use the 'equals()' function. Dexter 3/27/2024

hchen99 commented 6 months ago

Just to verify as not sure how to reproduce the problem (I might have missed what you described and assuming your input file is set to launch sim control panel automatically):

When sim control panel is automatically launched as specified in the input file, the connection host name is set to the host name of the variable server by default. The host also can be set to a different name in the input file, for instance: simControlPanel = trick.SimControlPanel() simControlPanel.set_host("localhost") trick.add_external_application(simControlPanel)

Trying to understand the reason for "there is no workaround to this problem" to help to identify the real issue here so we can make a proper update.

dandexter commented 6 months ago

I have not tried this but maybe you can replicate the issue by editing your computers hosts file to add an IP address like 10.10.10.10 for your host name.

Here is why there are no workarounds that will get the sim-control panel to work on my computer:

  1. I have tried to run the sim-control standalone using the trick-simcontrol command and then trying to connect to a running simulation. The issue is that the simulation is not seen by sim-control as if the server socket for the variable server is not running. I have also set the port number for the variable server in the input file by using trick.var_server_set_port( 7000 ), to make it easier to specify the simulation running at localhost:7000 but that does not work either.
  2. When I use the sim-control that gets opened by the simulation by setting trick.sim_control_panel_set_enabled(True) in the input file, I see the sim-control window get created but none of the GUI controls work as it appears frozen. It is almost like the sim-control is blocked trying to connect to the variable server and it is never connects and the GUI is locked up.
  3. I tried the code you suggested below, I see it try to open Two sim-control panels as I see the window icon's in the tool tray but there is no Window is visible for either. If I hit Control-C on the simulation then both sim-control panel windows finally open. Maybe this particular issue is related to the Apple Silicone Macs even though I'm an Intel Mac.
    simControlPanel = trick.SimControlPanel()
    simControlPanel.set_host( "localhost" )
    trick.add_external_application( simControlPanel )

    Console Output:

    % ./S_main_Darwin_22.exe RUN_a_side_mpr/input.py 
    /Users/ddexter/projects/Trick/trick/bin/trick-simcontrol   wasp 51952 &
    /Users/ddexter/projects/Trick/trick/bin/trick-simcontrol   localhost 51952 &
    This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener)
    This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener)
    ^CProcess terminated by signal SIGSEGV
    java.lang.NullPointerException: Cannot invoke "String.split(String)" because the return value of "trick.common.utils.VariableServerConnection.get()" is null
    java.lang.NullPointerException: Cannot invoke "String.split(String)" because the return value of "trick.common.utils.VariableServerConnection.get()" is null
    ddexter@wasp SIM_sine %     at trick.simcontrol.SimControlApplication.getInitializationPacket(SimControlApplication.java:447)
    at trick.simcontrol.SimControlApplication.initialize(SimControlApplication.java:579)
    at trick.simcontrol.SimControlApplication.getInitializationPacket(SimControlApplication.java:447)
    at org.jdesktop.application.Application$1.run(Application.java:186)
    at trick.simcontrol.SimControlApplication.initialize(SimControlApplication.java:579)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at org.jdesktop.application.Application$1.run(Application.java:186)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

    Here is more information about my computer and the issue:

  4. Intel Mac (MacBook Pro)
  5. macOS 13.6.6
  6. Xcode 15.2
  7. openjdk 21.0.2 2024-01-16
  8. The issue seems to happen when the hostname resolves to an IP address that does not correspond to any IP address to network adaptors in my computer.
  9. As of the past week of updating Trick, I'm now having problems with the sim-control window not working regardless of how the hostname resolves. See the summary of using the code you recommended in item 3 above.
hchen99 commented 6 months ago

Really appreciate all the info. We'll look through the details and keep working on a solution

dandexter commented 6 months ago

With the "python3 GIL locking solution" fix merged into master, the sim-control window now displays properly again for me. However, I still have the issue of the sim-control not working if the host name resolves to an IP address that is not assigned to a network adapter in my computer.

The good news is that I have verified that you can recreate the problem by adding a line to your /etc/hosts file with an invalid IP address for your hostname. Just edit your /etc/hosts file and add an IP address of 10.10.10.10 for your host name. For example below, replace YourHostname with the name of your computer. You may need to temporarily comment out additional entries for your hostname if they exist.

% cat /etc/hosts

127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost
10.10.10.10 YourHostname

With the sim-control now displaying with the latest python 3 GIL fix, I tried using the following code in my input file with mixed results.

simControlPanel = trick.SimControlPanel()
simControlPanel.set_host( "localhost" )
trick.add_external_application( simControlPanel )
  1. This tries to open two sim-controls, one using my host name and the other on localhost.
  2. The sim-control opened to 'localhost' appears to be working even when the host IP address is invalid.
  3. The sim-control opened to my host name does not display the sim-control Window but I do get an icon for it on the toolbar when the host IP address is invalid. I do have to kill the sim-control process manually to make that instance go away.
  4. The sim-control should detect the invalid IP address for the host and use localhost instead. The Java code I provided at the top of the issue should solve this problem provided it does not also affect the variable server. Please note I updated the code to use the euqls() function to compare the strings. I tested this both with and without a valid host IP address and the Java code works as expected.
hchen99 commented 6 months ago

Thanks for the additional info., Dan! We watched Sean did the way you suggested to recreate the problem on a Linux box and did see the the sim control coming up with delay & error. Sean was able to manually substitute the hostname with localhost and reconnect, and also he was able to start another sim control panel by providing localhost with port number without error.

We discussed one way is to add "localhost : xxx" to the "Host : Port" drop down if can't connect with message saying something like try localhost. The user might try to use sim control panel to connect a sim running on a different machine and accidentally provide a wrong hostname, so auto connecting to localhost might not what the user wants.

Btw, if you have both add external application for sim control panel and set sim control panel enabled in your input file as following, you'll see 2 sim control panels:

sharmeye commented 6 months ago

@dandexter We've got a branch with a control panel fix that we need to do some HIL testing with before we merge. If you'd like to be a guinea pig for this, the PR is linked to this issue.

dandexter commented 6 months ago

Yes, I would like to test any fix you come up with.

I still believe the underlying issue is that the host name of the local computer is being used to connect to a local simulation instead of just using localhost. It seems there are two options to fixing this issue:

sharmeye commented 5 months ago

We don't think that automatically trying localhost when a connection fails is necessarily the behavior we want. We like this solution, which indicates to the user that there is a problem with their network configuration. It also allows them (and with prompting) the option to manually connect to localhost by ensuring it is in the available sim list in the dropdown menu at the bottom of the sim control panel.