diff options
| author | Eli Zaretskii | 2016-03-05 12:12:58 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2016-03-05 12:12:58 +0200 |
| commit | bc96f6e827ba079006ae87914395942fc79f3f26 (patch) | |
| tree | c980a478b0229057db165de1fec6a40fc56b1f0b | |
| parent | ac9a931d595dd83ebac61c6c9cf7388985fee277 (diff) | |
| download | emacs-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.c | 151 | ||||
| -rw-r--r-- | nt/inc/sys/socket.h | 5 | ||||
| -rw-r--r-- | nt/mingw-cfg.site | 4 | ||||
| -rw-r--r-- | src/w32.c | 125 |
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 | ||
| 39 | int sys_getaddrinfo (const char * node, const char * service, | ||
| 40 | const struct addrinfo * hints, struct addrinfo ** res); | ||
| 41 | void 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 | |||
| 1598 | int (WINAPI *pfn_getaddrinfo) (const char *, const char *, | ||
| 1599 | const struct addrinfo *, struct addrinfo **); | ||
| 1600 | void (WINAPI *pfn_freeaddrinfo) (struct addrinfo *); | ||
| 1601 | |||
| 1602 | static int | ||
| 1603 | load_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 | |||
| 1633 | int | ||
| 1634 | sys_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 | |||
| 1714 | void | ||
| 1715 | sys_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 | ||
| 102 | int sys_socket(int af, int type, int protocol); | 104 | int sys_socket(int af, int type, int protocol); |
| 103 | int sys_bind (int s, const struct sockaddr *addr, int namelen); | 105 | int 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); |
| 119 | int sys_sendto (int s, const char * buf, int len, int flags, | 121 | int 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); |
| 123 | int sys_getaddrinfo (const char * node, const char * service, | ||
| 124 | const struct addrinfo * hints, struct addrinfo ** res); | ||
| 125 | void 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 | |||
| 68 | ac_cv_func_getpeername=yes | 68 | ac_cv_func_getpeername=yes |
| 69 | # Implemented as sys_socket in w32.c | 69 | # Implemented as sys_socket in w32.c |
| 70 | ac_cv_func_socket=yes | 70 | ac_cv_func_socket=yes |
| 71 | # Implemented as sys_getaddrinfo in w32.c | ||
| 72 | ac_cv_func_getaddrinfo=yes | ||
| 73 | # Implemented as an inline function in ws2tcpip.h | ||
| 74 | ac_cv_func_gai_strerror=yes | ||
| 71 | # Implemented in w32.c | 75 | # Implemented in w32.c |
| 72 | ac_cv_func_mkostemp=yes | 76 | ac_cv_func_mkostemp=yes |
| 73 | ac_cv_func_readlink=yes | 77 | ac_cv_func_readlink=yes |
| @@ -7202,6 +7202,10 @@ int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags, | |||
| 7202 | int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags, | 7202 | int (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 | ||
| 7205 | int (PASCAL *pfn_getaddrinfo) (const char *, const char *, | ||
| 7206 | const struct addrinfo *, struct addrinfo **); | ||
| 7207 | void (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. */ |
| 7206 | BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags); | 7210 | BOOL (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 | ||
| 7736 | int | 7750 | int |
| 7751 | sys_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 | |||
| 7842 | void | ||
| 7843 | sys_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 | |||
| 7861 | int | ||
| 7737 | sys_shutdown (int s, int how) | 7862 | sys_shutdown (int s, int how) |
| 7738 | { | 7863 | { |
| 7739 | if (winsock_lib == NULL) | 7864 | if (winsock_lib == NULL) |