Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
535 views
in Technique[技术] by (71.8m points)

sockets - SO_REUSEADDR and AF_UNIX

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.
");
      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 … */
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...