Allow the usage of the TOS API to set DSCP values on IPv4 sockets.
[doldaconnect.git] / daemon / net.c
index 44974f1..e7c63d1 100644 (file)
@@ -66,8 +66,6 @@ static struct configvar myvars[] =
      * 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). */
@@ -84,6 +82,11 @@ static struct configvar myvars[] =
      * minimize delay TOS value is used (see the TOS VALUES
      * section). */
     {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
+    /** If enabled, the IP TOS interface will be used to set Diffserv
+     * codepoints on IPv4 sockets, by shifting the DSCP value to bits
+     * to the left (across the ECN bits). This may only work on
+     * Linux. */
+    {CONF_VAR_BOOL, "dscp-tos", {.num = 0}},
     {CONF_VAR_END}
 };
 
@@ -172,6 +175,7 @@ static struct socket *newsock(int type)
     struct socket *new;
     
     new = smalloc(sizeof(*new));
+    memset(new, 0, sizeof(*new));
     new->refcount = 2;
     new->fd = -1;
     new->isrealsocket = 1;
@@ -525,8 +529,12 @@ static void sockflush(struct socket *sk)
            ret = write(sk->fd, sk->outbuf.s.buf, sk->outbuf.s.datasize);
        if(ret < 0)
        {
-           /* For now, assume transient error, since
-            * the socket is polled for errors */
+           if((errno != EINTR) && (errno != EAGAIN))
+           {
+               if(sk->errcb != NULL)
+                   sk->errcb(sk, errno, sk->data);
+               closesock(sk);
+           }
            break;
        }
        if(ret > 0)
@@ -976,27 +984,41 @@ int pollsocks(int timeout)
 int socksettos(struct socket *sk, int tos)
 {
     int buf;
+    int dscp2tos;
     
     if(sk->family == AF_UNIX)
        return(0); /* Unix sockets are always perfect. :) */
     if(sk->family == AF_INET)
     {
+       dscp2tos = confgetint("net", "dscp-tos");
        switch(tos)
        {
        case 0:
            buf = 0;
            break;
        case SOCK_TOS_MINCOST:
-           buf = 0x02;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-mincost") << 2;
+           else
+               buf = 0x02;
            break;
        case SOCK_TOS_MAXREL:
-           buf = 0x04;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-maxrel") << 2;
+           else
+               buf = 0x04;
            break;
        case SOCK_TOS_MAXTP:
-           buf = 0x08;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-maxtp") << 2;
+           else
+               buf = 0x08;
            break;
        case SOCK_TOS_MINDELAY:
-           buf = 0x10;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-mindelay") << 2;
+           else
+               buf = 0x10;
            break;
        default:
            flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);