The blog of dlaa.me

"Silence is the virtue of fools." [Why the Windows Phone 7 Emulator can sometimes take forever to access the network - and how to fix it!]

If you've used the Windows Phone 7 emulator to access the network, you might have noticed that in some environments it takes an absurdly long time for network activity to complete. For example, a single HTTP request with Internet Explorer or an HttpWebRequest from a custom Silverlight application can take upwards of 20-30 seconds to complete - even when the remote server responds immediately.

Now, a lot of you probably haven't experienced this problem and have no idea what I'm talking about - but I bet those of you who have are eager for a solution! I had to deal with this myself, and I know it makes developing a network-oriented application exceedingly frustrating...

Fortunately, there's a fix! :)

 

The Cause

I got so tired of the delays one evening, I decided to install Microsoft's Network Monitor (AKA NetMon) so I could look at what was happening at the network level. (Aside: Network Monitor is a fantastic tool for sniffing packets. Another great program (which works cross-platform) is Wireshark.) So I ran a new instance of the emulator, started the trace, and opened IE (which navigated to its default page). The problem was immediately evident from the timestamps (the left-most column below) and the nature of the traffic:

15.2837914  DNS:QueryId = 0xE7D1, QUERY (Standard query), Query  for go.microsoft.com of type Host Addr on class Internet
15.2838039  DNS:QueryId = 0xD4AE, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
15.3120594  DNS:QueryId = 0xE7D1, QUERY (Standard query), Response - Success, 64.4.11.160, 96.6.112.198
16.2787382  DNS:QueryId = 0xD4AE, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
17.2787318  DNS:QueryId = 0xD4AE, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
19.2787138  DNS:QueryId = 0xD4AE, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
23.2788677  DNS:QueryId = 0xD4AE, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
27.2923071  DNS:QueryId = 0x91B, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
28.2888689  DNS:QueryId = 0x91B, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
29.2888390  DNS:QueryId = 0x91B, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
31.2889078  DNS:QueryId = 0x91B, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
35.2889120  DNS:QueryId = 0x91B, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
39.3462453  HTTP:Request, GET /fwlink/, Query:LinkID=192163

The trace above is just a snippet; the total time taken from when IE began its navigation until the (very basic) page had completely loaded was 182 seconds, or just over three minutes!

 

Looking a little closer, we see that Windows Phone 7 (and/or the emulator) sends out two DNS queries for the IP address of the go.microsoft.com server corresponding to the IE home page URL. The IPv4 query returns immediately, but there's no response to the IPv6 query. At this point, two things are going wrong:

  1. Windows Phone 7 has received a valid IPv4 response to its DNS query and could proceed with the HTTP request. But it doesn't... Instead, it delays everything waiting for an IPv6 reply to its query - and eventually times out (presumably) after about 25 seconds. While I'm not aware of a specification that covers this scenario, it just plain seems wrong. If the network stack prefers to have an IPv6 address "on file", that's fine - but there seems to be no need to delay everything waiting for it. A better approach might be to proceed with the current transaction using the valid IPv4 address that's already been returned - then switch to the IPv6 address later on if/when it becomes available.

  2. The DNS server should reply to the IPv6 query with either a valid response or an error code - and not ignore it as though nothing happened. In this case, the DNS server happens to be my DSL modem, which I suspect knows nothing about IPv6 and is therefore unable to return a valid IPv6 address. However, that's no excuse for ignoring the IPv6 queries - according to my reading of RFC1035, it should respond to these queries with a "Format error" response code (or similar). If it did, Windows Phone 7 would presumably process the failure and move on with its life instead of hanging around waiting for a reply that never shows up...

 

This trace also explains why some people experience the slowness and others don't - if the IPv6 query gets a reply (instead of timing out), the network transaction proceeds immediately. So if you're fortunate enough to have a well-mannered DNS server (as I am at work), you'll be fine. But if you're unfortunate enough to have a poorly-mannered DNS server (as I am at home), you'll be spending a lot of time twiddling your thumbs waiting for the network...

 

The Fix

Fortunately, there's an easy fix: get a better DNS server! :) Either reconfigure your (or your company's) DNS server, upgrade its firmware, or flat-out replace the darn thing and you'll be set. Unfortunately, most people don't have a lot of control over the networking hardware/configuration they're using - or maybe they're just not eager to mess with this stuff. No problem - there's another fix: swap out the DNS server your computer is using for one that works better!

But where can you find a better DNS server? As it happens, there are a number of free DNS options already out there, just waiting to be utilized! The most well-known might be OpenDNS, but there are others like Google Public DNS, etc.. In my experience, OpenDNS and Google Public DNS both handle the IPV6 DNS request immediately - just like we want. So all you need to do is point your computer to one of these DNS servers, and things should work better!

 

