This project is read-only.

HangUp delay question and suggestion

May 6, 2010 at 7:17 PM
Edited May 6, 2010 at 7:18 PM

First, thanks for the rapid response to dealing with the issues of the responses from non-Microsoft VPN servers (Debian-Linux).

This question / suggestion has no bearing on DotRas functionality, per se, but on what some might consider a minor issue, but for our application, it is a significant issue.

The UI of our app responds directly to VPN connection status change events and one in particular that our Marketing department has identified as a user hot-spot issue is the time it takes to notify the user that the VPN connection is closed after they click the button to initiate a client connection termination.  Upon examining the new code in the RasHelper.HangUp() method we find this (excerpt):

                    bool active = false;

                    do
                    {
                        active = RasHelper.Instance.IsConnectionActive(handle);

                        // Pause the calling thread to prevent unnecessary processor usage while the disconnection attempt is in progress. This will also allow
                        // for proper cleanup by the connection state machine when the connection has disconnected.
                        Thread.Sleep(1000);
                    }
                    while (active);

                    // Mark the handle as invalid to prevent it from being used elsewhere in the assembly.
                    handle.SetHandleAsInvalid();

Question 1:  Could the Thread.Sleep() parameter amount be made a caller-definable value rather than a fixed constant to allow hand tweaking the response?

Question 2:  Is there a technical reason why the thread must be put to sleep even AFTER the RasHelper.Instance.IsConnectionActive(handle) returns false?  Granted, it's only 1 second (in this case) but we wish to streamline the UIX as much as possible.  If there is no technical requirement for always waiting after the connection is confirmed inactive, could this code excerpt be replaced with something like:

                    while (RasHelper.Instance.IsConnectionActive(handle))
                    {
                        // Pause the calling thread to prevent unnecessary processor usage while the disconnection attempt is in progress. This will also allow
                        // for proper cleanup by the connection state machine when the connection has disconnected.
                        Thread.Sleep(1000);
                    }

                    // Mark the handle as invalid to prevent it from being used elsewhere in the assembly.
                    handle.SetHandleAsInvalid();

This way, the code need only wait for as long as it absolutely must before returning.

May 6, 2010 at 11:24 PM
Edited May 7, 2010 at 6:52 AM

Question 1:  Could the Thread.Sleep() parameter amount be made a caller-definable value rather than a fixed constant to allow hand tweaking the response?

The reason for the sleep being there is to allow Windows to cleanup and release all necessary resources used by RasMan, and to keep processor usage from spiking while it continuously checks whether the connection is active. According to the SDK, it should take approximately 3 seconds to terminate (see below) the connection. There is no guideline in the Windows SDK specifically how long to wait, however if I allow that value to be adjustable the caller may reduce the value which would result in a race condition between the application and RAS. Even at 1 second, there is no guarantee the port will be completely freed from use.

"A simple way to avoid these problems is to call Sleep(3000) after returning from RasHangUp; after that pause, the application can exit." - Windows SDK

Question 2:  Is there a technical reason why the thread must be put to sleep even AFTER the RasHelper.Instance.IsConnectionActive(handle) returns false?

This ties back to the response from question 1. The Windows SDK does state the application cannot terminate directly after calling HangUp to ensure the operation has enough time to complete. The sleep is only there to prevent any problems with the state machine. I had this very issue in my unit tests while I was trying to fix the issue surrounding hangup for you the other day.

"If the system prematurely terminates the state machine, the state machine can fail to properly close a port, leaving the port in an inconsistent state." - Windows SDK

If that particular problem occurs on your machine, that entire device would become unusable until the machine is restarted. Which is the lesser of two evils, waiting a second or having to reboot the machine if it fails?

Note: All Windows SDK quotes on the page come from the RasHangUp page located at http://msdn.microsoft.com/en-us/library/aa377567(VS.85).aspx

 

Edit: I just wanted to add that I could signifiantly reduce the sleep while monitoring it, but keep the 1 second pause at the end. Basically, implement your change and reduce the pause to, say, 50 ms and make it variable as you requested earlier, along with the forced Thread.Sleep(1000) after the loop has completed. I do however want the post completion pause to remain, not having that there has had disasterous consequences in the past. Any thoughts?

May 7, 2010 at 3:36 PM

I went ahead and put in my proposed change, ran through all the unit tests for each of the servers I have setup and there were no issues. An overload to RasConnection.HangUp has now been added that will allow you to adjust the interval at which polling occurs, all the way down to 0 to check continuously. Also, I modified the default interval so it's set to 50 ms down from 1000.

Let me know how it works out.

Work Item: http://dotras.codeplex.com/WorkItem/View.aspx?WorkItemId=10799

May 7, 2010 at 6:53 PM

Thanks for the quick turn-around.  The changes to RasHelper.HangUp() work perfectly.  I think that in our earlier discussions, I incorrectly thought that a connection status of closed *was* the indicator that the state machine was completely shutdown.  If I am not mistaken, I now see that they are independent occurences.  Is that correct?  If that is correct, and since the Windows SDK states we must wait, then I must also conclude that Windows generates no state-machine-is-shutdown events.  Is that correct?

 

May 7, 2010 at 7:01 PM

Yes, they are independent of each other - at least from what I've experienced they are independent of each other. I've called HangUp before in the unit tests, and even though the call returned the port was left open and I had to reboot to fix it.

I do not know anywhere that would indicate when the state machine has finished cleaning of resources, the extra second added to the end is only there to ensure it has enough time after it has completed to finish releasing the resources.