Ensure that UNIX sockets are automatically unlinked upon close.
[doldaconnect.git] / daemon / net.c
index 4054518..f2ade0f 100644 (file)
 
 static struct configvar myvars[] =
 {
-    /* 0 = Direct mode, 1 = Passive mode, 2 = SOCKS proxy */
+    /** The network mode to use. Currently supported values are 0 for
+     * active mode and 1 for passive mode. In the future, SOCKS5 proxy
+     * support may be added. */
     {CONF_VAR_INT, "mode", {.num = 0}},
+    /** Set the SO_REUSEADDR socket option on listening sockets, so
+     * that dead TCP connections waiting for timeout are ignored. */
     {CONF_VAR_BOOL, "reuseaddr", {.num = 0}},
-    /* Only for direct mode */
+    /** Overrides the IPv4 address reported to other clients in active
+     * mode. Useful for servers behind NAT routers. If both this and
+     * net.publicif are unspecified the address of the hub connection
+     * is used. */
     {CONF_VAR_IPV4, "visibleipv4", {.ipv4 = {0}}},
+    /** Specifies an interface name from which to fetch the IPv4
+     * address reported to other clients in active mode. If both this
+     * and net.visibleipv4 are unspecified the address of the hub
+     * connection is used. */
     {CONF_VAR_STRING, "publicif", {.str = L""}},
     /* Diffserv should be supported on IPv4, too, but I don't know the
      * API to do that. */
+    /** The Diffserv value to use on IPv6 connections when the
+     * minimize cost TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-mincost", {.num = 0}},
+    /** The Diffserv value to use on IPv6 connections when the
+     * maximize reliability TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-maxrel", {.num = 0}},
+    /** The Diffserv value to use on IPv6 connections when the
+     * maximize throughput TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-maxtp", {.num = 0}},
+    /** The Diffserv value to use on IPv6 connections when the
+     * minimize delay TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
     {CONF_VAR_END}
 };
@@ -174,11 +197,11 @@ static struct socket *newsock(int type)
        new->inbuf.d.f = new->inbuf.d.l = NULL;
        break;
     }
-    CBCHAININIT(new, socket_conn);
-    CBCHAININIT(new, socket_err);
-    CBCHAININIT(new, socket_read);
-    CBCHAININIT(new, socket_write);
-    CBCHAININIT(new, socket_accept);
+    new->conncb = NULL;
+    new->errcb = NULL;
+    new->readcb = NULL;
+    new->writecb = NULL;
+    new->acceptcb = NULL;
     new->next = sockets;
     new->prev = NULL;
     if(sockets != NULL)
@@ -240,11 +263,6 @@ void putsock(struct socket *sk)
     
     if(--(sk->refcount) == 0)
     {
-       CBCHAINFREE(sk, socket_conn);
-       CBCHAINFREE(sk, socket_err);
-       CBCHAINFREE(sk, socket_read);
-       CBCHAINFREE(sk, socket_write);
-       CBCHAINFREE(sk, socket_accept);
        switch(sk->type)
        {
        case SOCK_STREAM:
@@ -270,8 +288,7 @@ void putsock(struct socket *sk)
            }
            break;
        }
-       if(sk->fd >= 0)
-           close(sk->fd);
+       closesock(sk);
        if(sk->remote != NULL)
            free(sk->remote);
        free(sk);
@@ -357,18 +374,21 @@ static void sockrecv(struct socket *sk)
        {
            if((errno == EINTR) || (errno == EAGAIN))
                return;
-           CBCHAINDOCB(sk, socket_err, sk, errno);
+           if(sk->errcb != NULL)
+               sk->errcb(sk, errno, sk->data);
            closesock(sk);
            return;
        }
        if(ret == 0)
        {
-           CBCHAINDOCB(sk, socket_err, sk, 0);
+           if(sk->errcb != NULL)
+               sk->errcb(sk, 0, sk->data);
            closesock(sk);
            return;
        }
        sk->inbuf.s.datasize += ret;
-       CBCHAINDOCB(sk, socket_read, sk);
+       if(sk->readcb != NULL)
+           sk->readcb(sk, sk->data);
        break;
     case SOCK_DGRAM:
        if(ioctl(sk->fd, SIOCINQ, &inq))
@@ -389,7 +409,8 @@ static void sockrecv(struct socket *sk)
            free(dbuf);
            if((errno == EINTR) || (errno == EAGAIN))
                return;
-           CBCHAINDOCB(sk, socket_err, sk, errno);
+           if(sk->errcb != NULL)
+               sk->errcb(sk, errno, sk->data);
            closesock(sk);
            return;
        }
@@ -404,7 +425,8 @@ static void sockrecv(struct socket *sk)
            free(dbuf);
            if(!((sk->family == AF_INET) || (sk->family == AF_INET6)))
            {
-               CBCHAINDOCB(sk, socket_err, sk, 0);
+               if(sk->errcb != NULL)
+                   sk->errcb(sk, 0, sk->data);
                closesock(sk);
            }
            return;
@@ -417,7 +439,8 @@ static void sockrecv(struct socket *sk)
        else
            sk->inbuf.d.f = dbuf;
        sk->inbuf.d.l = dbuf;
-       CBCHAINDOCB(sk, socket_read, sk);
+       if(sk->readcb != NULL)
+           sk->readcb(sk, sk->data);
        break;
     }
 }
@@ -443,7 +466,8 @@ static void sockflush(struct socket *sk)
        if(ret > 0)
        {
            memmove(sk->outbuf.s.buf, ((char *)sk->outbuf.s.buf) + ret, sk->outbuf.s.datasize -= ret);
-           CBCHAINDOCB(sk, socket_write, sk);
+           if(sk->writecb != NULL)
+               sk->writecb(sk, sk->data);
        }
        break;
     case SOCK_DGRAM:
@@ -454,13 +478,24 @@ static void sockflush(struct socket *sk)
        free(dbuf->data);
        free(dbuf->addr);
        free(dbuf);
-       CBCHAINDOCB(sk, socket_write, sk);
+       if(sk->writecb != NULL)
+           sk->writecb(sk, sk->data);
        break;
     }
 }
 
 void closesock(struct socket *sk)
 {
+    struct sockaddr_un *un;
+    
+    if((sk->family == AF_UNIX) && !sockgetlocalname(sk, (struct sockaddr **)&un, NULL) && (un->sun_family == PF_UNIX))
+    {
+       if(strchr(un->sun_path, '/'))
+       {
+           if(unlink(un->sun_path))
+               flog(LOG_WARNING, "could not unlink UNIX socket %s: %s", un->sun_path, strerror(errno));
+       }
+    }
     sk->state = SOCK_STL;
     close(sk->fd);
     sk->fd = -1;
@@ -544,7 +579,7 @@ size_t sockqueuesize(struct socket *sk)
  * netcslisten() instead.
 */
 
-struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, int (*func)(struct socket *, struct socket *, void *), void *data)
+struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
 {
     struct socket *sk;
     int intbuf;
@@ -573,12 +608,12 @@ struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namel
        putsock(sk);
        return(NULL);
     }
