Download sample code here (New window)
There’s been a project knocking around the back of my head for a while. I keep putting it off, doing some work on it now and again but never really settling down to really do it. This long weekend turned out to be one of those occasions; I’ve just finished playing Fallout 3 (Awesome game, the ending left a slightly bitter taste in my mouth though) and ended up with nothing to do. Visual Studio to the rescue…
Now what?
If you ever worked on an application that requires Internet connectivity, you will have had to handle situations where the connection may be unavailable for certain periods of time. Sometimes you can get by that by trapping an exception; I know I have, though I still find that particular solution to be somewhat inelegant. What I wanted was some way to monitor the state of the connection and keep track of it. This way, if you need to send a message for example, you can have your application decide whether it should try to send it right away, or whether it should stash it away till the connection becomes available. This post is about how to determine whether a connection is up or down, and notify the application when the state changes.
Doing it the managed way
There is a method in .net, NetworkInterface.GetIsNetworkAvailable(). This method will tell you whether there is a connection going out of the machine, and it seemed to be the ticket. Unfortunately (or fortunately – this would have been a really short post otherwise), in my case, it wasn’t. You see, when we’re working off a LAN, we can have local only connectivity, or low connectivity. This means that the machine can talk to the router, but cannot access the Internet at large; the method still returns true in this case. If you’re working on an intranet application, this may be ok for you, but I wanted something bigger.
Going native
My friends have a long standing joke. It goes something like, “If someone invents a piece of hardware to wipe your bottom, the Windows API probably already supports it.” (The exact quote is unsuitable for mixed company). The windows API does, indeed, grant you nearly god-like powers over your system, and nearly anything Windows can do, the API can too. Since Windows can tell when there is no connectivity to the web (the dreaded “local only” icon), I figured that PInvoke.net would be the next port of call in my search. Sure enough, wininet.dll defines a function InternetGetConnectedState…
Ouch. We still have the same issue… it doesn’t really care about the “local only” business. At least, it gives us some additional information, such as whether the connection is through a modem or a LAN.
Hackety-hack-hack time
I’m still fairly confident that there’s a direct way to get to this information, but since I just want to get this to work right now, I’ll fudge it up a bit.
Using the wininet.dll function, we can tell whether we’re connected to a modem, connected to a LAN, or not connected at all. Not connected means just that, so that’s easy. For modem connections, I’ll assume that it’s either connected to the Internet, or not connected at all (You’ll have to excuse my blatant ignorance of networking hardware. Drop me a comment if you know this is the case). This just leaves us with the LAN condition to deal with.
The machine that goes PING!
When we know we’re connected to a LAN, but not how far we can go, we have to resort to the time honoured mechanism of the PING. All hail the mighty PING.
A ping is simply a very short message that’s sent to the server. If the server accepts the ping, it just echoes it back. It’s a protocol for machines to determine if they can see each other over a network. In .net, the ping is represented by a Ping class, and returns a PingReply:
1: if (isLan)
2: {
3: PingReply reply = pingOfLife.Send(PingTarget, 3000);
4: return reply.Status == IPStatus.Success;
5: }
This sends a ping to a URL identified by the PingTarget property, and waits up to 3 seconds for a reply. The URLs for Ping don’t take a protocol specifier, so you’d use, say, www.google.com rather than http://www.google.com.
You will notice that in the sample code and the example above, we’re only assuming a successful connection if the reply to the ping is successful. This is a simplification. In reality, the ping is checking whether we can access the ping target, irrespective of whether the rest of the Internet is accessible. If the target server is down, you’ll get a “No connection” result.
When you think about it, it doesn’t matter in most cases. You only care about whether your application can reach its server, not whether it’s got access to random web pages.
What else?
This seemed to sort it out for me. You can find the entire source code in the sample project. The ConnectionState class in the sample also contains events you can hook into so your application will get notified of state changes.