X-Developer Cross-platform development in C++, Flight Simulation


IPv6 … isn’t!

Yesterday we shipped the 1.3 update for the CRJ. It included the much-awaited remote CDU functionality, which is basically a web server running in the plugin, serving the CDU screen in HTML format via Ajax.
The webserver in the plugin is a very basic HTTP server built with boost.asio, an incredibly powerful cross-platform asynchronous network library.

Thinking progressive as I always do, I of course built the webserver with IPv6 support, and configured it to always start in dual-stack mode, that means it serves the CDU both via IPv4 and IPv6.
I thought I could relax on that basis, and not touch this code again until the IPv6 address space is full.

I was so wrong!
Reports from customers kept coming in, that they couldn't start the CRJ any more. A very helpful customer showed me a gdb stacktrace of what was wrong. Guess what: it couldn't open a listening socket on 0::0, the "any" IP address in IPv6.
No, this guy was not using Windows 98. He was using the latest and greatest Ubuntu Linux. SRSLY, WTF?! It is 2011 and Ubuntu 11.10 has IPv6 support disabled by default?
Next customer with this problem was using Windows XP. Still the most popular MS OS these days. Guess what, no IPv6 enabled by default!

After instructing those guys how to enable IPv6 on their machines, I coded a patch for the server, to fallback to IPv4 only when dual-stack is unavailable. This is released as the 1.3.1 hotfix now.

I wonder how this planet is going to make the transition to IPv6 any time soon, when about 25% of my customers just can't use it without browsing through cryptic knowledgebase articles...


snprintf is not _snprintf_s_WTF_SNAFU !

The last three days were filled up with collecting all the customer reports and preparing the first service pack for the CRJ. Luckily, no real showstopper showed up, but one thing was strange:

I was fixing the display of 25kHz spaced COM-frequencies, where the CRJ 1.0.0 software had a stupid rounding error. I implemented the fix on my Linux Notebook, and was satisfied with the result. I pushed the fix to my git repository, pulled on my Windows PC and compiled again. Starting up the CRJ I had an instant crash with the dreaded "X-Plane.exe has stopped working"-window.

What had happened? To display the value on the small RTU display, I use a well-known C99 function called "snprintf()". It is the safe counterpart of sprintf() (Stream print formatted) that takes an additional argument, the maximum number of characters to be written to the destination buffer. What is great about snprintf() is that it guarantees the output buffer is null-terminated, even if when the output is truncated. And that was precisely what I wanted: The output had to be truncated to 7 characters, 3 characters the frequency before the decimal, then the decimal point, then two digits after the decimal, then the null-terminator. If I put in the frequency as 136.375 it should be truncated so the string reads 136.37\0

Fair enough, now why was the CRJ crashing so violently on Windows? The answer is: Visual C++ doesn't have an snprintf() function. There exist the following two "equivalents": _snprintf() and sprintf_s(). The former was what I used - and guess what - the Microsoft _snprintf() does NOT guarantee the null-terminator!!1!

So the frequency on the RTU read something like 136.375!$Dg=73*+#?§ with some random garbage behind the 7th character.

snprintf() is a C99 standardized function, for god's sake! It's not a GNU extension or a Torvalds memorial function. It's flipping C99 AND C++0x!

Google for the rescue! Apparently quite a lot of people on MSDN have already stumbled over the retarded _snprintf function and there is a workaround that behaves consistent to the C99 requirements:

#ifdef _MSC_VER
#include <cstdarg>
inline int my_snprintf(char* str, size_t size, const char* format, ...)
    size_t count;
    va_list ap;
    va_start(ap, format);
    count = _vscprintf(format, ap);
    _vsnprintf_s(str, size, _TRUNCATE, format, ap);
    return count;
#define snprintf my_snprintf

Now that's a kludgy workaround that keeps the CRJ flying...


Knowledgebase for cross-platform X-Plane plugin development

Hi folks,

this is my blog about the development of X-Plane plugins, about the beauty of C++ code, about X-Plane and aviation in general.

The goal is to bundle all the advice on cross-platform development I scattered on the X-Plane.org forum in the last year.
So I will try to sum up everything you need to know to successfully build X-Plane plugins.

I will start by migrating blog entries from the X-Plane.org blog here, and then organize my various posts related to cross-platform plugin development to build some kind of knowledgebase for plugin developers.

Comments and suggestions are highly welcome.