-    if(func != NULL)
-       CBREG(sk, socket_accept, func, NULL, data);
+    sk->acceptcb = func;
+    sk->data = data;
     return(sk);
 }
 
-struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, int (*func)(struct socket *, struct socket *, void *), void *data)
+struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
 {
     if(confgetint("net", "mode") == 1)
     {
@@ -591,13 +626,13 @@ struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, i
     return(NULL);
 }
 
-struct socket *netcstcplisten(int port, int local, int (*func)(struct socket *, struct socket *, void *), void *data)
+struct socket *netcstcplisten(int port, int local, void (*func)(struct socket *, struct socket *, void *), void *data)
 {
     struct sockaddr_in addr;
 #ifdef HAVE_IPV6
     struct sockaddr_in6 addr6;
 #endif
-    struct socket *(*csfunc)(int, struct sockaddr *, socklen_t, int (*)(struct socket *, struct socket *, void *), void *);
+    struct socket *(*csfunc)(int, struct sockaddr *, socklen_t, void (*)(struct socket *, struct socket *, void *), void *);
     struct socket *ret;
     
     if(local)
@@ -668,7 +703,7 @@ void netdgramconn(struct socket *sk, struct sockaddr *addr, socklen_t addrlen)
     sk->ignread = 1;
 }
 
-struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, int (*func)(struct socket *, int, void *), void *data)
+struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)(struct socket *, int, void *), void *data)
 {
     struct socket *sk;
     int mode;
@@ -688,8 +723,8 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, int (*func)(s
        if(errno == EINPROGRESS)
        {
            sk->state = SOCK_SYN;
-           if(func != NULL)
-               CBREG(sk, socket_conn, func, NULL, data);
+           sk->conncb = func;
+           sk->data = data;
            return(sk);
        }
        putsock(sk);
@@ -756,7 +791,10 @@ int pollsocks(int timeout)
            {
                sslen = sizeof(ss);
                if((newfd = accept(sk->fd, (struct sockaddr *)&ss, &sslen)) < 0)
-                   CBCHAINDOCB(sk, socket_err, sk, errno);
+               {
+                   if(sk->errcb != NULL)
+                       sk->errcb(sk, errno, sk->data);
+               }
                newsk = newsock(sk->type);
                newsk->fd = newfd;
                newsk->family = sk->family;
@@ -764,13 +802,15 @@ int pollsocks(int timeout)
                memcpy(newsk->remote = smalloc(sslen), &ss, sslen);
                newsk->remotelen = sslen;
                putsock(newsk);
-               CBCHAINDOCB(sk, socket_accept, sk, newsk);
+               if(sk->acceptcb != NULL)
+                   sk->acceptcb(sk, newsk, sk->data);
            }
            if(pfds[i].revents & POLLERR)
            {
                retlen = sizeof(ret);
                getsockopt(sk->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
-               CBCHAINDOCB(sk, socket_err, sk, ret);
+               if(sk->errcb != NULL)
+                   sk->errcb(sk, ret, sk->data);
                continue;
            }
            break;
@@ -779,14 +819,16 @@ int pollsocks(int timeout)
            {
                retlen = sizeof(ret);
                getsockopt(sk->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
-               CBCHAINDOCB(sk, socket_conn, sk, ret);
+               if(sk->conncb != NULL)
+                   sk->conncb(sk, ret, sk->data);
                closesock(sk);
                continue;
            }
            if(pfds[i].revents & (POLLIN | POLLOUT))
            {
                sk->state = SOCK_EST;
-               CBCHAINDOCB(sk, socket_conn, sk, 0);
+               if(sk->conncb != NULL)
+                   sk->conncb(sk, 0, sk->data);
            }
            break;
        case SOCK_EST:
@@ -794,7 +836,8 @@ int pollsocks(int timeout)
            {
                retlen = sizeof(ret);
                getsockopt(sk->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen);
-               CBCHAINDOCB(sk, socket_err, sk, ret);
+               if(sk->errcb != NULL)
+                   sk->errcb(sk, ret, sk->data);
                closesock(sk);
                continue;
            }
@@ -816,7 +859,8 @@ int pollsocks(int timeout)
        }
        if(pfds[i].revents & POLLHUP)
        {
-           CBCHAINDOCB(sk, socket_err, sk, 0);
+           if(sk->errcb != NULL)
+               sk->errcb(sk, 0, sk->data);
            closesock(sk);
            unlinksock(sk);
            continue;
@@ -1026,7 +1070,8 @@ int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *le
        return(-1);
     }
     *namebuf = memcpy(smalloc(len), &name, len);
-    *lenbuf = len;
+    if(lenbuf != NULL)
+       *lenbuf = len;
     return(0);
 }