The Details

By default, most home computers get their DNS server address via DHCP from their router or modem. So you could change the DNS server address in the router/modem configuration and that ought to work fine. However, you might not have access/permission for that - and besides it would affect everything else on the network. Unless you're a network administrator, this path may be more trouble than it's worth...

The good news is there's an easy way to change the DNS settings for a computer's network connection within Windows - and it's even easier to automate! To make this change in the UI, open the Network and Sharing Center (either via the Start Menu or the Control Panel or right-clicking the network icon in the system tray), click on the active network adapter (typically "Local Area Connection" or "Wireless Network Connection", click the Properties button in the lower left of the dialog, click the "Internet Protocol Version 4 (TCP/IPv4)" item, click the Properties button below it, select the "Use the following DNS server addresses", type the IP addresses of the "Preferred DNS server" and "Alternate DNS server", and hit OK/Close a bunch of times. To undo the change, repeat those steps, but choose "Obtain DNS server automatically" instead at the last step.

Step 0 Step 1 Step 2 Step 3

 

Okay, the UI approach may be pretty, but it's hardly efficient. :) If you're going to do this more than a couple of times, you may want use (or customize) one of one of the following scripts I've written based on the Windows netsh utility and the IP addresses from the corresponding Wikipedia entries (please don't forget to change the adapter name if you're using a wireless connection):

D:\T>type DNS-OpenDNS.cmd
@echo off
netsh interface ipv4 add dnsservers "Local Area Connection" 208.67.222.222 index=1
netsh interface ipv4 add dnsservers "Local Area Connection" 208.67.220.220 index=2
netsh interface ipv4 show dnsservers

D:\T>type DNS-GooglePublicDNS.cmd
@echo off
netsh interface ipv4 add dnsservers "Local Area Connection" 8.8.8.8 index=1
netsh interface ipv4 add dnsservers "Local Area Connection" 8.8.4.4 index=2
netsh interface ipv4 show dnsservers

D:\T>type DNS-Default.cmd
@echo off
netsh interface ipv4 delete dnsservers "Local Area Connection" all
netsh interface ipv4 show dnsservers

D:\T>

To run one of these scripts, open a Command Prompt with administrative privileges (right-click "Command Prompt" on the Start Menu and pick "Run as administrator") and run the appropriate script. It'll tell you a bit about what it has done and the changes will take effect immediately (i.e., there's no need to reboot). (For what it's worth, the underlying configuration changes made by the two methods I've discussed should be exactly the same, so you could even use the command-line to enable a custom DNS and then use the UI to disable it!)

Personally, I tend to make this switch just before I start working with the Windows Phone emulator - and then switch back to the default configuration when I'm done. Theoretically, I could run my development machine with a custom DNS all the time, but then it wouldn't be configured the same as the rest of the household and I worry that could trip me up some day long after I've forgotten about any of this. But personal issues aside, I encourage people to switch as often or rarely as they'd like. :)

 

The Benefits

Returning to the IE home page example from earlier, let's take a new trace after configuring a custom DNS:

2.7696164  DNS:QueryId = 0x4E64, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
2.8465201  DNS:QueryId = 0x4E64, QUERY (Standard query), Response - Success,
2.8590985  DNS:QueryId = 0xE75, QUERY (Standard query), Query  for go.microsoft.com of type Host Addr on class Internet
2.8678965  DNS:QueryId = 0x64D2, QUERY (Standard query), Query  for go.microsoft.com of type AAAA on class Internet
2.9341095  DNS:QueryId = 0xE75, QUERY (Standard query), Response - Success, 54, 0
2.9441158  DNS:QueryId = 0x64D2, QUERY (Standard query), Response - Success,
3.0086106  HTTP:Request, GET /fwlink/, Query:LinkID=192163

Yup, that's looking much better! To be fair, it's not clear to me why there's a duplicate query for the IPv6 address, but even with three queries (vs. two), it still manages to get the initial HTTP request sent in less than a quarter of a second. Stepping back and looking at the time taken by the entire transaction, it now completes in just under 5 seconds - less than 3% of the original time!

 

With a custom DNS in place, my frustration developing network applications for Windows Phone 7 went away and I was able to spend my time coding instead of waiting. I'm guessing the underlying DNS server problem that causes these long delays isn't super pervasive (or else they would have fixed the Windows Phone 7 emulator and/or Windows Phone OS by now), but I've also got to imagine I'm not the only one who's affected by this problem. So if you've ever wondered what in the world is taking so long, maybe your DNS server is the problem - and now you know how to fix it! :)