Wandering Thoughts archives

2010-02-24

How to listen on a socket in the modern IPv6-enabled world

Suppose that you are a fancy modern server program, and you want to listen for both IPv4 and (if available) IPv6 connections. As it happens this is a bit more intricate than you might expect, and it varies between systems.

To start with:

  • use getaddrinfo() with a NULL host, the port you want, AF_UNSPEC as the address family, and AI_PASSIVE and AI_ADDRCONFIG in the flags.

  • if the results don't contain any IPv6 sockets, you have an IPv4 only system. You can skip the rest of this and just create and bind an IPv4 socket. (You probably want to set SO_REUSEADDR on the newly created socket; pretty much everyone does this.)

Otherwise, you have a choice of two options, because you are on a system that seems to support both IPv4 and IPv6. You either need to create two listening sockets, one for IPv4 only and one for IPv6 only, or you need to create an IPv6 listening socket that is also guaranteed to get IPv4 traffic. Simply binding an IPv6 socket is not enough to insure that you get IPv4 traffic; many systems do not default to dual binding sockets.

(Since there are systems that don't support dual binding sockets under any circumstances, such as OpenBSD, using two separate sockets is more portable.)

To be able to create separate IPv6 and IPv4 sockets, you need to explicitly turn on the IPV6_V6ONLY socket option on your IPv6 socket before you attempt to bind it to the wildcard listening address. To create an IPv6 socket that will also get IPv4 connections, you need to explicitly turn off IPV6_V6ONLY on your IPv6 socket, probably before you bind() it to the listening address.

(I believe but cannot completely confirm that all current IPv6 enabled Unix systems have IPV6_V6ONLY; certainly Linux, OpenBSD, NetBSD, FreeBSD, Mac OS X, AIX, and Solaris 10 all do, although OpenBSD doesn't let you turn it off. Solaris 8 doesn't have it, but if you still have a Solaris 8 system you may have other problems.)

Note that you should care about this issue even if your software is Linux specific. While Linux defaults to having dual binding on (which lets you just bind an IPv6 socket and get IPv4 for free), this can be turned off on individual systems and Debian is apparently going to default to having it turned off in their next release.

ModernSocketsListening written at 01:04:26; Add Comment

2010-02-17

The purpose of configuration files

The common garden variety configuration file is generally terrible; hard to write, hard to read, and hard to use. That's because they've generally been designed wrong, with the wrong purpose.

Much like programming languages, very few people create configuration systems with the goal of communicating with both the program and other people; instead they are almost always aimed just towards communicating with the program. When you are just communicating with the program, all sorts of things can be implicit, cryptic, and focused on the mechanics of what the program needs to do.

But this leaves you with the problem of assembler language. Although you're describing precisely what the program should do, you're not describing why it does these things or even what they are; you can't, because there is no mechanism for it (except comments, and we all know the problems with them). In addition to readability for other people (including your future self), leaving off the higher level logic of what is going on leaves you open to various issues.

In short: configuration files need to be designed for people to read, not just for programs to parse and use.

(This is very similar to some modern attitudes on programming language design, where a good part of the purpose of a language is to enable clear communication of your intentions with other developers, not just instructing the computer on what code to execute.)

This problem can't be solved by slapping some generic high-level features into your configuration system and calling it done, or by making your program be configured through a full general purpose programming language. Good configuration systems are program specific, because they start from a high level description of what you're doing and then figure out how to write that out clearly in a way that the program can use too.

(You can and should include low-level features in your configuration system; sometimes they'll be needed. But they should not be routine, any more than people should routinely be dropping to assembler in a good programming language.)

This is hard work, and worse it is hard UI work. But doing it right is important. For programs complex enough to need them, configuration files are not an afterthought, they are an integral part of how people use your software. Treating them as an afterthought where you don't have to care about readability or anything short of what's easiest for the program is an abrogation of your design responsibilities.

(This is an expansion of a paragraph from this entry, because sometimes I have insights in passing that deserve to be expanded to full entries.)

ConfigurationPurpose written at 02:05:35; Add Comment

2010-02-09

Why your program should have an actual configuration file

Every so often, someone says something like 'you know, our program has a configuration file but also supports runtime reconfiguration via some magic. Clearly this is wrong, so what we should do is get rid of our configuration file and just make sure the running state is persistent'. If they're feeling nice, they add that the running state will be saved as an XML file.

Every time people say this, sysadmins cry. Here is a very important thing for real deployments of your program in real environments: configuration files are a good thing because they are really easy to manage. Running state that is updated by applying changes (often non-idempotent changes) is much harder.

First, let's get something out of the way: machine generated, automatically updated XML files are not configuration files in any conventional sense that is useful to sysadmins. They are an internal persistence mechanism that may, perhaps, have vaguely useful and inspectable contents (but generally not). So regardless of XML or not, if you go down this route you do not have a configuration file but instead a program with configuration state that persists over reboots and restarts.

Let's inventory some of the things that you lose when you merely have persistent configuration state without actual configuration files:

  • you cannot configure the program without the program actually being running. Programs often have undesirable behavior when started in an unconfigured, misconfigured, or inaccurately configured state.

    Among other things, this means that you can't prepare alternate configurations in advance; you must build them on the fly.

    (Or you must build them on another machine or in another instance of the program, shut both down, and port the magic persistence database over in whatever form it is in, assuming that it does not have host or instance specific data buried in it that you must scrub out.)

  • you cannot atomically make a bunch of changes, having them all take effect at once by putting a new configuration file into place and restarting the program (well, unless there's an explicit 'batch changes together' mechanism). Instead you must make the changes reconfiguration operation by reconfiguration operation. Much like before, this can result in the program temporarily operating in a highly undesirable state. At a minimum, it's going to complicate planning changes.
  • corollary: you can't easily switch configurations or choose different configurations based on outside conditions.

  • automatically updating configuration files clash, potentially badly, with attempts to maintain configuration files through version control systems, automated deployment mechanisms, and so on.

  • it is (or should be) easier to understand a configuration that is written out in a configuration file than one that is the implicit results of applying a bunch of configuration change operations.

    (If it is not, let's be honest here: you need a better configuration file format.)

  • it is much easier to update configurations by providing new files than it is to update configurations by applying configuration changes. There are lots of mechanisms to put new files into place; there are very few to carefully run sequences of commands, keeping track of what ones have already been executed successfully.

I could go on, but I think I'm going to stop now; I hope that you get the point. Configuration files don't exist merely because those other programmers are lazy people, they exist because they're actually a pretty good solution to a whole bunch of problems at once. Getting rid of them is almost never forward progress.

UseConfigurationFiles written at 00:34:14; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.