Don't print the path from Unix sockets as abstract peers seem to not follow the speci...
[doldaconnect.git] / daemon / net.c
index f2ade0f..16c7bbb 100644 (file)
@@ -33,6 +33,7 @@
 #include <netinet/in.h>
 #include <netdb.h>
 #include <sys/signal.h>
+#include <sys/stat.h>       /* For rebindunix() */
 #ifdef HAVE_LINUX_SOCKIOS_H
 #include <linux/sockios.h>
 #endif
@@ -490,10 +491,10 @@ void closesock(struct socket *sk)
     
     if((sk->family == AF_UNIX) && !sockgetlocalname(sk, (struct sockaddr **)&un, NULL) && (un->sun_family == PF_UNIX))
     {
-       if(strchr(un->sun_path, '/'))
+       if((sk->state == SOCK_LST) && strchr(un->sun_path, '/'))
        {
            if(unlink(un->sun_path))
-               flog(LOG_WARNING, "could not unlink UNIX socket %s: %s", un->sun_path, strerror(errno));
+               flog(LOG_WARNING, "could not unlink Unix socket %s: %s", un->sun_path, strerror(errno));
        }
     }
     sk->state = SOCK_STL;
@@ -572,6 +573,29 @@ size_t sockqueuesize(struct socket *sk)
 }
 
 /*
+ * Seriously, I don't know if it's naughty or not to remove
+ * pre-existing Unix sockets.
+ */
+static int rebindunix(struct socket *sk, struct sockaddr *name, socklen_t namelen)
+{
+    struct sockaddr_un *un;
+    struct stat sb;
+    
+    if((sk->family != AF_UNIX) || (name->sa_family != PF_UNIX))
+       return(-1);
+    un = (struct sockaddr_un *)name;
+    if(stat(un->sun_path, &sb))
+       return(-1);
+    if(!S_ISSOCK(sb.st_mode))
+       return(-1);
+    if(unlink(un->sun_path))
+       return(-1);
+    if(bind(sk->fd, name, namelen) < 0)
+       return(-1);
+    return(0);
+}
+
+/*
  * The difference between netcslisten() and netcslistenlocal() is that
  * netcslistenlocal() always listens on the local host, instead of
  * following proxy/passive mode directions. It is suitable for eg. the
@@ -598,7 +622,7 @@ struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namel
        intbuf = 1;
        setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
     }
-    if(bind(sk->fd, name, namelen) < 0)
+    if((bind(sk->fd, name, namelen) < 0) && ((errno != EADDRINUSE) || (rebindunix(sk, name, namelen) < 0)))
     {
        putsock(sk);
        return(NULL);
@@ -890,6 +914,8 @@ int socksettos(struct socket *sk, int tos)
 {
     int buf;
     
+    if(sk->family == AF_UNIX)
+       return(0); /* Unix sockets are always perfect. :) */
     if(sk->family == AF_INET)
     {
        switch(tos)
@@ -1208,9 +1234,6 @@ int addreq(struct sockaddr *x, struct sockaddr *y)
 
 char *formataddress(struct sockaddr *arg, socklen_t arglen)
 {
-    struct sockaddr_un *UNIX; /* Some wise guy has #defined unix with
-                              * lowercase letters to 1, so I do this
-                              * instead. */
     struct sockaddr_in *ipv4;
 #ifdef HAVE_IPV6
     struct sockaddr_in6 *ipv6;
@@ -1224,8 +1247,7 @@ char *formataddress(struct sockaddr *arg, socklen_t arglen)
     switch(arg->sa_family)
     {
     case AF_UNIX:
-       UNIX = (struct sockaddr_un *)arg;
-       ret = sprintf2("%s", UNIX->sun_path);
+       ret = sstrdup("Unix socket");
        break;
     case AF_INET:
        ipv4 = (struct sockaddr_in *)arg;