DSCP: document; hex print; -bI:dscp
[exim.git] / src / src / ip.c
index af57fa411ca5d825bd3f0654e91b272cb6eca4b3..be4511dfa514d21caf7eb7e0b97b1b353b70e50e 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/ip.c,v 1.7 2007/01/08 10:50:18 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for doing things with sockets. With the advent of IPv6 this has
@@ -361,4 +359,122 @@ return -1;
 }
 
 
+
+
+/*************************************************
+*       Lookup DSCP settings for a socket        *
+*************************************************/
+
+struct dscp_name_tableentry {
+  const uschar *name;
+  int value;
+};
+/* Keep both of these tables sorted! */
+static struct dscp_name_tableentry dscp_table[] = {
+#ifdef IPTOS_DSCP_AF11
+    { CUS"af11", IPTOS_DSCP_AF11 },
+    { CUS"af12", IPTOS_DSCP_AF12 },
+    { CUS"af13", IPTOS_DSCP_AF13 },
+    { CUS"af21", IPTOS_DSCP_AF21 },
+    { CUS"af22", IPTOS_DSCP_AF22 },
+    { CUS"af23", IPTOS_DSCP_AF23 },
+    { CUS"af31", IPTOS_DSCP_AF31 },
+    { CUS"af32", IPTOS_DSCP_AF32 },
+    { CUS"af33", IPTOS_DSCP_AF33 },
+    { CUS"af41", IPTOS_DSCP_AF41 },
+    { CUS"af42", IPTOS_DSCP_AF42 },
+    { CUS"af43", IPTOS_DSCP_AF43 },
+    { CUS"ef", IPTOS_DSCP_EF },
+#endif
+#ifdef IPTOS_LOWCOST
+    { CUS"lowcost", IPTOS_LOWCOST },
+#endif
+    { CUS"lowdelay", IPTOS_LOWDELAY },
+#ifdef IPTOS_MINCOST
+    { CUS"mincost", IPTOS_MINCOST },
+#endif
+    { CUS"reliability", IPTOS_RELIABILITY },
+    { CUS"throughput", IPTOS_THROUGHPUT }
+};
+static int dscp_table_size =
+  sizeof(dscp_table) / sizeof(struct dscp_name_tableentry);
+
+/* DSCP values change by protocol family, and so do the options used for
+setsockopt(); this utility does all the lookups.
+
+Arguments:
+  dscp_name   a string, so far unvalidated
+  af          address_family in use
+  level       setsockopt level to use
+  optname     setsockopt name to use
+  dscp_value  value for dscp_name
+
+Returns: TRUE if okay to setsockopt(), else FALSE
+*/
+
+BOOL
+dscp_lookup(const uschar *dscp_name, int af,
+    int *level, int *optname, int *dscp_value)
+{
+uschar *dscp_lookup;
+int first, last;
+
+if (af == AF_INET)
+  {
+  *level = IPPROTO_IP;
+  *optname = IP_TOS;
+  }
+else if (af == AF_INET6)
+  {
+  *level = IPPROTO_IPV6;
+  *optname = IPV6_TCLASS;
+  }
+else
+  {
+  DEBUG(D_transport)
+    debug_printf("Unhandled address family %d in dscp_lookup()\n", af);
+  return FALSE;
+  }
+if (!dscp_name)
+  {
+  DEBUG(D_transport)
+    debug_printf("[empty DSCP]\n");
+  return FALSE;
+  }
+dscp_lookup = expand_string(US dscp_name);
+if (dscp_lookup == NULL || *dscp_lookup == '\0')
+  return FALSE;
+
+first = 0;
+last = dscp_table_size;
+while (last > first)
+  {
+  int middle = (first + last)/2;
+  int c = Ustrcmp(dscp_lookup, dscp_table[middle].name);
+  if (c == 0)
+    {
+    *dscp_value = dscp_table[middle].value;
+    return TRUE;
+    }
+  else if (c > 0)
+    {
+    first = middle + 1;
+    }
+  else
+    {
+    last = middle;
+    }
+  }
+return FALSE;
+}
+
+void
+dscp_list_to_stream(FILE *stream)
+{
+int i;
+for (i=0; i < dscp_table_size; ++i)
+  fprintf(stream, "%s\n", dscp_table[i].name);
+}
+
+
 /* End of ip.c */