Does Linux automatically clean up abstract domain sockets

socketunix-sockets

There's a great answer on StackOverflow about providing a better lock for daemons (synthesized from Eduardo Fleury) that doesn't depend on the common PID file lock mechanism for daemons. There are lots of good comments there about why PID lock files can sometimes cause problems, so I won't rehash them here.

In short, the solution relies on Linux abstract namespace domain sockets, which keeps track of the sockets by name for you, rather than relying on files, which can stick around after the daemon is SIGKILL'd. The example shows that Linux seems to free the socket once the process is dead.

But I can't find definitive documentation in Linux that says what exactly Linux does with the abstract socket when the bound process is SIGKILL'd. Does anyone know?

Put another way, when precisely is the abstract socket freed to be used again?

I don't want to replace the PID file mechanism with abstract sockets unless it definitively solves the problem.

Best Answer

Yes, linux automatically "cleans up" abstract sockets to the extent that cleaning up even makes sense. Here's a minimal working example with which you can verify this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int
main(int argc, char **argv)
{
  int s;
  struct sockaddr_un sun;

  if (argc != 2 || strlen(argv[1]) + 1 > sizeof(sun.sun_path)) {
    fprintf(stderr, "usage: %s abstract-path\n", argv[0]);
    exit(1);
  }

  s = socket(AF_UNIX, SOCK_STREAM, 0);
  if (s < 0) {
    perror("socket");
    exit(1);
  }
  memset(&sun, 0, sizeof(sun));
  sun.sun_family = AF_UNIX;
  strcpy(sun.sun_path + 1, argv[1]);
  if (bind(s, (struct sockaddr *) &sun, sizeof(sun))) {
    perror("bind");
    exit(1);
  }
  pause();
}

Run this program as ./a.out /test-socket &, then run ss -ax | grep test-socket, and you will see the socket in use. Then kill %./a.out, and ss -ax will show the socket is gone.

However, the reason you can't find this clean-up in any documentation is that it isn't really cleaning up in the same sense that non-abstract unix-domain sockets need cleaning up. A non-abstract socket actually allocates an inode and creates an entry in a directory, which needs to be cleaned up in the underlying file system. By contrast, think of an abstract socket more like a TCP or UDP port number. Sure, if you bind a TCP port and then exit, that TCP port will be free again. But whatever 16-bit number you used still exists abstractly and always did. The namespace of port numbers is 1-65535 and never changes or needs cleaning.

So just think of the abstract socket name like a TCP or UDP port number, just picked from a much larger set of possible port numbers that happen to look like pathnames but are not. You can't bind the same port number twice (barring SO_REUSEADDR or SO_REUSEPORT). But closing the socket (explicitly or implicitly by terminating) frees the port, with nothing left to clean up.

Related Question