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 /lib-src/pop.c | |
| 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.
Diffstat (limited to 'lib-src/pop.c')
| -rw-r--r-- | lib-src/pop.c | 151 |
1 files changed, 150 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 */ |