The Universal Pause Button is amazing

Posted on . Updated on .

The Universal Pause Button is a free and open source Windows program that was featured on the front page of Hacker News a couple of months ago. It’s the Windows low-level and simple equivalent of a program that, under Unix-like systems, would find the PID in charge of the focused window in X11 and send it a SIGSTOP signal when pressing a button, followed by SIGCONT when the button is pressed again. The “button” normally being the pause/break key in the keyboard.

Effectively, this allows pausing the process at a low level and its author, Ryan Ries, states he specifically wrote it to be able to pause cutscenes in the videogame The Witcher III, which normally cannot be paused with an in-game native mechanism, and pay attention to real life events. In my case, it’s been used so far to pause and resume the game Dark Souls (note: Dark Souls III will be available in 2016 and I’m considering buying Dark Souls II at some point in the future). I had bought the game many months before but I had to abandon the playthrough precisely due to the lack of a pause function even in offline mode.

I thought of writing a review of the game but I decided to focus this post on the Universal Pause Button project instead. For a quick review, let me tell you the game is pretty good and enjoyable, but doesn’t hold your hand in many of the gameplay aspects, which are to be discovered slowly and painfully by the player. However, in the Internet age, it’s possible for anyone to read a lot of information about how the different RPG aspects of the game work, and also to get a nice overview of the available equipment to decide how you want to build your character. This makes the game easier while retaining its difficulty in the boss fights and enemies in general, and the exploratory excitement when entering a new area. Advancing through the game requires efforts and perseverance, and it’s a very rewarding experience. It brings back old school game mechanics like powerful bosses and the need to learn enemy locations, their attack patterns and weaknesses. Nothing Megaman didn’t have, but nowadays it’s considered “hard” because it requires time that’s to be added to an already long game in contrast with old school games that could be finished in one evening once you memorized them completely.

Dark Souls, however and as stated previously, lacks a pause button. Supposedly because it’s an online game where you can interact with other players in many situations, but I focused on single player and I always played in offline mode (previously this was with an offline Game For Windows Live account, also called local account, but nowadays it’s with Steam’s offline mode). It’s true you can quit the game at any moment and it will restore everything as was left before quitting, but this mechanism has two problems. First, you have to navigate a menu to quit and the game doesn’t pause in those seconds and, more importantly, if you’re in a boss fight and you quit, you will be teleported out of the boss arena and lose your progress in the fight. The lack of a pause button in offline mode cannot be justified easily and I don’t think it makes the game any more difficult. It’s simply an impractical glitch. In this situation, the universal pause button has no disadvantages. You only need to take a couple of steps back if in a tight situation, and quickly hit the pause key in your keyboard, as in any other game.

It’s unfortunate that many games nowadays cannot be paused at any moment, in what I can only consider a sad trend. Most of them can be paused normally or feature a menu you can escape to, but cannot be paused in certain cutscenes and dialogues. In Hacker News and reddit, some people commented how in the Wii U and the original Wii, you can press the home button in any game, and it will pause gameplay showing you the Home Menu. That’s what we should aim for in any platform, in my opinion.

The Universal Pause Button has allowed me to play Dark Souls in what is arguably the worst moment in my life to play videogames, having to pay proper and much needed and deserved attention to my wife and a now four-months-old baby. I used the button dozens of times during my playthrough, which I completed this weekend. I’ve personally thanked the project author through email.

If you’re going to use it, I can give you two hints: after installing (i.e. extracting) the program somewhere in your drive, create a link to it in your Windows Startup folder so you won’t have to launch it manually every time. Also, be careful with games and apps that require you to be permanently online due to DRM or anti-cheat mechanism, as the program could interfere with them.

Windows Update is slowness personified

Posted on .

My main desktop computer dual-boots Linux and Windows. Specifically now, Fedora and Windows 7 Home Premium 64-bits. I keep Fedora in an old-ish 128 GB Intel SSD that works remarkably well and has more than enough space for what I use it and, until now, I kept Windows in a 500 GB hard drive. Last week, however, I bought a 500 GB Samsung 850 Evo SSD to replace the HDD (it was just €180 from Amazon and had the same capacity). The drive performance is amazing and games load incredibly faster. Actually, everything is incredibly fast now. Except for one thing: Windows Update.

