aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
diff options
context:
space:
mode:
authorRobert Pluim2019-11-15 11:11:30 +0100
committerRobert Pluim2019-11-26 08:46:13 +0100
commit650a514e996287106f9a9525b6f27068ec2a0cbf (patch)
tree188170aae76f32d894d8df1baa7f435fbfe99d88 /src/process.c
parent5c3d0cf7910afa6b3fbdba24ac5c5817f268eb0e (diff)
downloademacs-650a514e996287106f9a9525b6f27068ec2a0cbf.tar.gz
emacs-650a514e996287106f9a9525b6f27068ec2a0cbf.zip
Extend network-interface-list to return IPv6 and network info
Bug#38218 * src/process.c (Fnetwork_interface_list): Extend argument list to allow requesting full network info and/or IPv4/IPv6 info. (network_interface_list) [HAVE_GETIFADDRS]: Use getifaddrs to retrieve interface IP addresses. * src/process.h: Update prototype of network_interface_list. * src/w32.c (g_b_init_get_adapters_addresses): New init flag. (globals_of_w32): Initialize it. (GetAdaptersAddresses_Proc): New function typedef. (get_adapters_addresses): New wrapper function. (init_winsock): Load htonl and ntohl. (sys_htonl, sys_ntohl): New wrapper functions. (network_interface_list): Implement in terms of get_adapters_addresses. * nt/inc/sys/socket.h: Add sys_htonl and sys_ntohl prototypes. * etc/NEWS: Announce IPv4/IPv6 changes in network-interface-list. * doc/lispref/processes.texi (Misc Network): Document updated arglist and return values for network-interface-list.
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c158
1 files changed, 100 insertions, 58 deletions
diff --git a/src/process.c b/src/process.c
index 9158cfd347c..0f82682ae5f 100644
--- a/src/process.c
+++ b/src/process.c
@@ -4255,73 +4255,86 @@ usage: (make-network-process &rest ARGS) */)
4255} 4255}
4256 4256
4257 4257
4258#ifdef HAVE_NET_IF_H
4259 4258
4260#ifdef SIOCGIFCONF 4259#ifdef HAVE_GETIFADDRS
4261static Lisp_Object 4260static Lisp_Object
4262network_interface_list (void) 4261network_interface_list (bool full, unsigned short match)
4263{ 4262{
4264 struct ifconf ifconf; 4263 Lisp_Object res = Qnil;
4265 struct ifreq *ifreq; 4264 struct ifaddrs *ifap;
4266 void *buf = NULL;
4267 ptrdiff_t buf_size = 512;
4268 int s;
4269 Lisp_Object res;
4270 ptrdiff_t count;
4271 4265
4272 s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); 4266 if (getifaddrs (&ifap) == -1)
4273 if (s < 0)
4274 return Qnil; 4267 return Qnil;
4275 count = SPECPDL_INDEX ();
4276 record_unwind_protect_int (close_file_unwind, s);
4277 4268
4278 do 4269 for (struct ifaddrs *it = ifap; it != NULL; it = it->ifa_next)
4279 { 4270 {
4280 buf = xpalloc (buf, &buf_size, 1, INT_MAX, 1); 4271 int len;
4281 ifconf.ifc_buf = buf; 4272 int addr_len;
4282 ifconf.ifc_len = buf_size; 4273 uint32_t *maskp;
4283 if (ioctl (s, SIOCGIFCONF, &ifconf)) 4274 uint32_t *addrp;
4284 { 4275 Lisp_Object elt = Qnil;
4285 emacs_close (s);
4286 xfree (buf);
4287 return Qnil;
4288 }
4289 }
4290 while (ifconf.ifc_len == buf_size);
4291
4292 res = unbind_to (count, Qnil);
4293 ifreq = ifconf.ifc_req;
4294 while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len)
4295 {
4296 struct ifreq *ifq = ifreq;
4297#ifdef HAVE_STRUCT_IFREQ_IFR_ADDR_SA_LEN
4298#define SIZEOF_IFREQ(sif) \
4299 ((sif)->ifr_addr.sa_len < sizeof (struct sockaddr) \
4300 ? sizeof (*(sif)) : sizeof ((sif)->ifr_name) + (sif)->ifr_addr.sa_len)
4301 4276
4302 int len = SIZEOF_IFREQ (ifq); 4277 /* BSD can allegedly return interfaces with a NULL address. */
4303#else 4278 if (it->ifa_addr == NULL)
4304 int len = sizeof (*ifreq); 4279 continue;
4280 if (match && it->ifa_addr->sa_family != match)
4281 continue;
4282 if (it->ifa_addr->sa_family == AF_INET)
4283 {
4284 DECLARE_POINTER_ALIAS (sin1, struct sockaddr_in, it->ifa_netmask);
4285 maskp = (uint32_t *)&sin1->sin_addr;
4286 DECLARE_POINTER_ALIAS (sin2, struct sockaddr_in, it->ifa_addr);
4287 addrp = (uint32_t *)&sin2->sin_addr;
4288 len = sizeof (struct sockaddr_in);
4289 addr_len = 1;
4290 }
4291#ifdef AF_INET6
4292 else if (it->ifa_addr->sa_family == AF_INET6)
4293 {
4294 DECLARE_POINTER_ALIAS (sin6_1, struct sockaddr_in6, it->ifa_netmask);
4295 maskp = (uint32_t *) &sin6_1->sin6_addr;
4296 DECLARE_POINTER_ALIAS (sin6_2, struct sockaddr_in6, it->ifa_addr);
4297 addrp = (uint32_t *) &sin6_2->sin6_addr;
4298 len = sizeof (struct sockaddr_in6);
4299 addr_len = 4;
4300 }
4305#endif 4301#endif
4306 char namebuf[sizeof (ifq->ifr_name) + 1]; 4302 else
4307 ifreq = (struct ifreq *) ((char *) ifreq + len); 4303 continue;
4308 4304
4309 if (ifq->ifr_addr.sa_family != AF_INET) 4305 Lisp_Object addr = conv_sockaddr_to_lisp (it->ifa_addr, len);
4310 continue;
4311 4306
4312 memcpy (namebuf, ifq->ifr_name, sizeof (ifq->ifr_name)); 4307 if (full)
4313 namebuf[sizeof (ifq->ifr_name)] = 0; 4308 {
4314 res = Fcons (Fcons (build_string (namebuf), 4309 elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt);
4315 conv_sockaddr_to_lisp (&ifq->ifr_addr, 4310 /* There is an it->ifa_broadaddr field, but its contents are
4316 sizeof (struct sockaddr))), 4311 unreliable, so always calculate the broadcast address from
4317 res); 4312 the address and the netmask. */
4313 int i;
4314 uint32_t mask;
4315 for (i = 0; i < addr_len; i++)
4316 {
4317 mask = maskp[i];
4318 maskp[i] = (addrp[i] & mask) | ~mask;
4319 }
4320 elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt);
4321 elt = Fcons (addr, elt);
4322 }
4323 else
4324 {
4325 elt = addr;
4326 }
4327 res = Fcons (Fcons (build_string (it->ifa_name), elt), res);
4318 } 4328 }
4329#ifdef HAVE_FREEIFADDRS
4330 freeifaddrs (ifap);
4331#endif
4319 4332
4320 xfree (buf);
4321 return res; 4333 return res;
4322} 4334}
4323#endif /* SIOCGIFCONF */ 4335#endif /* HAVE_GETIFADDRS */
4324 4336
4337#ifdef HAVE_NET_IF_H
4325#if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS) 4338#if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS)
4326 4339
4327struct ifflag_def { 4340struct ifflag_def {
@@ -4550,17 +4563,46 @@ network_interface_info (Lisp_Object ifname)
4550#endif /* defined (HAVE_NET_IF_H) */ 4563#endif /* defined (HAVE_NET_IF_H) */
4551 4564
4552DEFUN ("network-interface-list", Fnetwork_interface_list, 4565DEFUN ("network-interface-list", Fnetwork_interface_list,
4553 Snetwork_interface_list, 0, 0, 0, 4566 Snetwork_interface_list, 0, 2, 0,
4554 doc: /* Return an alist of all network interfaces and their network address. 4567 doc: /* Return an alist of all network interfaces and their network address.
4555Each element is a cons, the car of which is a string containing the 4568Each element is cons of the form (IFNAME . IP) where IFNAME is a
4556interface name, and the cdr is the network address in internal 4569string containing the interface name, and IP is the network address in
4557format; see the description of ADDRESS in `make-network-process'. 4570internal format; see the description of ADDRESS in
4571`make-network-process'. The interface name is not guaranteed to be
4572unique.
4573
4574Optional parameter FULL non-nil means return all IP address info for
4575each interface. Each element is then a list of the form
4576 (IFNAME IP BCAST MASK)
4577where IFNAME is the interface name, IP the IP address,
4578BCAST the broadcast address, and MASK the network mask.
4579
4580Optional parameter FAMILY controls the type of addresses to return.
4581The default of nil means both IPv4 and IPv6, symbol `ipv4' means IPv4
4582only, symbol `ipv6' means IPv6 only.
4583
4584See also `network-interface-info', which is limited to IPv4 only.
4558 4585
4559If the information is not available, return nil. */) 4586If the information is not available, return nil. */)
4560 (void) 4587 (Lisp_Object full, Lisp_Object family)
4561{ 4588{
4562#if (defined HAVE_NET_IF_H && defined SIOCGIFCONF) || defined WINDOWSNT 4589#if defined HAVE_GETIFADDRS || defined WINDOWSNT
4563 return network_interface_list (); 4590 unsigned short match;
4591 bool full_info = false;
4592
4593 if (! NILP (full))
4594 full_info = true;
4595 if (NILP (family))
4596 match = 0;
4597 else if (EQ (family, Qipv4))
4598 match = AF_INET;
4599#ifdef AF_INET6
4600 else if (EQ (family, Qipv6))
4601 match = AF_INET6;
4602#endif
4603 else
4604 error ("Unsupported address family");
4605 return network_interface_list (full_info, match);
4564#else 4606#else
4565 return Qnil; 4607 return Qnil;
4566#endif 4608#endif