Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Access Your Pocket PC Over the Internet

0.00/5 (No votes)
8 Jan 2009 1  
A DynDNS updater for the Compact Framework.

CompactDDNSplusVNC

What does it do?

DynDNS is one of many services that can associate a domain name with an IP Address. A domain name is just a user friendly alias for an IP address. In situations where the IP addresses given out by ISPs (know as the WAN IP) are not always the same (dynamic versus static), it is not possible to find the device over the Internet without knowing the latest address given to it. A DynDNS client is a software that identifies changes to a WAN IP, and re-associates a pre-determined domain name with the new IP. The domain name can then be used to find the device over the Internet. Because 3G/GPRS connections always have dynamic IPs (at least in Australia), a DynDNS type service is needed to access a device over the Internet.

*Note – Many 3G/GPRS connections also have what are called ‘Private IPs’. You will need to find a provider that will allow your SIM to have a ‘Public IP’. In Australia, Optus works with no modifications, whist Telstra will provide the service if you are prepared to spend several hours on the phone searching for someone who knows what you’re on about.

Uses

  • Use a Pocket PC as a gateway to control systems (security/irrigation/lighting etc.).
  • Use a GPS enabled Pocket PC to track a vehicle’s location at all times.
  • Use with ‘VNC’ to access employee PDAs for remote assistance.
  • Many more …

Background

I decided to post this article for several reasons. I could not find any reference to a DynDNS updater for Pocket PCs when I developed this code. The Code Project has been of tremendous use to me over the past couple of years, and I am keen to contribute something back.

Achieving the end goal involved negotiating a few hurdles I had not foreseen. I work as an engineer developing software to interface with control systems, and have spent the last few years focused on the use of Pocket PCs not only as devices to remotely access controllers, but also as the ‘brains’ in distributed control systems.

The Pocket PC offers great value for money as a control/logging device. Although it does not provide onboard I/O (many Wi-Fi I/O devices available), for around $500 AU, you get a device with:

  • Real time clock
  • Battery backup
  • Local GUI for user interaction
  • Wi-Fi and Bluetooth connectivity
  • 3G/GPRS connectivity
  • SMS alarms
  • Device designed for low power consumption
  • Rich programming environment with .NET CF

Requirements

To use CompactDDNS, you will need:

  • A DynDNS account and at least one host created
  • (Free for up to 5 hosts)
  • A Pocket PC phone with WM5 or WM6
  • (Might work with PPC2003)
  • A 3G/GPRS enabled SIM card with a ‘Public IP’
  • Visual Studio 2005 with the relevant Pocket PC SDK

Features

As well as a DynDNS updater, CompactDDNS can also edit the appropriate Registry key for your 3G/GPRS connection to keep it permanently connected.

Finally, I have included the EXE, but not the source code for my in-house VNC server for Pocket PCs. This VNC server works well, but is yet to have authentication implemented. You can choose to launch the VNC server from CompactDDNS. I am happy for the Code Project community to use this VNC server in non-commercial applications.

The Code

In developing professional applications for Pocket PCs, I make extensive use of the OpenNetCF Framework, and would recommend anyone who is serious about development using .NET CF to do likewise.

In order to post this project, I have reworked my code to not use the OpenNetCF Framework. For instance, to find the WAN IP of my SIM, I usually use the Adaptors class provided in the OpenNetCF.Net assembly. However to bypass this requirement, I have used the ‘WhatsMyIP’ web service.

If you have access to the OpenNetCF Framework, I have included an alternate ‘modMain’ that includes the creation of a notify icon. Enabling this feature will enable you to hide and then show the CompactDDNS app. To use this feature, add a reference to the OpenNetCF.Windows.Forms assembly and set the ‘ControlBox’ property of the main form to true (enabling you to hide the form).

The basic updater code first loads a configuration (including the last update info) from an XML file, then - if the updater is enabled - it retrieves the WAN IP using the ‘WhatsMyIP’ web service.

The retrieved IP is then compared with the last update IP from the settings file, and only if the IP has changed does it use the new WAN IP to update the DynDNS service. Once updated, the application periodically loops through the available IP addresses on the device to ensure that the last updated IP is still available. If the last updated IP is no longer available, the updater once again tries the ‘WhatsMyIP’ web service for the new WAN IP (if connected), and so on and so forth.

Although the code I used for doing the DynDNS update resides in the ‘PhoneLib’ project and was written in C#, I have produced the equivalent code for VB, and it can be found commented out in the ‘modGlobals’ file.

Here is the function that does the DynDNS update:

