4

I've seen several similar questions on Google, but nothing exactly matches what I'm trying to do. I'm making a lag-reducing program (for a game) that basically lowers the user's MTU when a certain process is open, and restores it when the process is closed. However, MTU is a network-adapter specific setting, and some users have multiple connected network adapters. To this end, I thought it'd be nice to have the program also detect which adapter is being used by the game, and only change the MTU on that adapter.

The game will only use one adapter at a time.

I can't hardcode in end-server-IP addresses because they change fairly frequently. It seems to be there must be a way to determine which adapter the other process is using without knowing the end IP address, but I can't seem to find it.

EDIT: Thanks to Cicada and Remco, I've solved the problem.

I used the ManagedIPHelper class that Remco linked to (ManagedIpHelper) and Cicada's comments led me to this article (Identifying active network interface)

Combining those with some (Nasty, horribly unoptimized) LINQ, I got this code snippet, which takes the process name and returns the Network Interface it's using, or null if it can't find one.

    private NetworkInterface getAdapterUsedByProcess(string pName)
    {
        Process[] candidates = Process.GetProcessesByName(pName);
        if (candidates.Length == 0)
            throw new Exception("Cannot find any running processes with the name " + pName + ".exe");

        IPAddress localAddr = null;
        using (Process p = candidates[0])
        {
            TcpTable table = ManagedIpHelper.GetExtendedTcpTable(true);
            foreach (TcpRow r in table)
                if (r.ProcessId == p.Id)
                {
                    localAddr = r.LocalEndPoint.Address;
                    break;
                }
        }

        if (localAddr == null)
            throw new Exception("No routing information for " + pName + ".exe found.");

        foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
        {
            IPInterfaceProperties ipProps = nic.GetIPProperties();
            if (ipProps.UnicastAddresses.Any(new Func<UnicastIPAddressInformation, bool>((u) => { return u.Address.ToString() == localAddr.ToString(); })))
                return nic;
        }
        return null;
    }

Testing confirms this works perfectly! Many thanks, guys!

Side notes to anyone using this snippet:

  • You'll need the ManagedIpHelper classes.
  • Your app may need to request elevation, depending on the situation.
  • Multiple running processes (think Chrome) will return an undefined result. If you're going to use this code with a multpile-process-candiate situation, I highly recommend you change using (Process p = candidates[0]) to a more specific filter, ie based on PID.
  • You may also want to impliment new exception types, so you can, for example, catch "No routing info" more cleanly, the reason being that this error is often fixed by simply waiting a bit (to let the target process open a connection) and then retrying.
Community
  • 1
  • 1
Xcelled
  • 2,084
  • 3
  • 22
  • 40
  • 2
    If you find the local endpoint used by the process then you know what adapter it is using. Can you not do that? – user703016 May 28 '12 at 20:09
  • Well, I don't control the process, so I'm not sure how to go about doing that. – Xcelled May 28 '12 at 22:11
  • 2
    Well `netstat -a` gives you the local endpoints used by processes. You then have to map the IP to the proper adapter. (Maybe there's more simple, though). – user703016 May 28 '12 at 22:12
  • How does reducing the MTU reduce the lag? You would be much better off playing with socket send/receive buffer sizes, Nagle settings, etc, for your own socket. I doubt users will take kindly to having their global NIC settings tampered with. – user207421 May 30 '12 at 00:03
  • Lowering MTU after Nagle is off increases the number of packets sent to the server, so the precieved response time is less. MTU is only set when user allows it. Also, I can't control the game's socket, so no luck there. – Xcelled May 30 '12 at 03:27

1 Answers1

2

in addition to Cicada, this must help you:

It is a C# wrapper around some c/c++ code, which gets you the list of all open connections with associated PID ( Process Id ).

http://www.timvw.be/2007/09/09/build-your-own-netstatexe-with-c/

I do believe this is the only way to go, determine the process(id) based on executable path/name and try to find the current connection of that process.

Remco
  • 1,713
  • 1
  • 13
  • 14
  • How well does this work if the process has connections on multiple subnets? – John Saunders May 29 '12 at 06:21
  • @JohnSaunders, that condition is undefined. You'd potentially receive all adapters in use, then you'd be stuck with having to pick one.... You could "narrow it down" by matching both the remote and local endpoints, but that kind of defeats the purpose of using this approach (finding the adapter **without** knowing the end IP). Fortunately, the process I'm watching only opens one connection.... – Xcelled May 29 '12 at 20:25
  • I'm not sure what you mean by "undefined". It's a perfectly valid situation, in general. If you also feel that it's valid in general, then I wish you'd update your question to indicate that in your particular case, there will never be more than one adapter. – John Saunders May 29 '12 at 21:43
  • I mean undefined as in "Which adapter you get first is not consistent". Will edit as you suggest. – Xcelled May 30 '12 at 03:22