emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r114686: Implement network-interface-* functions for


From: Eli Zaretskii
Subject: [Emacs-diffs] trunk r114686: Implement network-interface-* functions for MS-Windows (bug #15610).
Date: Wed, 16 Oct 2013 15:44:43 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 114686
revision-id: address@hidden
parent: address@hidden
fixes bug: http://debbugs.gnu.org/15610
committer: Eli Zaretskii <address@hidden>
branch nick: trunk
timestamp: Wed 2013-10-16 18:44:02 +0300
message:
  Implement network-interface-* functions for MS-Windows (bug #15610).
  
   src/w32.c (network_interface_get_info, network_interface_list)
   (network_interface_info): New functions.
   (GetAdaptersInfo_Proc): New typedef.
   (get_adapters_info): New wrapper function.
   (globals_of_w32): Initialize g_b_init_get_adapters_info.
   src/process.h (network_interface_list, network_interface_info): New
   prototypes.
   src/process.c (conv_sockaddr_to_lisp): Now externally-visible.
   (Fnetwork_interface_list, Fnetwork_interface_info): Define for
   all systems.  Return non-nil for systems that HAVE_NET_IF_H and
   for WINDOWSNT.  Doc fix.
   (syms_of_process): Defsubr Snetwork_interface_list and
   Snetwork_interface_info unconditionally.
modified:
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/process.c                  process.c-20091113204419-o5vbwnq5f7feedwu-462
  src/process.h                  process.h-20091113204419-o5vbwnq5f7feedwu-272
  src/w32.c                      w32.c-20091113204419-o5vbwnq5f7feedwu-808
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2013-10-16 15:07:36 +0000
+++ b/src/ChangeLog     2013-10-16 15:44:02 +0000
@@ -1,5 +1,21 @@
 2013-10-16  Eli Zaretskii  <address@hidden>
 
+       * w32.c (network_interface_get_info, network_interface_list)
+       (network_interface_info): New functions.  (Bug#15610)
+       (GetAdaptersInfo_Proc): New typedef.
+       (get_adapters_info): New wrapper function.
+       (globals_of_w32): Initialize g_b_init_get_adapters_info.
+
+       * process.h (network_interface_list, network_interface_info): New
+       prototypes.
+
+       * process.c (conv_sockaddr_to_lisp): Now externally-visible.
+       (Fnetwork_interface_list, Fnetwork_interface_info): Define for
+       all systems.  Return non-nil for systems that HAVE_NET_IF_H and
+       for WINDOWSNT.  Doc fix.
+       (syms_of_process): Defsubr Snetwork_interface_list and
+       Snetwork_interface_info unconditionally.
+
        * menu.c (have_boxes): Fix redundant simulation of radio buttons
        in NS GUI sessions.  (Bug#15629)
 

=== modified file 'src/process.c'
--- a/src/process.c     2013-09-24 11:48:53 +0000
+++ b/src/process.c     2013-10-16 15:44:02 +0000
@@ -1958,7 +1958,7 @@
 /* Convert an internal struct sockaddr to a lisp object (vector or string).
    The address family of sa is not included in the result.  */
 
-static Lisp_Object
+Lisp_Object
 conv_sockaddr_to_lisp (struct sockaddr *sa, int len)
 {
   Lisp_Object address;
@@ -3504,16 +3504,45 @@
 }
 
 
-#if defined (HAVE_NET_IF_H)
-
-#ifdef SIOCGIFCONF
 DEFUN ("network-interface-list", Fnetwork_interface_list, 
Snetwork_interface_list, 0, 0, 0,
        doc: /* Return an alist of all network interfaces and their network 
address.
 Each element is a cons, the car of which is a string containing the
 interface name, and the cdr is the network address in internal
-format; see the description of ADDRESS in `make-network-process'.  */)
+format; see the description of ADDRESS in `make-network-process'.
+
+If the information is not available, return nil.  */)
   (void)
 {
+#if (defined (HAVE_NET_IF_H) && defined (SIOCGIFCONF)) || defined (WINDOWSNT)
+  return network_interface_list ();
+#else
+  return Qnil;
+#endif
+}
+
+DEFUN ("network-interface-info", Fnetwork_interface_info, 
Snetwork_interface_info, 1, 1, 0,
+       doc: /* Return information about network interface named IFNAME.
+The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS),
+where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address,
+NETMASK is the layer 3 network mask, HWADDR is the layer 2 address, and
+FLAGS is the current flags of the interface.
+
+Data that is unavailable is returned as nil.  */)
+  (Lisp_Object ifname)
+{
+#if (defined (HAVE_NET_IF_H) && (defined (SIOCGIFADDR) || defined 
(SIOCGIFHWADDR) || defined (SIOCGIFFLAGS))) || defined (WINDOWSNT)
+  return network_interface_info (ifname);
+#else
+  return Qnil;
+#endif
+}
+
+#if defined (HAVE_NET_IF_H)
+
+#ifdef SIOCGIFCONF
+Lisp_Object
+network_interface_list (void)
+{
   struct ifconf ifconf;
   struct ifreq *ifreq;
   void *buf = NULL;
@@ -3654,13 +3683,8 @@
   { 0, 0 }
 };
 
-DEFUN ("network-interface-info", Fnetwork_interface_info, 
Snetwork_interface_info, 1, 1, 0,
-       doc: /* Return information about network interface named IFNAME.
-The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS),
-where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address,
-NETMASK is the layer 3 network mask, HWADDR is the layer 2 address, and
-FLAGS is the current flags of the interface.  */)
-  (Lisp_Object ifname)
+Lisp_Object
+network_interface_info (Lisp_Object ifname)
 {
   struct ifreq rq;
   Lisp_Object res = Qnil;
@@ -3802,7 +3826,7 @@
 
   return unbind_to (count, any ? res : Qnil);
 }
-#endif
+#endif /* !SIOCGIFADDR && !SIOCGIFHWADDR && !SIOCGIFFLAGS */
 #endif /* defined (HAVE_NET_IF_H) */
 
 /* Turn off input and output for process PROC.  */
@@ -7293,14 +7317,8 @@
   defsubr (&Sset_network_process_option);
   defsubr (&Smake_network_process);
   defsubr (&Sformat_network_address);
-#if defined (HAVE_NET_IF_H)
-#ifdef SIOCGIFCONF
   defsubr (&Snetwork_interface_list);
-#endif
-#if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS)
   defsubr (&Snetwork_interface_info);
-#endif
-#endif /* defined (HAVE_NET_IF_H) */
 #ifdef DATAGRAM_SOCKETS
   defsubr (&Sprocess_datagram_address);
   defsubr (&Sset_process_datagram_address);

=== modified file 'src/process.h'
--- a/src/process.h     2013-09-20 15:34:36 +0000
+++ b/src/process.h     2013-10-16 15:44:02 +0000
@@ -240,4 +240,8 @@
 extern void catch_child_signal (void);
 #endif
 
+extern Lisp_Object network_interface_list (void);
+extern Lisp_Object network_interface_info (Lisp_Object);
+
+
 INLINE_HEADER_END

=== modified file 'src/w32.c'
--- a/src/w32.c 2013-10-14 16:23:10 +0000
+++ b/src/w32.c 2013-10-16 15:44:02 +0000
@@ -218,6 +218,8 @@
 #undef recvfrom
 #undef sendto
 
+#include <iphlpapi.h>  /* should be after winsock2.h */
+
 #include "w32.h"
 #include <dirent.h>
 #include "w32common.h"
@@ -296,6 +298,7 @@
 static BOOL g_b_init_convert_sddl_to_sd;
 static BOOL g_b_init_is_valid_security_descriptor;
 static BOOL g_b_init_set_file_security;
+static BOOL g_b_init_get_adapters_info;
 
 /*
   BEGIN: Wrapper functions around OpenProcessToken
@@ -438,6 +441,9 @@
     LPTSTR  *StringSecurityDescriptor,
     PULONG StringSecurityDescriptorLen);
 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
+typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
+    PIP_ADAPTER_INFO pAdapterInfo,
+    PULONG pOutBufLen);
 
   /* ** A utility function ** */
 static BOOL
@@ -1130,6 +1136,28 @@
   return retval;
 }
 
+static DWORD WINAPI
+get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
+{
+  static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
+  HMODULE hm_iphlpapi = NULL;
+
+  if (is_windows_9x () == TRUE)
+    return ERROR_NOT_SUPPORTED;
+
+  if (g_b_init_get_adapters_info == 0)
+    {
+      g_b_init_get_adapters_info = 1;
+      hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
+      if (hm_iphlpapi)
+       s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
+         GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
+    }
+  if (s_pfn_Get_Adapters_Info == NULL)
+    return ERROR_NOT_SUPPORTED;
+  return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
+}
+
 
 
 /* Return 1 if P is a valid pointer to an object of size SIZE.  Return
@@ -7434,6 +7462,269 @@
   return nchars;
 }
 
+
+/* Emulation of SIOCGIFCONF and getifaddrs, see process.c.  */
+
+extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
+
+/* Return information about network interface IFNAME, or about all
+   interfaces (if IFNAME is nil).  */
+static Lisp_Object
+network_interface_get_info (Lisp_Object ifname)
+{
+  ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
+  IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
+  DWORD retval = get_adapters_info (ainfo, &ainfo_len);
+  Lisp_Object res = Qnil;
+
+  if (retval == ERROR_BUFFER_OVERFLOW)
+    {
+      ainfo = xrealloc (ainfo, ainfo_len);
+      retval = get_adapters_info (ainfo, &ainfo_len);
+    }
+
+  if (retval == ERROR_SUCCESS)
+    {
+      int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
+      int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
+      int if_num;
+      struct sockaddr_in sa;
+
+      /* For the below, we need some winsock functions, so make sure
+        the winsock DLL is loaded.  If we cannot successfully load
+        it, they will have no use of the information we provide,
+        anyway, so punt.  */
+      if (!winsock_lib && !init_winsock (1))
+       goto done;
+
+      for (adapter = ainfo; adapter; adapter = adapter->Next)
+       {
+         char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
+         u_long ip_addr;
+         /* Present Unix-compatible interface names, instead of the
+            Windows names, which are really GUIDs not readable by
+            humans.  */
+         static const char *ifmt[] = {
+           "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
+           "lo", "ifx%d"
+         };
+         enum {
+           NONE = -1,
+           ETHERNET = 0,
+           TOKENRING = 1,
+           FDDI = 2,
+           PPP = 3,
+           SLIP = 4,
+           WLAN = 5,
+           LOOPBACK = 6,
+           OTHER_IF = 7
+         } ifmt_idx;
+
+         switch (adapter->Type)
+           {
+           case MIB_IF_TYPE_ETHERNET:
+             /* Windows before Vista reports wireless adapters as
+                Ethernet.  Work around by looking at the Description
+                string.  */
+             if (strstr (adapter->Description, "Wireless "))
+               {
+                 ifmt_idx = WLAN;
+                 if_num = wlan_count++;
+               }
+             else
+               {
+                 ifmt_idx = ETHERNET;
+                 if_num = eth_count++;
+               }
+             break;
+           case MIB_IF_TYPE_TOKENRING:
+             ifmt_idx = TOKENRING;
+             if_num = tr_count++;
+             break;
+           case MIB_IF_TYPE_FDDI:
+             ifmt_idx = FDDI;
+             if_num = fddi_count++;
+             break;
+           case MIB_IF_TYPE_PPP:
+             ifmt_idx = PPP;
+             if_num = ppp_count++;
+             break;
+           case MIB_IF_TYPE_SLIP:
+             ifmt_idx = SLIP;
+             if_num = sl_count++;
+             break;
+           case IF_TYPE_IEEE80211:
+             ifmt_idx = WLAN;
+             if_num = wlan_count++;
+             break;
+           case MIB_IF_TYPE_LOOPBACK:
+             if (lo_count < 0)
+               {
+                 ifmt_idx = LOOPBACK;
+                 if_num = lo_count++;
+               }
+             else
+               ifmt_idx = NONE;
+             break;
+           default:
+             ifmt_idx = OTHER_IF;
+             if_num = ifx_count++;
+             break;
+           }
+         if (ifmt_idx == NONE)
+           continue;
+         sprintf (namebuf, ifmt[ifmt_idx], if_num);
+
+         sa.sin_family = AF_INET;
+         ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
+         if (ip_addr == INADDR_NONE)
+           {
+             /* Bogus address, skip this interface.  */
+             continue;
+           }
+         sa.sin_addr.s_addr = ip_addr;
+         sa.sin_port = 0;
+         if (NILP (ifname))
+           res = Fcons (Fcons (build_string (namebuf),
+                               conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
+                                                      sizeof (struct 
sockaddr))),
+                        res);
+         else if (strcmp (namebuf, SSDATA (ifname)) == 0)
+           {
+             Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
+             register struct Lisp_Vector *p = XVECTOR (hwaddr);
+             Lisp_Object flags = Qnil;
+             int n;
+             u_long net_mask;
+
+             /* Flags.  We guess most of them by type, since the
+                Windows flags are different and hard to get by.  */
+             flags = Fcons (intern ("up"), flags);
+             if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
+               {
+                 flags = Fcons (intern ("broadcast"), flags);
+                 flags = Fcons (intern ("multicast"), flags);
+               }
+             flags = Fcons (intern ("running"), flags);
+             if (ifmt_idx == PPP)
+               {
+                 flags = Fcons (intern ("pointopoint"), flags);
+                 flags = Fcons (intern ("noarp"), flags);
+               }
+             if (adapter->HaveWins)
+               flags = Fcons (intern ("WINS"), flags);
+             if (adapter->DhcpEnabled)
+               flags = Fcons (intern ("dynamic"), flags);
+
+             res = Fcons (flags, res);
+
+             /* Hardware address and its family.  */
+             for (n = 0; n < adapter->AddressLength; n++)
+               p->u.contents[n] = make_number ((int) adapter->Address[n]);
+             /* Windows does not support AF_LINK or AF_PACKET family
+                of addresses.  Use an arbitrary family number that is
+                identical to what GNU/Linux returns.  */
+             res = Fcons (Fcons (make_number (1), hwaddr), res);
+
+             /* Network mask.  */
+             sa.sin_family = AF_INET;
+             net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
+             if (net_mask != INADDR_NONE)
+               {
+                 sa.sin_addr.s_addr = net_mask;
+                 sa.sin_port = 0;
+                 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+                                                     sizeof (struct sockaddr)),
+                              res);
+               }
+             else
+               res = Fcons (Qnil, res);
+
+             sa.sin_family = AF_INET;
+             if (ip_addr != INADDR_NONE)
+               {
+                 /* Broadcast address is only reported by
+                    GetAdaptersAddresses, which is of limited
+                    availability.  Generate it on our own.  */
+                 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
+
+                 sa.sin_addr.s_addr = bcast_addr;
+                 sa.sin_port = 0;
+                 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+                                                     sizeof (struct sockaddr)),
+                              res);
+
+                 /* IP address.  */
+                 sa.sin_addr.s_addr = ip_addr;
+                 sa.sin_port = 0;
+                 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+                                                     sizeof (struct sockaddr)),
+                              res);
+               }
+             else
+               res = Fcons (Qnil, Fcons (Qnil, res));
+           }
+       }
+      /* GetAdaptersInfo is documented to not report loopback
+        interfaces, so we generate one out of thin air.  */
+      if (!lo_count)
+       {
+         sa.sin_family = AF_INET;
+         sa.sin_port = 0;
+         if (NILP (ifname))
+           {
+             sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
+             res = Fcons (Fcons (build_string ("lo"),
+                                 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
+                                                        sizeof (struct 
sockaddr))),
+                          res);
+           }
+         else if (strcmp (SSDATA (ifname), "lo") == 0)
+           {
+             res = Fcons (Fcons (intern ("running"),
+                                 Fcons (intern ("loopback"),
+                                        Fcons (intern ("up"), Qnil))), Qnil);
+             /* 772 is what 3 different GNU/Linux systems report for
+                the loopback interface.  */
+             res = Fcons (Fcons (make_number (772),
+                                 Fmake_vector (make_number (6),
+                                               make_number (0))),
+                          res);
+             sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
+             res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+                                                 sizeof (struct sockaddr)),
+                          res);
+             sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
+             res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+                                                 sizeof (struct sockaddr)),
+                          res);
+             sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
+             res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+                                                 sizeof (struct sockaddr)),
+                          res);
+           }
+
+       }
+    }
+
+ done:
+  xfree (ainfo);
+  return res;
+}
+
+Lisp_Object
+network_interface_list (void)
+{
+  return network_interface_get_info (Qnil);
+}
+
+Lisp_Object
+network_interface_info (Lisp_Object ifname)
+{
+  return network_interface_get_info (ifname);
+}
+
+
 /* The Windows CRT functions are "optimized for speed", so they don't
    check for timezone and DST changes if they were last called less
    than 1 minute ago (see http://support.microsoft.com/kb/821231).  So
@@ -7735,6 +8026,7 @@
   g_b_init_convert_sddl_to_sd = 0;
   g_b_init_is_valid_security_descriptor = 0;
   g_b_init_set_file_security = 0;
+  g_b_init_get_adapters_info = 0;
   num_of_processors = 0;
   /* The following sets a handler for shutdown notifications for
      console apps. This actually applies to Emacs in both console and


reply via email to

[Prev in Thread] Current Thread [Next in Thread]