public static string UpdateDDNS(string Host, string Ip, string UserID, 
       string Password, string UserAgent) 
{ 
    string ResponseText = "Failed"; 
    System.Net.HttpWebRequest Request = null; 
    System.Net.NetworkCredential myCred = 
               new System.Net.NetworkCredential(UserID,
        Password); 
    //This sets mappings to ensure the HttpRequest 
    //uses the internet connection to update 
    SetDDNS_Prov(UserID, Password); 
    string url = "http://" + UserID + ":"+ Password + 
        "@members.dyndns.org/nic/update?hostname=" + Host + "&myip=" +
        Ip + "&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0:8245"; 
    Debug.WriteLine("url =" + url); 
    try 
    { 
        // make a Web request 
        Request = (System.Net.HttpWebRequest)
                      System.Net.HttpWebRequest.Create(url); 
        //"Open Control-Compact Watchdog-v1.0"; 
        Request.UserAgent = UserAgent;
        Request.Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy(); 
        Request.Method = "GET"; 
        Request.Credentials = myCred; 
        System.Net.HttpWebResponse HttpWResponse = (
            System.Net.HttpWebResponse) Request.GetResponse(); 
        if (HttpWResponse != null) 
        { 
            System.IO.Stream stm = HttpWResponse.GetResponseStream(); 
            System.IO.StreamReader sr = new System.IO.StreamReader(stm); 
            ResponseText = sr.ReadToEnd(); 
            stm.Close(); 
            sr.Close(); 
            Request = null; 
            HttpWResponse = null; 
            stm = null; 
            sr = null; 
        } 
    } 
    catch (Exception ex) 
    { 
        Debug.WriteLine("Update Failed - " + ex.Message); 
    } 
    return ResponseText; 
}

And, here is the function for the mapping provisions:

//Uses CM_Mappings Provisioning to force the connection manager 
//to use the internet and not the local network to update DDNS 
public static string SetDDNS_Prov(string UserID , string Password ) 
{ 
    System.Xml.XmlDocument d= new System.Xml.XmlDocument(); 
    //My Way of making strings with lots of quotes more legible 
    //by avoiding control characters for quotes(Works for VB too) 
    String provString = "<wap-provisioningdoc>"; 
    provString += "<characteristic type='CM_Mappings'>"; 
    provString += "<characteristic type='900'>";  // This needs to be less than
                                                  // 1000 (first default mapping) 
    provString += "<parm name='Pattern' value='*://" + UserID + ":" + Password +
                                                 //"@members.dyndns.org/*'/>"; 
    provString += "<parm name='Network' 
        value='{436EF144-B4FB-4863-A041-8F905A62C572}'/>"; 
    provString += "</characteristic>"; 
    provString += "</characteristic>"; 
    provString += "</wap-provisioningdoc>"; 
    provString = provString.Replace("'", Convert.ToChar(34).ToString()); 
    Debug.WriteLine("provString = " + provString); 
    d.LoadXml(provString); 
    try 
    { 
        System.Xml.XmlDocument d2 =
        Microsoft.WindowsMobile.Configuration.ConfigurationManager.ProcessConfiguration(
        d, true); 
        return d2.OuterXml; 
    } 
    catch (Exception ex) 
    { 
        Debug.WriteLine("Error caught at SetDDNS_Prov - " + ex.Message); 
    } 
    return "failed"; 
}

And the same functions in VB:

Public Function UpdateDDNS(ByRef Host As String, ByRef Ip As String, _
       ByVal UserID As String, ByVal Password As String) As String 
    Dim myCred As New Net.NetworkCredential(UserID, Password) 
    Dim url As String = "http://" & UserID & ":" & _
                        Password & "@members.dyndns.org/nic/update" & _ 
                        "?hostname=" + Host + "&myip=" + Ip + "&wildcard" & _ 
                        "=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0:8245" 
    Dim Request As Net.HttpWebRequest 
    Dim ResponseText As String = "Failed - Could not connect" 
    Try 
        'This sets mappings to ensure the HttpRequest 
        'uses the internet connection to update 
        SetDDNS_Prov(UserID, Password) 
        Request = CType(System.Net.HttpWebRequest.Create(url), _
                        System.Net.HttpWebRequest) 
        Request.UserAgent = "Open Control-Compact Watchdog-v1.0" 
        Request.Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy() 
        Request.Method = "GET" 
        Request.Credentials = myCred 
        Dim HttpWResponse As Net.HttpWebResponse = Nothing 
        Try 
            HttpWResponse = CType(Request.GetResponse(), _
                                  System.Net.HttpWebResponse) 
        Catch e As Exception 
            Debug.WriteLine("Inner Exception Caught" & _ 
                            " at UpdateDDNS" & e.Message) 
        End Try 
        If Not HttpWResponse Is Nothing Then 
            Dim strm As IO.Stream = HttpWResponse.GetResponseStream() 
            Dim sr As IO.StreamReader = New IO.StreamReader(strm) 
            ResponseText = sr.ReadToEnd() 
            strm.Close() 
            sr.Close() 
            Request = Nothing 
            HttpWResponse = Nothing 
            strm = Nothing 
            sr = Nothing 
        End If 
    Catch ex As Exception 
        OnEx(ex) 
    End Try 
    Return ResponseText 
