aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2016-03-05 12:12:58 +0200
committerEli Zaretskii2016-03-05 12:12:58 +0200
commitbc96f6e827ba079006ae87914395942fc79f3f26 (patch)
treec980a478b0229057db165de1fec6a40fc56b1f0b
parentac9a931d595dd83ebac61c6c9cf7388985fee277 (diff)
downloademacs-bc96f6e827ba079006ae87914395942fc79f3f26.tar.gz
emacs-bc96f6e827ba079006ae87914395942fc79f3f26.zip
Implement getaddrinfo fallback for MS-Windows
See http://lists.gnu.org/archive/html/emacs-devel/2016-02/msg01602.html for more details. * nt/mingw-cfg.site (ac_cv_func_getaddrinfo) (ac_cv_func_gai_strerror): Set to "yes", as the configure script's test program is not smart enough to auto-detect these. * nt/inc/sys/socket.h (getaddrinfo, freeaddrinfo): Redirect to sys_getaddrinfo and sys_freeaddrinfo. Provide prototypes for sys_getaddrinfo and sys_freeaddrinfo. * src/w32.c (init_winsock): Try loading getaddrinfo and freeaddrinfo from ws2_32.dll. (sys_getaddrinfo, sys_freeaddrinfo): New functions. * lib-src/pop.c [WINDOWSNT]: Include winsock2.h, not winsock.h, and also ws2tcpip.h. (getaddrinfo, freeaddrinfo) [WINDOWSNT]: Redirect to sys_getaddrinfo and sys_freeaddrinfo, respectively. (load_ws2, sys_getaddrinfo, sys_freeaddrinfo) [WINDOWSNT]: New functions.
-rw-r--r--lib-src/pop.c151
-rw-r--r--nt/inc/sys/socket.h5
-rw-r--r--nt/mingw-cfg.site4
-rw-r--r--src/w32.c125
4 files changed, 284 insertions, 1 deletions
diff --git a/lib-src/pop.c b/lib-src/pop.c
index 812bd4ca24c..21d721546b7 100644
--- a/lib-src/pop.c
+++ b/lib-src/pop.c
@@ -28,7 +28,17 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
28#include <sys/types.h> 28#include <sys/types.h>
29#ifdef WINDOWSNT 29#ifdef WINDOWSNT
30#include "ntlib.h" 30#include "ntlib.h"
31#include <winsock.h> 31#undef _WIN32_WINNT
32#define _WIN32_WINNT 0x0501 /* for getaddrinfo stuff */
33#include <winsock2.h>
34#include <ws2tcpip.h>
35#undef getaddrinfo
36#define getaddrinfo sys_getaddrinfo
37#undef freeaddrinfo
38#define freeaddrinfo sys_freeaddrinfo
39int sys_getaddrinfo (const char * node, const char * service,
40 const struct addrinfo * hints, struct addrinfo ** res);
41void sys_freeaddrinfo (struct addrinfo * ai);
32#undef SOCKET_ERROR 42#undef SOCKET_ERROR
33#define RECV(s,buf,len,flags) recv (s,buf,len,flags) 43#define RECV(s,buf,len,flags) recv (s,buf,len,flags)
34#define SEND(s,buf,len,flags) send (s,buf,len,flags) 44#define SEND(s,buf,len,flags) send (s,buf,len,flags)
@@ -1581,4 +1591,143 @@ find_crlf (char *in_string, int len)
1581 return (0); 1591 return (0);
1582} 1592}
1583 1593
1594#ifdef WINDOWSNT
1595/* The following 2 functions are only available since XP, so we load
1596 them dynamically and provide fallbacks. */
1597
1598int (WINAPI *pfn_getaddrinfo) (const char *, const char *,
1599 const struct addrinfo *, struct addrinfo **);
1600void (WINAPI *pfn_freeaddrinfo) (struct addrinfo *);
1601
1602static int
1603load_ws2 (void)
1604{
1605 static int ws2_loaded = 0;
1606
1607 if (!ws2_loaded)
1608 {
1609 HANDLE ws2_lib = LoadLibrary ("Ws2_32.dll");
1610
1611 if (ws2_lib != NULL)
1612 {
1613 ws2_loaded = 1;
1614 pfn_getaddrinfo = (void *) GetProcAddress (ws2_lib, "getaddrinfo");
1615 pfn_freeaddrinfo = (void *) GetProcAddress (ws2_lib, "freeaddrinfo");
1616 /* Paranoia: these two functions should go together, so if
1617 one is absent, we cannot use the other. */
1618 if (pfn_getaddrinfo == NULL)
1619 pfn_freeaddrinfo = NULL;
1620 else if (pfn_freeaddrinfo == NULL)
1621 pfn_getaddrinfo = NULL;
1622 }
1623 }
1624 if (!ws2_loaded)
1625 {
1626 errno = ENETDOWN;
1627 return -1;
1628 }
1629 return 0;
1630}
1631
1632
1633int
1634sys_getaddrinfo (const char *node, const char *service,
1635 const struct addrinfo *hints, struct addrinfo **res)
1636{
1637 int rc;
1638
1639 if (load_ws2 () != 0)
1640 {
1641 errno = ENETDOWN;
1642 return WSANO_RECOVERY;
1643 }
1644
1645 if (pfn_getaddrinfo)
1646 rc = pfn_getaddrinfo (node, service, hints, res);
1647 else
1648 {
1649 int port = 0;
1650 struct hostent *host_info;
1651 struct gai_storage {
1652 struct addrinfo addrinfo;
1653 struct sockaddr_in sockaddr_in;
1654 } *gai_storage;
1655
1656 /* We don't support any flags besides AI_CANONNAME. */
1657 if (hints && (hints->ai_flags & ~(AI_CANONNAME)) != 0)
1658 return WSAEINVAL;
1659 /* NODE cannot be NULL, since pop.c has fallbacks for that. */
1660 if (!node)
1661 return WSAHOST_NOT_FOUND;
1662
1663 if (service)
1664 {
1665 const char *protocol =
1666 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
1667 struct servent *srv = getservbyname (service, protocol);
1668
1669 if (srv)
1670 port = srv->s_port;
1671 else
1672 return WSAHOST_NOT_FOUND;
1673 }
1674
1675 gai_storage = calloc (1, sizeof *gai_storage);
1676 gai_storage->sockaddr_in.sin_port = port;
1677 host_info = gethostbyname (node);
1678 if (host_info)
1679 {
1680 memcpy (&gai_storage->sockaddr_in.sin_addr,
1681 host_info->h_addr, host_info->h_length);
1682 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
1683 }
1684 else
1685 {
1686 free (gai_storage);
1687 return WSAHOST_NOT_FOUND;
1688 }
1689
1690 gai_storage->addrinfo.ai_addr =
1691 (struct sockaddr *)&gai_storage->sockaddr_in;
1692 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
1693 if (hints && (hints->ai_flags & AI_CANONNAME) != 0)
1694 {
1695 gai_storage->addrinfo.ai_canonname = strdup (host_info->h_name);
1696 if (!gai_storage->addrinfo.ai_canonname)
1697 {
1698 free (gai_storage);
1699 return WSA_NOT_ENOUGH_MEMORY;
1700 }
1701 }
1702 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
1703 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
1704 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
1705 gai_storage->addrinfo.ai_next = NULL;
1706
1707 *res = &gai_storage->addrinfo;
1708 rc = 0;
1709 }
1710
1711 return rc;
1712}
1713
1714void
1715sys_freeaddrinfo (struct addrinfo *ai)
1716{
1717 if (load_ws2 () != 0)
1718 {
1719 errno = ENETDOWN;
1720 return;
1721 }
1722
1723 if (pfn_freeaddrinfo)
1724 pfn_freeaddrinfo (ai);
1725 else
1726 {
1727 if (ai->ai_canonname)
1728 free (ai->ai_canonname);
1729 free (ai);
1730 }
1731}
1732#endif /* WINDOWSNT */
1584#endif /* MAIL_USE_POP */ 1733#endif /* MAIL_USE_POP */
diff --git a/nt/inc/sys/socket.h b/nt/inc/sys/socket.h
index d7ed92d6158..2c72a78b0f4 100644
--- a/nt/inc/sys/socket.h
+++ b/nt/inc/sys/socket.h
@@ -98,6 +98,8 @@ typedef unsigned short uint16_t;
98#define accept sys_accept 98#define accept sys_accept
99#define recvfrom sys_recvfrom 99#define recvfrom sys_recvfrom
100#define sendto sys_sendto 100#define sendto sys_sendto
101#define getaddrinfo sys_getaddrinfo
102#define freeaddrinfo sys_freeaddrinfo
101 103
102int sys_socket(int af, int type, int protocol); 104int sys_socket(int af, int type, int protocol);
103int sys_bind (int s, const struct sockaddr *addr, int namelen); 105int sys_bind (int s, const struct sockaddr *addr, int namelen);
@@ -118,6 +120,9 @@ int sys_recvfrom (int s, char *buf, int len, int flags,
118 struct sockaddr *from, int * fromlen); 120 struct sockaddr *from, int * fromlen);
119int sys_sendto (int s, const char * buf, int len, int flags, 121int sys_sendto (int s, const char * buf, int len, int flags,
120 const struct sockaddr *to, int tolen); 122 const struct sockaddr *to, int tolen);
123int sys_getaddrinfo (const char * node, const char * service,
124 const struct addrinfo * hints, struct addrinfo ** res);
125void sys_freeaddrinfo (struct addrinfo * ai);
121 126
122/* In addition to wrappers for the winsock functions, we also provide 127/* In addition to wrappers for the winsock functions, we also provide
123 an fcntl function, for setting sockets to non-blocking mode. */ 128 an fcntl function, for setting sockets to non-blocking mode. */
diff --git a/nt/mingw-cfg.site b/nt/mingw-cfg.site
index 05034fedd48..ff9df60c275 100644
--- a/nt/mingw-cfg.site
+++ b/nt/mingw-cfg.site
@@ -68,6 +68,10 @@ ac_cv_func_getsockname=yes
68ac_cv_func_getpeername=yes 68ac_cv_func_getpeername=yes
69# Implemented as sys_socket in w32.c 69# Implemented as sys_socket in w32.c
70ac_cv_func_socket=yes 70ac_cv_func_socket=yes
71# Implemented as sys_getaddrinfo in w32.c
72ac_cv_func_getaddrinfo=yes
73# Implemented as an inline function in ws2tcpip.h
74ac_cv_func_gai_strerror=yes
71# Implemented in w32.c 75# Implemented in w32.c
72ac_cv_func_mkostemp=yes 76ac_cv_func_mkostemp=yes
73ac_cv_func_readlink=yes 77ac_cv_func_readlink=yes
diff --git a/src/w32.c b/src/w32.c
index 998f696bdf8..ccf7cc335ce 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -7202,6 +7202,10 @@ int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7202int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags, 7202int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7203 const struct sockaddr * to, int tolen); 7203 const struct sockaddr * to, int tolen);
7204 7204
7205int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7206 const struct addrinfo *, struct addrinfo **);
7207void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7208
7205/* SetHandleInformation is only needed to make sockets non-inheritable. */ 7209/* SetHandleInformation is only needed to make sockets non-inheritable. */
7206BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags); 7210BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7207#ifndef HANDLE_FLAG_INHERIT 7211#ifndef HANDLE_FLAG_INHERIT
@@ -7284,6 +7288,16 @@ init_winsock (int load_now)
7284 LOAD_PROC (sendto); 7288 LOAD_PROC (sendto);
7285#undef LOAD_PROC 7289#undef LOAD_PROC
7286 7290
7291 /* Try loading functions not available before XP. */
7292 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7293 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7294 /* Paranoia: these two functions should go together, so if one
7295 is absent, we cannot use the other. */
7296 if (pfn_getaddrinfo == NULL)
7297 pfn_freeaddrinfo = NULL;
7298 else if (pfn_freeaddrinfo == NULL)
7299 pfn_getaddrinfo = NULL;
7300
7287 /* specify version 1.1 of winsock */ 7301 /* specify version 1.1 of winsock */
7288 if (pfn_WSAStartup (0x101, &winsockData) == 0) 7302 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7289 { 7303 {
@@ -7734,6 +7748,117 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7734} 7748}
7735 7749
7736int 7750int
7751sys_getaddrinfo (const char *node, const char *service,
7752 const struct addrinfo *hints, struct addrinfo **res)
7753{
7754 int rc;
7755
7756 if (winsock_lib == NULL)
7757 {
7758 errno = ENETDOWN;
7759 return SOCKET_ERROR;
7760 }
7761
7762 check_errno ();
7763 if (pfn_getaddrinfo)
7764 rc = pfn_getaddrinfo (node, service, hints, res);
7765 else
7766 {
7767 int port = 0;
7768 struct hostent *host_info;
7769 struct gai_storage {
7770 struct addrinfo addrinfo;
7771 struct sockaddr_in sockaddr_in;
7772 } *gai_storage;
7773
7774 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7775 if (hints && hints->ai_flags != 0)
7776 return WSAEINVAL;
7777 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7778 if (!node)
7779 return WSAHOST_NOT_FOUND;
7780
7781 if (service)
7782 {
7783 const char *protocol =
7784 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7785 struct servent *srv = sys_getservbyname (service, protocol);
7786
7787 if (srv)
7788 port = srv->s_port;
7789 else if (*service >= '0' && *service <= '9')
7790 {
7791 char *endp;
7792
7793 port = strtoul (service, &endp, 10);
7794 if (*endp || port > 65536)
7795 return WSAHOST_NOT_FOUND;
7796 port = sys_htons ((unsigned short) port);
7797 }
7798 else
7799 return WSAHOST_NOT_FOUND;
7800 }
7801
7802 gai_storage = xzalloc (sizeof *gai_storage);
7803 gai_storage->sockaddr_in.sin_port = port;
7804 host_info = sys_gethostbyname (node);
7805 if (host_info)
7806 {
7807 memcpy (&gai_storage->sockaddr_in.sin_addr,
7808 host_info->h_addr, host_info->h_length);
7809 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7810 }
7811 else
7812 {
7813 /* Attempt to interpret host as numeric inet address. */
7814 unsigned long numeric_addr = sys_inet_addr (node);
7815
7816 if (numeric_addr == -1)
7817 {
7818 free (gai_storage);
7819 return WSAHOST_NOT_FOUND;
7820 }
7821
7822 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7823 sizeof (gai_storage->sockaddr_in.sin_addr));
7824 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7825 }
7826
7827 gai_storage->addrinfo.ai_addr =
7828 (struct sockaddr *)&gai_storage->sockaddr_in;
7829 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7830 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7831 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7832 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7833 gai_storage->addrinfo.ai_next = NULL;
7834
7835 *res = &gai_storage->addrinfo;
7836 rc = 0;
7837 }
7838
7839 return rc;
7840}
7841
7842void
7843sys_freeaddrinfo (struct addrinfo *ai)
7844{
7845 if (winsock_lib == NULL)
7846 {
7847 errno = ENETDOWN;
7848 return;
7849 }
7850
7851 check_errno ();
7852 if (pfn_freeaddrinfo)
7853 pfn_freeaddrinfo (ai);
7854 else
7855 {
7856 eassert (ai->ai_next == NULL);
7857 xfree (ai);
7858 }
7859}
7860
7861int
7737sys_shutdown (int s, int how) 7862sys_shutdown (int s, int how)
7738{ 7863{
7739 if (winsock_lib == NULL) 7864 if (winsock_lib == NULL)