I can’t imagine what Windows Update does to be so slow. Partitions are properly aligned for the SSD and everything’s in place. After installing SP1 it still had around 200 updates to do (196 if I recall correctly), and most of them were small security fixes and updates. In fact, the total download size was around 400 MB, so it averaged just a couple MB per update. Once they were downloaded, it took the system more than 1 hour and 20 minutes to install them, doing nothing else. That’s more than the time it took for the whole system to be installed. In that time I could have installed Fedora from an old image and updated the whole operating system and applications.

To put thing in perspective, AnandTech reviewed this hard drive and the slowest operation benchmarked was 4KB random reads at 104 MB/second. In 1 hour and 20 minutes it could have random-read around 500 GB, that is, the whole hard drive. I’m unable to imagine what makes Windows Update so slow. It also takes ages to find new updates, even if downloading them takes a few seconds and the servers are able to saturate my download bandwidth (100 Mbps).

By the way, after upgrading I signed up for the free upgrade to Windows 10. I can only hope Windows Update or its equivalent performs better there. Anyway, I feel good after writing the rant.

All systems migrated to Fedora

Posted on .

Back in February I migrated from Slackware to Fedora. I still had a few machines here and there running Slackware, but yesterday I finished migrating all remaining systems to Fedora. I’m still very happy with the distribution and what I’ve seen so far. Note: I also removed my SlackBuilds repository from GitHub. Most people running Slackware use SlackBuild scripts from SlackBuilds.org and my repository had no stars nor forks, but if anyone is interested in those scripts I still keep a copy around.

Just upgraded to Fedora 22

Posted on .

Fedora 22 was released today and I upgraded already. Having started with a minimal installation in Fedora 21, the upgrade was from “nonproduct” to “nonproduct”. The most important change in Fedora 22 is “yum” being replaced with “dnf” as the package manager. I had already switched to dnf a few weeks ago so this didn’t affect me much. Desktop environment updates don’t affect me at all because I’m running i3. Besides that, I will have to update my installation to use libinput in the following days, which is the other important change for me, as other X11 input drivers will be deprecated slowly in Fedora.

A small surprise: some Fedora 22 packages still have the “fc21” tag as they have not been rebuilt for the new release. I made sure this was the case and not an update problem. For example, see asciidoc. All of them are “noarch” (hence they don’t need to be rebuilt) except for xorg-x11-drv-vmmouse, which already has an update pending as I’m writing this. People with more complete and complex systems will probably see more instances of this happening with other packages.

Note to future self: the next time, wait a couple of weeks before upgrading, so all the mirrors are properly in sync. And do not switch mirrors before the upgrade to avoid package downgrades in “dnf distro-sync”. A few weird things popped up while upgrading, but they were solved quickly and the system is up and running again exactly as it was before. All in all, the process was fast and smooth. I’m still very happy with Fedora so far.

Multicast UDP surprises

Posted on . Updated on .

In my job I have to deal with UDP multicast traffic constantly. Creating software that communicates using multicast messages in C or C++ using the BSD sockets API can lead to surprising situations and behavior due to the way the API and the kernel work (Linux in my case). I think some of those aspects are interesting and will try to detail them here. I’ll suppose you are somewhat familiar with the sockets API and I’ll try to escalate from TCP to “What you should know if you’re going to use UDP multicast”. Everything here refers to IPv4. I’ve detected small differences in IPv6, but I didn’t have time to experiment fully with it.

TCP

Most people start socket programming with TCP as it’s easy and convenient. You start by creating a socket with the socket() system call and from there proceed to do the following.

In the client, you call connect() to connect to a server at a given address. After that, the socket can be used like a file with read(), write() and close(). You can call bind() before calling connect() but in most cases it’s not needed.

In the server, you first bind the socket to a listening address with bind(). At that point you normally specify a listening port and a listening IP address. The listening address can be INADDR_ANY to listen on any (all) IP addresses at that port. If you run netstat --listen --tcp -n on you machine and you see an asterisk before the port name, that means the process specified INADDR_ANY. You can also specify another listening address, like 127.0.0.1 or the IP address of a network interface, which you can dynamically obtain prior to calling bind(), so as to restrict traffic to a given interface or avoid listening to the world.

