Use a lock file to be able to log an error when the UDS socket's path is
in use by another instance, avoid silently unlink()ing it.

There's no way for multiple instances (e.g. in a multi-domain setup) to
bind() to the same address, there's nothing like SO_REUSEADDR for unix
sockets.  Just unlinking the socket makes for a behaviour that's
initially confusing to the user, and creates a race condition where
one instane's bind() call can happen between another instane's unlink()
and bind() causing the latter to fail.  Resort to logging an error when
uds_{,ro_}address is in use.

Signed-off-by: Andrew Zaborowski <andrew.zaborow...@intel.com>
---
 uds.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/uds.c b/uds.c
index 6d39dc8..4960bbe 100644
--- a/uds.c
+++ b/uds.c
@@ -23,7 +23,9 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/un.h>
+#include <sys/file.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "address.h"
 #include "contain.h"
@@ -34,19 +36,32 @@
 struct uds {
        struct transport t;
        struct address address;
+       int lock_fd;
 };
 
 static int uds_close(struct transport *t, struct fdarray *fda)
 {
+       struct uds *uds = container_of(t, struct uds, t);
        struct sockaddr_un sa;
        socklen_t len = sizeof(sa);
+       char *lock_name;
 
        if (!getsockname(fda->fd[FD_GENERAL], (struct sockaddr *) &sa, &len) &&
            sa.sun_family == AF_LOCAL) {
                unlink(sa.sun_path);
+
+               if (asprintf(&lock_name, "%s.lock", sa.sun_path) != -1) {
+                       /* Must be done after the socket was unlinked.  The lock
+                        * isn't released until the close() below but another
+                        * process can no longer open our lock file to check 
this.
+                        */
+                       unlink(lock_name);
+                       free(lock_name);
+               }
        }
 
        close(fda->fd[FD_GENERAL]);
+       close(uds->lock_fd);
        return 0;
 }
 
@@ -60,7 +75,9 @@ static int uds_open(struct transport *t, struct interface 
*iface, struct fdarray
        const char* file_mode_cfg;
        struct sockaddr_un sa;
        mode_t file_mode;
-       int fd, err;
+       int fd, err, lock_fd;
+       char *lock_name;
+       int ret = -1;
 
        fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
        if (fd < 0) {
@@ -71,13 +88,31 @@ static int uds_open(struct transport *t, struct interface 
*iface, struct fdarray
        sa.sun_family = AF_LOCAL;
        strncpy(sa.sun_path, name, sizeof(sa.sun_path) - 1);
 
+       if (asprintf(&lock_name, "%s.lock", name) == -1) {
+               pr_err("uds: asprinf error");
+               return -1;
+       }
+       lock_fd = open(lock_name, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
+       if (lock_fd == -1) {
+               pr_err("uds: failed to open(%s): %m", lock_name);
+               goto free_lock_name;
+       }
+
+       if (flock(lock_fd, LOCK_EX | LOCK_NB) != 0) {
+               pr_err("uds: can't acquire lock, another instance may be using 
%s",
+                      name);
+               goto free_lock_name;
+       }
+
        unlink(name);
 
        err = bind(fd, (struct sockaddr *) &sa, sizeof(sa));
        if (err < 0) {
                pr_err("uds: bind failed: %m");
                close(fd);
-               return -1;
+               close(lock_fd);
+               unlink(lock_name);
+               goto free_lock_name;
        }
 
        file_mode_cfg = "uds_file_mode";
@@ -96,7 +131,12 @@ static int uds_open(struct transport *t, struct interface 
*iface, struct fdarray
        chmod(name, file_mode);
        fda->fd[FD_EVENT] = -1;
        fda->fd[FD_GENERAL] = fd;
-       return 0;
+       uds->lock_fd = lock_fd;
+       ret = 0;
+
+free_lock_name:
+       free(lock_name);
+       return ret;
 }
 
 static int uds_recv(struct transport *t, int fd, void *buf, int buflen,
-- 
2.34.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to