November 16, 2009
Diagnosing a WCF CommunicationException
A small handful of the users of Logos Bible Software 4 are reporting that they can’t sign in to our server. Signing in just involves transmitting the user name and password over HTTPS so that the server can issue an authentication cookie, very much the same as if the user were to access https://www.logos.com/login in a browser, yet executing this method in the client code results in the following exception:
System.ServiceModel.CommunicationException: Could not connect to
https://services.logos.com/. TCP error code 10045: The attempted
operation is not supported for the type of object referenced.
Some quick searching reveals that “code 10045 represents WSAEOPNOTSUPP”, meaning, “The attempted operation is not supported for the type of object referenced. Usually this occurs when a socket descriptor to a socket that cannot support this operation is trying to accept a connection on a datagram socket.”
This isn’t a very helpful, especially when WCF is meant to hide all the details of the underlying sockets from the hapless application programmer who simply wants things to just work, so I did some more digging. The CommunicationException has an inner WebException, which has an inner SocketException:
System.Net.Sockets.SocketException: The attempted operation is not
supported for the type of object referenced
at System.Net.Sockets.Socket.get_ConnectEx()
at System.Net.Sockets.Socket.BeginConnectEx(EndPoint remoteEP,
Boolean flowContext, AsyncCallback callback, Object state)
at System.Net.Sockets.Socket.UnsafeBeginConnect(EndPoint remoteEP,
AsyncCallback callback, Object state)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,
Socket s4, Socket s6, Socket& socket, IPAddress& address,
ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout,
Exception& exception)
This gives the actual location of the error, which seems worth investigating. Disassembling the ConnectEx method reveals that it uses double-checked locking to initialize a static delegate named s_ConnectEx by calling WSAIoctl. If that fails, it throws a SocketException. The parameters passed to WSAIoctl reported in Reflector are GUIDs and integers, instead of symbolic identifiers, but searching the Visual C++ header files for the constants reveals that Socket is invoking the SIO_GET_EXTENSION_FUNCTION_POINTER command and asking for a function pointer to the ConnectEx function.
Now things are starting to make more sense. Winsock2 supports “layered service providers”, which allow new functionality to be added to the Winsock stack in a modular way. The SIO_GET_EXTENSION_FUNCTION_POINTER command can be used by an application to retrieve a pointer to a function that the application knows is implemented by an installed LSP. In the case of ConnectEx, the provider is the standard Microsoft Winsock2 libraries, so it should always be available. However, LSPs are chained together; presumably, if an installed LSP simply returns WSAEOPNOTSUPP because it doesn’t support the requested function, instead of passing the message to the next LSP in the chain, WSAIoctl will return WSAEOPNOTSUPP and Socket.ConnectEx will throw.
One of our users experiencing this problem reported that his Winsock catalog listing (which can be displayed by executing “netsh winsock show catalog”, or using AutoRuns) included lspcs.dll, which is an LSP for CyberSitter (an internet filtering program). When he uninstalled Cybersitter and switched to using Vista’s parental controls, Logos 4 was able to connect to our servers and sign in. It seems very likely that CyberSitter’s LSP has a bug that prevents .NET programs from accessing the ConnectEx function in the Microsoft Winsock stack. (Logos 4 is not the only program affected by this LSP.)
Posted by Bradley Grainger at 6:11 PM | Comments (0) | TrackBack
November 5, 2009
How to Crash every WPF application
Now that we’ve released Logos 4, our users are really helping us stress-test WPF. (It’s still a little remarkable that after three years, ours is the first (and only!) WPF application installed on many of our users’ systems.)
On one system, the application was crashing at startup, with the following exception:
System.TypeInitializationException: The type initializer for
'System.Windows.Media.FontFamily' threw an exception. --->
System.ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path)
at System.IO.Path.GetFileName(String path)
at MS.Internal.FontCache.FontSourceCollection.SetFontSources()
at MS.Internal.FontCache.FontSourceCollection.GetEnumerator()
at MS.Internal.FontCache.FamilyCollection.BuildFamilyList(List`1& familyList,
SortedDictionary`2& familyNameList, SortedList`2& frequentStrings)
at MS.Internal.FontCache.FamilyCollection.MS.Internal.FontCache.
IFontCacheElement.AddToCache(CheckedPointer newPointer, ElementCacher cacher)
at MS.Internal.FontCache.HashTable.Lookup(IFontCacheElement e, Boolean add)
at MS.Internal.FontCache.CacheManager.Lookup(IFontCacheElement e)
at System.Windows.Media.FontFamily.PreCreateDefaultFamilyCollection()
at System.Windows.Media.FontFamily..cctor()
We traced this to having an illegal path char in one of the fonts listed in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts registry key. To reproduce the problem, you can simply edit one of those values on your own machine and add a colon, pipe, or any other illegal path character to one of the values. Now, any WPF application on your system will crash as soon as it attempts to display its first UI.
If the user of your application discovers this issue, the only thing to do is to examine each of the Fonts registry values and correct/delete any that contain invalid characters. (Or write a program to do this for you.)
I’ve filed this as Connect issue 508419; we’ve also noted that others have encountered the same problem (and fixed it in a similar way).
Posted by Bradley Grainger at 10:24 AM | Comments (2) | TrackBack
November 2, 2009
Hiatus
If you’ve been following the company blog, you’ve probably guessed why this blog has been quiet for so long. Today (after four years of development, and two months of intense private beta testing) we released Logos Bible Software 4, the major upgrade to our flagship product. This was a ground-up rewrite in C#, WPF, and .NET 3.5 (as you can probably tell from the topics previously covered here), with a dash of C++/CLI and legacy code.
We got to play with a lot of cool new technology as we developed it (we started developing with VS2008 Beta 2, and upgraded to pre-release versions of WPF along the way) and learnt a lot, which I hope we can turn into some interesting blog topics in the next few months. And now that we’re “done”, we’re looking forward to upgrading to .NET 4.0 and targeting the new features introduced in Windows 7. (And I hope our growing Mac team might chime in with some OS X-specific posts, too.)
Meanwhile, our web team delivered major improvements to the infrastructure behind logos.com (which supports Logos 4), as well as developing the back-end for our iPhone app.
I think this is the part where I mention that we’re hiring… if you’re interested in Bible software, iPhone, WPF, web, Mac, or slaving away on a 15-year-old legacy codebase (just kidding!), we’ve got a spot on our growing teams.
Posted by Bradley Grainger at 9:59 PM | Comments (2) | TrackBack