changeset 68008:10f0a09ec82e

Add IPv6 support. (Qipv4, Qipv6): New vars. (syms_of_process): Intern and staticpro them. (Fformat_network_address): Handle 9 or 8 element vector as IPv6 address with or without port number. Handle 4 element vector as IPv4 address without port number. (conv_sockaddr_to_lisp, get_lisp_to_sockaddr_size) (conv_lisp_to_sockaddr): Handle IPv6 addresses. (Fmake_network_process): Use :family 'ipv4 and 'ipv6 to explicitly request that address family only. :family nil or omitted means to determine address family from the specified :host and :service. (server_accept_connection): Handle IPv6 addresses. (init_process): Add (:family ipv4) and (:family ipv6) sub-features. (ifflag_table): Add missing OpenBSD IFF_ flags.
author Kim F. Storm <storm@cua.dk>
date Wed, 04 Jan 2006 00:16:54 +0000
parents 0b578812ab24
children dd865bff7357
files src/process.c
diffstat 1 files changed, 135 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/process.c	Tue Jan 03 23:35:20 2006 +0000
+++ b/src/process.c	Wed Jan 04 00:16:54 2006 +0000
@@ -140,7 +140,10 @@
 Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal;
 Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
-Lisp_Object Qlocal, Qdatagram;
+Lisp_Object Qlocal, Qipv4, Qdatagram;
+#ifdef AF_INET6
+Lisp_Object Qipv6;
+#endif
 Lisp_Object QCname, QCbuffer, QChost, QCservice, QCtype;
 Lisp_Object QClocal, QCremote, QCcoding;
 Lisp_Object QCserver, QCnowait, QCnoquery, QCstop;
@@ -1195,9 +1198,11 @@
 DEFUN ("format-network-address", Fformat_network_address, Sformat_network_address,
        1, 2, 0,
        doc: /* Convert network ADDRESS from internal format to a string.
+A 4 or 5 element vector represents an IPv4 address (with port number).
+An 8 or 9 element vector represents an IPv6 address (with port number).
 If optional second argument OMIT-PORT is non-nil, don't include a port
-number in the string; in this case, interpret a 4 element vector as an
-IP address.  Returns nil if format of ADDRESS is invalid.  */)
+number in the string, even when present in ADDRESS.
+Returns nil if format of ADDRESS is invalid.  */)
      (address, omit_port)
      Lisp_Object address, omit_port;
 {
@@ -1207,13 +1212,13 @@
   if (STRINGP (address))  /* AF_LOCAL */
     return address;
 
-  if (VECTORP (address))  /* AF_INET */
+  if (VECTORP (address))  /* AF_INET or AF_INET6 */
     {
       register struct Lisp_Vector *p = XVECTOR (address);
       Lisp_Object args[6];
       int nargs, i;
 
-      if (!NILP (omit_port) && (p->size == 4 || p->size == 5))
+      if (p->size == 4 || (p->size == 5 && !NILP (omit_port)))
 	{
 	  args[0] = build_string ("%d.%d.%d.%d");
 	  nargs = 4;
@@ -1223,6 +1228,16 @@
 	  args[0] = build_string ("%d.%d.%d.%d:%d");
 	  nargs = 5;
 	}
+      else if (p->size == 8 || (p->size == 9 && !NILP (omit_port)))
+	{
+	  args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
+	  nargs = 8;
+	}
+      else if (p->size == 9)
+	{
+	  args[0] = build_string ("[%x:%x:%x:%x:%x:%x:%x:%x]:%d");
+	  nargs = 9;
+	}
       else
 	return Qnil;
 
@@ -2212,6 +2227,20 @@
 	cp = (unsigned char *)&sin->sin_addr;
 	break;
       }
+#ifdef AF_INET6
+    case AF_INET6:
+      {
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+	uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr;
+	len = sizeof (sin6->sin6_addr)/2 + 1;
+	address = Fmake_vector (make_number (len), Qnil);
+	p = XVECTOR (address);
+	p->contents[--len] = make_number (ntohs (sin6->sin6_port));
+	for (i = 0; i < len; i++)
+	  p->contents[i] = make_number (ntohs (ip6[i]));
+	return address;
+      }
+#endif
 #ifdef HAVE_LOCAL_SOCKETS
     case AF_LOCAL:
       {
@@ -2256,6 +2285,13 @@
 	  *familyp = AF_INET;
 	  return sizeof (struct sockaddr_in);
 	}
+#ifdef AF_INET6
+      else if (p->size == 9)
+	{
+	  *familyp = AF_INET6;
+	  return sizeof (struct sockaddr_in6);
+	}
+#endif
     }
 #ifdef HAVE_LOCAL_SOCKETS
   else if (STRINGP (address))
@@ -2302,6 +2338,23 @@
 	  sin->sin_port = htons (i);
 	  cp = (unsigned char *)&sin->sin_addr;
 	}
