Commit e1652a86 authored by Kim F. Storm's avatar Kim F. Storm

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.
parent dd878ee1
......@@ -140,7 +140,10 @@ Boston, MA 02110-1301, USA. */
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 @@ a socket connection. */)
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 @@ IP address. Returns nil if format of ADDRESS is invalid. */)
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 @@ IP address. Returns nil if format of ADDRESS is invalid. */)
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 @@ conv_sockaddr_to_lisp (sa, len)
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 @@ get_lisp_to_sockaddr_size (address, familyp)
*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 @@ conv_lisp_to_sockaddr (family, address, sa, len)
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 @@ a random port number is selected for the server.
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 @@ usage: (make-network-process &rest ARGS) */)
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 @@ usage: (make-network-process &rest ARGS) */)
/* :family FAMILY -- nil (for Inet), local, or integer. */
tem = Fplist_get (contact, QCfamily);
if (INTEGERP (tem))
family = XINT (tem);
else
if (NILP (tem))
{
if (NILP (tem))
family = AF_INET;
#ifdef HAVE_LOCAL_SOCKETS
else if (EQ (tem, Qlocal))
family = AF_LOCAL;
#ifdef HAVE_GETADDRINFO
family = AF_UNSPEC;
#else
family = AF_INET;
#endif
}
if (family < 0)
#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
error ("Unknown address family");
ai.ai_family = family;
/* :service SERVICE -- string, integer (port number), or t (random port). */
......@@ -2933,7 +2999,7 @@ usage: (make-network-process &rest ARGS) */)
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);
......@@ -3521,6 +3587,21 @@ static struct ifflag_def ifflag_table[] = {
#endif
#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 @@ server_accept_connection (server, channel)
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 @@ server_accept_connection (server, channel)
}
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
......@@ -6723,6 +6827,10 @@ init_process ()
#endif
#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);
......@@ -6782,6 +6890,12 @@ syms_of_process ()
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment