RASConnection constructor accepting RASHandle as parameter

May 6, 2010 at 5:59 PM
Edited May 6, 2010 at 6:16 PM

Hi there,

Thanks for providing this library, it has saved me a lot of time and hassle.

I was wondering why the constructor for RASConnection didnt take the RASHandle parameter returned by the Dialer.dial function?

Is the only way to get a connection object, to iterate through the collection returned by the RASDialer.GetActiveConnections() function?  testing each EntryName field against the one you used to dial the connection?

Or am I missing something?

Thanks,

Steve.

 

Coordinator
May 6, 2010 at 10:54 PM
Edited May 7, 2010 at 1:09 AM

The constructor for RasConnection is internal because outside sources literally cannot create a connection, only Windows can do that. The 1.1 SDK can only iterate through the list of active connections to find which connection you're looking for. How you search for that connection is up to you. The Windows SDK only exposes 1 API call for retrieval of active connections. The 1.2 SDK under development will be adding some additional methods to assist with locating connections. All they'll be doing internally is calling the GetActiveConnections method, and then iterating through the collection to find the connection you're looking for rather than making you do it.

As to why it wasn't made available from the start, I just didn't think of adding the feature.

Edit: I wanted to add, I have tried returning a RasConnection instance from the Dial and DialAsync methods but Windows doesn't recognize the connection until it has fully connected so the RasEnumConnections API didn't return it in the list.

May 7, 2010 at 5:02 PM
Edited May 7, 2010 at 5:22 PM

Hi Jeff,

Thanks for your comments.
1) I just thought that if the dial function is returning a handle to the connection that has just been dialed, it should have been possible to directly access that connection via the handle. But i guess that's not how windows works.
2) I tried to find the connection by iterating through the active connections and comparing against the handle returned by the dial function as you suggest, but a match did not occur. However the connection has been made and there is a match when i search for the connection by name. Why do you think that there is not a handle match?
3) I am assuming the difference between the synchronous and asynchronous dial functions is that execution waits for the synchronous function to finish before continuing execution of further statements, is this correct?
4) When using the synchronous dial function, the progress events are not fired / handled, is this expected? How does one ascertain whether or not dialing was successful under this circumstance?
Thanks and best wishes,
Steve.
(I would like to use the handle returned by the dial function to identify the connection i have just dialed if possible, as this seems to me the best (and least error prone)way of doing it. But I can use the connection name if there is some kind of inherent problem with this approach.)
Coordinator
May 7, 2010 at 5:46 PM
Edited May 7, 2010 at 5:58 PM

1) I just thought that if the dial function is returning a handle to the connection that has just been dialed, it should have been possible to directly access that connection via the handle. But i guess that's not how windows works

I could have allowed that, however that would mean you could create a RasConnection object by passing your own RasHandle instance to it, which RasHandle can be created by simply passing an IntPtr to the RasHandle constructor. When that handle is then passed to Windows, there is no telling what consequences would ensue (I wouldn't want to run that test on my own machines). I'd have to do tests to validate whether the handle you're trying to use is valid. In this scenario I feel the risk of exposing this piece of the API outweighs the reward. I don't want to expose any unnecessary risks to the operating system from malicious developers that may get their hands on this library.

2) I tried to find the connection by iterating through the active connections and comparing against the handle returned by the dial function as you suggest, but a match did not occur. However the connection has been made and there is a match when i search for the connection by name. Why do you think that there is not a handle match?
 
I myself thought this would have been possible until I attempted to do it yesterday after your question came up. Since the SafeHandle class that wraps the native IntPtr to the connection is a reference type, the equality test would need to verify the instances of RasHandle are the same instance, which they are not. Inside DotRas, when you call GetActiveConnections it makes a new instance of the RasHandle class, which causes it to differ from the one returned when Dial or DialAsync is called. If you want to test connections based on their handle, you can call the DangerousGetHandle and test the equality of the IntPtr structures directly. 
RasHandle handle = dialer.Dial();