+#ifdef AF_INET6
+      else if (family == AF_INET6)
+	{
+	  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+	  uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr;
+	  len = sizeof (sin6->sin6_addr) + 1;
+	  i = XINT (p->contents[--len]);
+	  sin6->sin6_port = htons (i);
+	  for (i = 0; i < len; i++)
+	    if (INTEGERP (p->contents[i]))
+	      {
+		int j = XFASTINT (p->contents[i]) & 0xffff;
+		ip6[i] = ntohs (j);
+	      }
+	  return;
+	}
+#endif
     }
   else if (STRINGP (address))
     {
@@ -2595,10 +2648,13 @@
 stream type connection, `datagram' creates a datagram type connection.
 
 :family FAMILY -- FAMILY is the address (and protocol) family for the
-service specified by HOST and SERVICE.  The default address family is
-Inet (or IPv4) for the host and port number specified by HOST and
-SERVICE.  Other address families supported are:
+service specified by HOST and SERVICE.  The default (nil) is to use
+whatever address family (IPv4 or IPv6) that is defined for the host
+and port number specified by HOST and SERVICE.  Other address families
+supported are:
   local -- for a local (i.e. UNIX) address specified by SERVICE.
+  ipv4  -- use IPv4 address family only.
+  ipv6  -- use IPv6 address family only.
 
 :local ADDRESS -- ADDRESS is the local address used for the connection.
 This parameter is ignored when opening a client process. When specified
@@ -2715,8 +2771,8 @@
   struct Lisp_Process *p;
 #ifdef HAVE_GETADDRINFO
   struct addrinfo ai, *res, *lres;
-      struct addrinfo hints;
-      char *portstring, portbuf[128];
+  struct addrinfo hints;
+  char *portstring, portbuf[128];
 #else /* HAVE_GETADDRINFO */
   struct _emacs_addrinfo
   {
@@ -2855,19 +2911,29 @@
 
   /* :family FAMILY -- nil (for Inet), local, or integer.  */
   tem = Fplist_get (contact, QCfamily);
-  if (INTEGERP (tem))
+  if (NILP (tem))
+    {
+#ifdef HAVE_GETADDRINFO
+      family = AF_UNSPEC;
+#else
+      family = AF_INET;
+#endif
+    }
+#ifdef HAVE_LOCAL_SOCKETS
+  else if (EQ (tem, Qlocal))
+    family = AF_LOCAL;
+#endif
+#ifdef AF_INET6
+  else if (EQ (tem, Qipv6))
+    family = AF_INET6;
+#endif
+  else if (EQ (tem, Qipv4))
+    family = AF_INET;
+  else if (INTEGERP (tem))
     family = XINT (tem);
   else
-    {
-      if (NILP (tem))
-	family = AF_INET;
-#ifdef HAVE_LOCAL_SOCKETS
-      else if (EQ (tem, Qlocal))
-	family = AF_LOCAL;
-#endif
-    }
-  if (family < 0)
     error ("Unknown address family");
+
   ai.ai_family = family;
 
   /* :service SERVICE -- string, integer (port number), or t (random port).  */
@@ -2933,7 +2999,7 @@
       QUIT;
       memset (&hints, 0, sizeof (hints));
       hints.ai_flags = 0;
-      hints.ai_family = NILP (Fplist_member (contact, QCfamily)) ? AF_UNSPEC : family;
+      hints.ai_family = family;
       hints.ai_socktype = socktype;
       hints.ai_protocol = 0;
       ret = getaddrinfo (SDATA (host), portstring, &hints, &res);
@@ -3522,6 +3588,21 @@
 #ifdef IFF_DYNAMIC
   { IFF_DYNAMIC,	"dynamic" },
 #endif
+#ifdef IFF_OACTIV
+  { IFF_OACTIV,		"oactiv" },	/* OpenBSD: transmission in progress */
+#endif
+#ifdef IFF_SIMPLEX
+  { IFF_SIMPLEX,	"simplex" },	/* OpenBSD: can't hear own transmissions */
+#endif
+#ifdef IFF_LINK0
+  { IFF_LINK0,		"link0" },	/* OpenBSD: per link layer defined bit */
+#endif
+#ifdef IFF_LINK1
+  { IFF_LINK1,		"link1" },	/* OpenBSD: per link layer defined bit */
+#endif
+#ifdef IFF_LINK2
+  { IFF_LINK2,		"link2" },	/* OpenBSD: per link layer defined bit */
+#endif
   { 0, 0 }
 };
 
@@ -3816,6 +3897,9 @@
   union u_sockaddr {
     struct sockaddr sa;
     struct sockaddr_in in;
+#ifdef AF_INET6
+    struct sockaddr_in6 in6;
+#endif
 #ifdef HAVE_LOCAL_SOCKETS
     struct sockaddr_un un;
 #endif
@@ -3872,6 +3956,26 @@
       }
       break;
 
+#ifdef AF_INET6
+    case AF_INET6:
+      {
+	Lisp_Object args[9];
+	uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr;
+	int i;
+	args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
+	for (i = 0; i < 8; i++)
+	  args[i+1] = make_number (ntohs(ip6[i]));
+	host = Fformat (9, args);
+	service = make_number (ntohs (saddr.in.sin_port));
+
+	args[0] = build_string (" <[%s]:%d>");
+	args[1] = host;
+	args[2] = service;
+	caller = Fformat (3, args);
+      }
+      break;
+#endif
+
 #ifdef HAVE_LOCAL_SOCKETS
     case AF_LOCAL:
 #endif
@@ -6724,6 +6828,10 @@
 #ifdef HAVE_LOCAL_SOCKETS
    ADD_SUBFEATURE (QCfamily, Qlocal);
 #endif
+   ADD_SUBFEATURE (QCfamily, Qipv4);
+#ifdef AF_INET6
+   ADD_SUBFEATURE (QCfamily, Qipv6);
+#endif
 #ifdef HAVE_GETSOCKNAME
    ADD_SUBFEATURE (QCservice, Qt);
 #endif
@@ -6782,6 +6890,12 @@
   staticpro (&Qlisten);
   Qlocal = intern ("local");
   staticpro (&Qlocal);
+  Qipv4 = intern ("ipv4");
+  staticpro (&Qipv4);
+#ifdef AF_INET6
+  Qipv6 = intern ("ipv6");
+  staticpro (&Qipv6);
+#endif
   Qdatagram = intern ("datagram");
   staticpro (&Qdatagram);