Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SO_REUSEADDR and AF_UNIX

Tags:

The fact

In the POSIX documentation, I can't see anything preventing the use of the SO_REUSEADDR socket option with AF_UNIX for UNIX Domain Sockets.

However, it invariably fails at bind time if the socket node already exists, and seems to be ignored and seems it is required to unlink the socket node on the file‑system first prior to invoke bind; in short, it does not reuse the address. There are plenty of threads on the web about this issue, and none with a solution.

The question

I won't insist, if it doesn't work, it doesn't work (seems to be the same at least on both BSD and Linux systems), and just have a question: is this normal behaviour or not? Is there any pointers suggesting it should be supported, or on the opposite, any pointers suggesting it should not? Or is this unspecified? Note the question is asked in the POSIX context, not in any particular platform context.

I welcome any POSIX reference on the matter.

Extra: a tiny snippet to not blindly unlink who‑know‑what

I've seen some threads on the web, suggesting to unlink any node of the expected name prior to bind. I feel it's unsafe, and one should only unlink a node which is already a socket node in this case: ex. it's probably wrong, to unlink a text file named mysocket to recreate a socket node of the same name in place. In this purpose, here is a tiny snippet:

/* Create the socket node  * ----------------------  * Note `SO_REUSEADDR` does not work with `AF_UNIX` sockets,  * so we will have to unlink the socket node if it already exists,  * before we bind. For safety, we won't unlink an already existing node  * which is not a socket node.   */  status = stat (path, &st); if (status == 0) {    /* A file already exists. Check if this file is a socket node.     *   * If yes: unlink it.     *   * If no: treat it as an error condition.     */    if ((st.st_mode & S_IFMT) == S_IFSOCK) {       status = unlink (path);       if (status != 0) {          perror ("Error unlinking the socket node");          exit (1);       }    }    else {       /* We won't unlink to create a socket in place of who-know-what.        * Note: don't use `perror` here, as `status == 0` (this is an        * error we've defined, not an error returned by a system-call).        */       fprintf (stderr, "The path already exists and is not a socket node.\n");       exit (1);    } } else {    if (errno == ENOENT) {       /* No file of the same path: do nothing. */    }    else {       perror ("Error stating the socket node path");       exit (1);    } }  /* … invoke `bind` here, which will create the socket node … */ 
like image 759
Hibou57 Avatar asked Mar 30 '13 07:03

Hibou57


People also ask

What is So_reuseaddr?

The SO_REUSEADDR socket option allows a socket to forcibly bind to a port in use by another socket. The second socket calls setsockopt with the optname parameter set to SO_REUSEADDR and the optval parameter set to a boolean value of TRUE before calling bind on the same port as the original socket.

What is the difference between the domains Af_inet and Af_unix?

The difference is that an INET socket is bound to an IP address-port tuple, while a UNIX socket is "bound" to a special file on your filesystem. Generally, only processes running on the same machine can communicate through the latter.

What is Af_unix socket?

The AF_UNIX (also known as AF_LOCAL) socket family is used to communicate between processes on the same machine efficiently. Traditionally, UNIX domain sockets can be either unnamed, or bound to a filesystem pathname (marked as being of type socket).

What is a socket file?

A socket is a special file used for inter-process communication, which enables communication between two processes. In addition to sending data, processes can send file descriptors across a Unix domain socket connection using the sendmsg() and recvmsg() system calls.


1 Answers

I only have access to one POSIX specification document, which is System Interfaces, so I'm going to do my best from here.

Our specification spelunking adventure must of course start in 2.10.6 Use of Options, which defines the SO_REUSEADDR option as follows:

The SO_REUSEADDR option indicates that the rules used in validating addresses supplied in a bind() should allow reuse of local addresses. Operation of this option is protocol-specific. The default value for SO_REUSEADDR is off; that is, reuse of local addresses is not permitted.

This paragraph basically disclaims any specification of what this option truly does, by delegating it to the specification of the underlying protocol.

Section 2.10.17 Use of Sockets for Local UNIX Connections describes the mechanics of creating UNIX domain sockets, but really the only thing it tells us is what socket type constant to use and which struct to use for addresses. The documentation for the sockaddr_un struct tells us only about its format, not about its behavior on bind.

The documentation for bind itself is understandably protocol-agnostic, telling us only what happens when the address is already in use, not the circumstances under which re-binding the same socket is valid.

Although it's not a POSIX standard document, Fujitsu has a document on the POSIX sockets API which is interesting if only because it's not specifically about Linux or BSD. Section 2.6.4 of this document has the following to say about the behavior of bind on UNIX sockets:

The path name, which must be specified in the sun.sun_path component, is created as a file in the file system using bind(). The process that calls bind() must therefore have write rights to the directory in which the file is to be written. The system does not delete the file. It should therefore be deleted by the process when it is no longer required.

Although this says nothing about SO_REUSEADDR in particular, it does state that the behavior of bind is to create a file, and that it is the responsibility of the binding process to remove it when it's no longer being used.

Finally, this document's description of setsockopt has the following to say about SO_REUSEADDR:

Specifies that the rules for the validity check on the addresses specified for bind() should permit the reuse of local addresses provided this is supported by the protocol.

So while this makes no specific mention of AF_UNIX, it does acknowledge that this option doesn't apply to all protocols.

I also found a (non-authoritative) summary describing the intended purpose of SO_REUSEADDR:

This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. If it is busy, but with another state, you will still get an address already in use error.

The TIME_WAIT state exists primarily for Internet-facing sockets to avoid a new program binding to a port that was recently being used by another program and inadvertently receiving packets relating to the old program. This problem is arguably not applicable to UNIX domain sockets because it's very unlikely that two programs would attempt to create a socket at the same path, so if TIME_WAIT is not implemented for UNIX sockets then that could be one (approximation of an) explanation for why SO_REUSEADDR does not apply to AF_UNIX.

like image 116
Martin Atkins Avatar answered Oct 21 '22 02:10

Martin Atkins