After that, you call listen() to put the socket in listening mode and accept() to accept new connections. The initial socket corresponds to the listening part you can see with netstat, while new sockets returned by accept() represent a specific connection with a client. Like before, you can call write(), read() and close().

Congratulations after writing a couple of client/server programs doing that. You’re now at the beginner level of socket programming. You can move up the stair by trying select(), poll(), non-blocking reads, threading or multi-processing to handle client connections on the server, etc.

UDP

Coming from a TCP background, a few things may surprise you. In the client you usually call bind() with port 0 and INADDR_ANY to bind the socket to a given address that will be used to both send messages and receive responses. Being connection-less, this is a needed step. After that, sendto() and recvfrom() will allow you to send data to other processes and receive data from them.

In the server, you normally bind() to a specific port and use a specific IP address or INADDR_ANY as before, and you sendto() and recvfrom() as in the client.

Few things appear to have changed yet there is an important difference. In TCP, the operating system queues data for you grouping it by connection (i.e. socket) and it’s essentially a queue of bytes. If you receive 20 bytes but request to read 40, your read operation will block unless you switched the socket to non-blocking mode. In that case, you’ll read 20 immediately. Likewise, if you request to read 10 you’ll read 10, and the 10 remaining bytes will wait for a future read().

In UDP, by contrast, the operating system queues your messages by order of arrival (they are not grouped by any connection because they don’t exist) and handles each message (UDP datagram) as an indivisible block. So if you receive a 20-bytes datagram and request to read 10, the operating system will dequeue that message and serve you the first 10 bytes, discarding the other 10. If you request to read 40, the operation will not block unless there are no datagrams pending and you’re in blocking mode, and in our case it will immediately return with the 20-bytes datagram.

This normally means when designing a UDP protocol you either create fixed-size datagrams or always use a large buffer and specify the maximum read size with each recvfrom() call. In my case, radars serve my software variable-sized data up to a maximum size of 64 KiB, which more or less matches the maximum size of a normal UDP datagram, so I usually declare reception buffers with that size and use it in the recvfrom() call.

Unless you’ve been warned or explained this, it usually catches you by surprise in your first UDP programs.

Multicast UDP

Sending data

If you want to create a program that will send traffic to a destination multicast address, an additional step is needed. After creating the socket with socket() and binding it to a local address with bind(), you need to call setsockopt() to specify the IP address of the network interface you want outgoing multicast traffic to go through. Take into account that, by being multicast traffic, the operating system cannot decide which interface to send the message from using the routing table. Multicast traffic can go through any given interface. See the following code:

int fd;
int ret;

// Create socket.
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
{
        /* Handle error. */
}

// Bind to local address.
struct sockaddr_in bind_addr = {
        .sin_family = AF_INET,
        .sin_port = 0,
        .sin_addr = {
                .s_addr = INADDR_ANY
        }
};
ret = bind(fd, (const struct sockaddr *)(&bind_addr), sizeof(bind_addr));
if (ret == -1)
{
        // Handle error.
}

// Set multicast interface.
struct in_addr if_ip;
if_ip.s_addr = ...;

ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                 (const void *)(&if_ip), sizeof(if_ip));
if (ret == -1)
{
        // Handle error.
}

After that, you can use the socket normally and indicate a multicast IP address as the destination address. To send multicast traffic through several interfaces, the easiest option is to create one socket per interface.

Receiving data

The next step is creating a program that will receive multicast traffic, say to IP address 230.1.1.1 and port 4001. There are several steps involved. A program wanting to receive multicast traffic needs to, at least, add a multicast subscription to that IP address on a given interface (specified by IP address too). That subscription is added to a socket and is usually related to the bind address of the socket, but operated independently.

In the bind() call, you must use the given port (4001 in this case). The bind address is usually set to INADDR_ANY or the interface address if you want to receive unicast traffic on that socket too, in addition to the multicast traffic. If you don’t want to receive unicast traffic on the socket and restrict it to multicast traffic, you normally specify the multicast IP address as the bind address.

But that’s not enough to receive multicast traffic on that port. The operating system needs more information. It won’t let multicast traffic in through an interface unless a running process has explicitly requested to receive multicast traffic to that IP address through that interface. This needs, again, a call to setsockopt() to add a multicast group subscription through that interface.