foreach (RasConnection connection in GetActiveConnections())
{
    if (connection.Handle.DangerousGetHandle() == handle.DangerousGetHandle())
    {
        // This will find your handle.
    }
}
Granted, accessing the handle directly is considered dangerous since you're working with the native pointer but in this instance if you're just testing for equality I wouldn't worry about the security implications. I'll see what I can do about making this piece of the API easier to work with for the next version of DotRas. I assumed Microsoft took care of overriding the operators to allow testing handle against handle, but alas they did not. This should suffice if you're using the 1.1 SDK until I can get something more developer friendly in place.
 
3) I am assuming the difference between the synchronous and asynchronous dial functions is that execution waits for the synchronous function to finish before continuing execution of further statements, is this correct?
 
That is correct. Dial simply locks the calling thread until the call has been completed, and DialAsync will allow your application to continue working while the connection attempt is underway. Using the DialAsync call does have some advantages...
  1. You can use the StateChanged event to receive notifications from the component as the connection state changes.
  2. You can use the DialCompleted event to determine the outcome of the connection attempt.
  3. You will be able to make use of the DialAsyncCancel method to terminate the connection while it is in progress.

If you have any kind of user interface, I would suggest making use of DialAsync to prevent the UI thread from being locked and causing your app to hang until the call completes.

4) When using the synchronous dial function, the progress events are not fired / handled, is this expected? How does one ascertain whether or not dialing was successful under this circumstance?
 
Yes that is expected. The way it works internally is the Dial method will return a handle if the connection was successful and if for any reason the connection did not succeed, Windows returns an error code which is then thrown back to the caller wrapped nicely in a RasException. The ErrorCode and ErrorMessage properties on the object will indicate what happened in Windows. If you wish to make use of the events on RasDialer, you will need to use the asynchronous DialAsync call. It works this way because Windows reports state information back to the component which is then sent to your application via the StateChanged event. Once the connection attempt has finished, then the DialCompleted event is raised.
 
Hopefully that answers the questions
 
Edit: Just had to make some formatting changes. Also, I thought it might be nice to add the RasDialer component implements the event-based asynchronous design pattern (http://msdn.microsoft.com/en-us/library/ms228974.aspx). Fancy!
Sep 20, 2010 at 10:00 AM

Sorry for resurrecting this thread, but I strumbled upon your statement:

"I don't want to expose any unnecessary risks to the operating system from malicious developers that may get their hands on this library."

That is something I can't leave uncommented. Firstly, Windows won't be corrupted by invalid handles, if something gets corrupted it is the calling application. Windows internally is using handle tables and knows exactly which handle is valid and which is not. Second you will need admin rights to corrupt windows at all (if there isn't any critical bug in it but this is something that microsoft has to take care of). And third, a "malicious" developer surely won't need your library to damage a windows system, and if he does, he won't be able to do much at all ;). The only thing I would be bothered with is that passing an invalid handle in your case could do something with a connection, the wrong connection. This may cause damage is some other senses, like your phone bill ;). But it is not your responsibility to protect developers from such mistakes and fact is, you can't! You are just decreasing the power of your library with such things in mind...

A solution would be to call this method "XxxUnsafe" and I guess any real NET developer knows that a method requiring an IntPtr as parameter is far away from being a safe call :).

Just my two words about it...

Thanks for your library...

Coordinator
Sep 20, 2010 at 2:37 PM

The whole reason for this thread was from the lack of GetActiveConnectionsXXX methods on the RasConnection class. Also, back when this thread was written there was no equality testing on the RasHandle class, so it was being done as the original poster said by checking the connection name and path. Since equality testing has been added to the RasHandle class, and the RasConnection.GetActiveConnectionByHandle method has been added, there truely is no reason to expose the constructor. You cannot initiate a new connection by calling the constructor on RasConnection, so the constructor is internal.

var conn = from c in RasConnection.GetActiveConnections()
    where c.Handle = handle
    select c;

This would work if you use Linq, or you can simply call RasConnection.GetActiveConnectionByHandle(handle) and pass in the handle returned from Dial or DialAsync methods on the RasDialer component. Internally it does the same thing as the above statement, it's only there to reduce the amount of code everyone has to write.

About my previous statement, yes I know all of that... and they could always use reflection to do it manually if they so choose. But as I said earlier, the constructor won't be exposed.