End Function 

'Forces connection manager to use the internet for 'ddns' 
Public Sub SetDDNS_Prov(ByVal UserID As String, ByVal Password As String) 
    Dim d As System.Xml.XmlDocument = New System.Xml.XmlDocument() 
    Dim provString As String = "<wap-provisioningdoc>" 
    provString += "<characteristic type='CM_Mappings'>" 
    provString += "<characteristic type='900'>" 
    provString += "<parm name='Pattern' value='*://" & UserID & ":" &
        Password & "@members.dyndns.org/*'/>" 
    provString += "<parm name='Network' 
       value='{436EF144-B4FB-4863-A041-8F905A62C572}'/>" 
    provString += "</characteristic>" 
    provString += "</characteristic>" 
    provString += "</wap-provisioningdoc>" 
    provString = provString.Replace("'", Chr(34)) 
    Debug.WriteLine("provString = " & provString) 
    Try 
        d.LoadXml(provString) 
        Dim d2 As System.Xml.XmlDocument = _
            Microsoft.WindowsMobile.Configuration._
            ConfigurationManager.ProcessConfiguration(d, True) 
        Debug.WriteLine("d2 = " & d2.InnerXml) 
    Catch ex As Exception 
        OnEx(ex) 
    End Try

Problems Encountered

Aside from having to use Net.HttpWebRequest and Net.HttpWebResponse to implement the web service requests, the basic code to do the DynDNS update worked almost the first go.

Then, for no apparent reason, it stopped working about a week later. It took me another 24 hours to find the cause of the problem, and then another two days to find a suitable solution.

I found that because I was debugging over Wi-Fi, my Pocket PC in fact had two Internet connections: one via 3G/GPRS, and another via my ADSL Router. Because I was using the OpenNetCF libraries to report the WAN IP of my SIM, I assumed the HttpWebRequest was also taking this route.

But, what I discovered was that the HttpWebRequest had always been using my ADSL connection over WiFi for the DDNS updates, and the day it stopped working, I had my ADSL modem off.

Having discovered the cause of the problem, I set out to find a solution. I was aware that the Pocket PC has a ‘Connection Manager’ that tries to determine the best connection to use for any network request.

It seemed logical to me that if the ‘Connection Manager’ found an Internet connection via the Wi-Fi, then this is likely to be cheaper for data transfer and hence a sensible choice. What did not seem logical was that if there was no Internet connection available via Wi-Fi, why the requests were not being made via the 3G/GPRS connection.

After much Googling, I discovered that the ‘Connection Manager’ uses mapping templates to match against the requested URL to determine the most appropriate connection to use. For a reason I never quite got to the bottom of (because I found the solution), the Connection Manager always wanted to use my ‘Work Network’ for the format of the URL for the DDNS update.

After more Googling, I found that by means of ‘WAP Provisioning Files’, I could add extra mappings of higher priority that included the template for the DDS update URL. After creating these extra mappings, everything worked fine.

I don’t wish to go into WAP Provisioning in detail here, however it is worth noting that can be very useful in the customization of Pocket PCs for specific tasks.

I have spent a reasonable amount of time modifying my code to work without OpenNetCF, and so shall leave this post at this point. If there proves to be a lot of interest in this article, I’ll endeavor to do a follow up article that goes into the code in more detail (I’ll also comment my code).

Hoping you found this article useful.

History

  • 09/01/09 - Posted v. 1.0.0.
  • 10/01/09 - Changed the UserAgent parameter for the 'UpdateDDNS' function called in doDDNS_Upate to "Code Project-Compact DDNS-v1.0". I had accidently left it with my product name. I should have mentioned the user agent in the article. If you uploaded the earlier version, can you change it to the above string, or use your own in the format "Company-Product-Version'? I'll include more detail on the DynDNS code in the next article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here