// Suppose we have already called socket() and bind().
struct ip_mreq group;
group.imr_interface.s_addr = /* Interface IP address in network order. */;
group.imr_multiaddr.s_addr = /* 230.1.1.1 in network order. */;

ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                 (const void *)(&group), sizeof(group));
if (ret == -1)
{
        // Handle error.
}

After a running process has successfully added a multicast group to a socket, the subscription will be listed by netstat -gn, the command you can run to check everything is working.

As soon as you want to receive traffic from more than one multicast IP address to the same port, some questions arise. If you bind() to INADDR_ANY, you will open yourself to unicast traffic. If you bind() to the multicast address, you can only receive from that multicast address. Normally, the easy solution is to create one socket per multicast address, binding each socket to each address and adding the corresponding multicast subscription to each socket.

SO_REUSEADDR

Depending on the way you manage your sockets, you might have to activate the SO_REUSEADDR option for your sockets. This option is set with setsockopt(), as before, and needs to be set before calling bind().

int one = 1;
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                 (const void *)(&one), sizeof(one));
if (ret == -1)
{
        // Handle error.
}

SO_REUSEADDR, in the context of multicast UDP, allows sockets to share the same listening address. If you create several sockets and all of them listen on a different multicast IP address, there will be no conflict. But, for example, if you want to receive unicast traffic to port 4001 by binding to INADDR_ANY and have separate sockets for multicast traffic, binding to *:4001 and 230.1.1.1:4001 at the same time will only be possible by specifying SO_REUSEADDR on both sockets. Either no reuse is allowed and there’s only one listening socket or reuse is allowed by everyone and there may be several listening sockets. That’s one example conflict but your application may have others that force you to use SO_REUSEADDR.

Relationship between the multicast address, the port and the interface address

Here comes the surprise. One of the most common mistakes is to think that all three elements (multicast address, port and interface address) are a single entity that acts as a filter to the traffic you will receive on a given socket. After all, the three of them are specified related to the socket. The multicast address and port are used when binding, and the multicast address and interface address are used when subscribing to the multicast group.

So if you bound to 230.1.1.1:4001 and subscribed to 230.1.1.1/192.168.1.1 on a socket, many people would expect that socket to receive traffic through the interface with address 192.168.1.1 going to address 230.1.1.1 and port 4001, and only that traffic. But it doesn’t work like that.

When you bind, you specify your listening address. You cannot received traffic that goes to incompatible addresses. When you subscribe to a multicast group your are saying two things to the operating system. On the one hand, traffic to that multicast group should be allowed through that interface because there’s a process interested in receiving it (we’re not taking into account firewalling rules, of course). On the other hand, that allowance will last as long as the socket is open.

So when the operating system sees multicast traffic coming through that interface, it will first check if someone has requested traffic to that multicast group through that interface. If someone has, it will let those datagrams in. Immediately and surprisingly, the operating system will forget (or stop caring about) which interface the traffic came through. It will deliver it to every socket bound to a compatible destination address and port, including any socket bound to INADDR_ANY on that port.

So if you want to receive traffic to a given multicast group on several interfaces and you create one socket per interface, binding with reuse and adding the multicast group on one interface per socket, you will be surprised when you receive traffic from every interface replicated on all those sockets. And it doesn’t stop per-process. One program of yours listens for multicast traffic and enables the multicast group on a given interface. Another process, outside your control, subscribes to the same multicast group on a completely different interface and suddenly both processes will start receiving all traffic.

If you’re thinking now about the security implications of the previous paragraphs you’re on the good track. You cannot isolate a process receiving multicast traffic to a specific interface from the source code alone. A third-party outside your control can enable that multicast group on another interface and it will reach your process. I’ve experimented this first hand. Comments are welcome in this regard.

If you want to test all of this by yourself, I have created a repository in GitHub containing a couple of example test programs for sending and receiving multicast traffic. All my tests ran on real hardware with real network interfaces. I haven’t bothered to test if everything works the same way in virtual machines.

Many thanks to W. Richard Stevens for extracting the multicast API documentation from Steve Deering’s original README published in 1989 and to Gary R. Wright for restoring Stevens’ kohala.com site after him passing away.