Skip navigation

Designing a public API is hard. You have to take a lot of things into account and make sure that your users (the developers) will be able to do anything their users (the clients) need or want. Nevertheless, there are some occasions where the API just gets in your way and makes the experience not as good as it should be.

In the last couple of weeks, I have been trying to add voice calls to (obligatory plug :P ) this awesome Google Talk client for Windows Phone, with limited success. To be fair, Google’s documentation is not up-to-date and just plain wrong on a couple of things (but that will be laid out in a future blog post). In that process, I found out a couple of ugly things in the Windows Phone API. Please take into account that most of this problems will only be applicable to you if you are trying to build a VoIP service, but may happen in some other projects.

Sockets & Networking

  • Socket calls are different from the full .NET framework. In order to minimize the probability of locking the UI thread, all socket calls are non-blocking. Due to Windows Phone’s Silverlight inheritance, the sockets API is not identical to .NET 4.0. Instead of using the BeginConnect/Send/Receive(AsyncCallback, Object) methods available in C#, and let the Socket object itself handle the state of the connection, you need to pass a SocketAsyncEventArgs: a class that holds the connection’s information, such as the end point (IP address and port), the read/write buffer, the callback to invoke when the call is finished, etc. This in itself is not bad (you can do everything you would expect to, only in a different way), but it complicates things with the following points.
  • There is no way of getting the local IP address(es). At most, you can get the public IP Address for the device, either using a STUN server, or a webpage like whatismyip.org. Getting the phone’s address is needed by ICE-UDP, one of the protocols that enable voice calls, so that means that a relay server will be needed to communicate two devices within the same Local Area Network.
  • You cannot set up a UDP server. Once again, this is a problem for voice calling, since ICE-UDP requires it.
  • You cannot know the ‘local’ UDP port for a UDP session. Normally, whenever you send something through UDP, you bind to an ephemeral port (usually one between 49152 and 65535). In most sockets APIs, you can either get that port’s number or bind to a specific port.

Cryptography

  • No MD5. Even though MD5 has several known vulnerabilities and should generally not be used, there are still websites that use it for authentication. Adding support for it is quite easy (there are public domain implementations throughout the web), but every application that needs it will need to include it themselves.
  • There are no SSL sockets. Despite the Phone itself can make SSL sockets (you can make a WebRequest to a https-enabled domain), this funcionality is not exposed for Sockets. There are workarounds, like the fabulous Bouncy Castle library, but that has some problems in itself: since sockets are async-only, you need to make a blocking wrapper for them (wich is not an end-of-the-world problem, but is slightly annoying). You also need to manage the root certificates and certificate revocation list yourself to be able to verify a remote certificate (which can get out of date, and then an attack similar to Sotirov, Stevens, et al of 2008 would work).
  • Lack of algorithms. Once again, this is not an end-of-the-world problem, since Bouncy Castle supports most of them, but including a ~4MB .dll in an application just to support one algorithm is a little too much.

Others

  • LINQ. Linq’s performance on the phone can be a little slow in some occasions. Also, whenever there is an exception thrown inside a LINQ block, the whole code just dies silently (the only evidence is that if you run your application with the debugger, the output window shows a  ”First chance exception” message).
  • Exceptions. There are (fortunately few) places in the API where exceptions do not work as expected. For example, whenever you try to serialize something that does not have the correct [DataContract]/[DataMember] attributes, the exception message is downright confusing. Furthermore, I ran into a case where you tried to save a isolatedstoragesettings object with a non-serializable object. It executed without any exceptions thrown, but didn’t save anything. I added some attributes to make it serializable (but didn’t do it correctly), and now it threw an exception, but saved the data that was serializable. After doing the right thing with the DataContract/Member attributes, it didn’t throw an exception, but once again, didn’t save anything. Some sockets operations will swallow exceptions as well (for example, out-of-bounds exceptions with the buffer), and only tell you that something went wrong in the callback, through one of the SocketError values. The Exception object will be lost, though.