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.
This commit is contained in:
parent
ac9a931d59
commit
bc96f6e827
4 changed files with 284 additions and 1 deletions
151
lib-src/pop.c
151
lib-src/pop.c
|
@ -28,7 +28,17 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#include <sys/types.h>
|
||||
#ifdef WINDOWSNT
|
||||
#include "ntlib.h"
|
||||
#include <winsock.h>
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501 /* for getaddrinfo stuff */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#undef getaddrinfo
|
||||
#define getaddrinfo sys_getaddrinfo
|
||||
#undef freeaddrinfo
|
||||
#define freeaddrinfo sys_freeaddrinfo
|
||||
int sys_getaddrinfo (const char * node, const char * service,
|
||||
const struct addrinfo * hints, struct addrinfo ** res);
|
||||
void sys_freeaddrinfo (struct addrinfo * ai);
|
||||
#undef SOCKET_ERROR
|
||||
#define RECV(s,buf,len,flags) recv (s,buf,len,flags)
|
||||
#define SEND(s,buf,len,flags) send (s,buf,len,flags)
|
||||
|
@ -1581,4 +1591,143 @@ find_crlf (char *in_string, int len)
|
|||
return (0);
|
||||
}
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
/* The following 2 functions are only available since XP, so we load
|
||||
them dynamically and provide fallbacks. */
|
||||
|
||||
int (WINAPI *pfn_getaddrinfo) (const char *, const char *,
|
||||
const struct addrinfo *, struct addrinfo **);
|
||||
void (WINAPI *pfn_freeaddrinfo) (struct addrinfo *);
|
||||
|
||||
static int
|
||||
load_ws2 (void)
|
||||
{
|
||||
static int ws2_loaded = 0;
|
||||
|
||||
if (!ws2_loaded)
|
||||
{
|
||||
HANDLE ws2_lib = LoadLibrary ("Ws2_32.dll");
|
||||
|
||||
if (ws2_lib != NULL)
|
||||
{
|
||||
ws2_loaded = 1;
|
||||
pfn_getaddrinfo = (void *) GetProcAddress (ws2_lib, "getaddrinfo");
|
||||
pfn_freeaddrinfo = (void *) GetProcAddress (ws2_lib, "freeaddrinfo");
|
||||
/* Paranoia: these two functions should go together, so if
|
||||
one is absent, we cannot use the other. */
|
||||
if (pfn_getaddrinfo == NULL)
|
||||
pfn_freeaddrinfo = NULL;
|
||||
else if (pfn_freeaddrinfo == NULL)
|
||||
pfn_getaddrinfo = NULL;
|
||||
}
|
||||
}
|
||||
if (!ws2_loaded)
|
||||
{
|
||||
errno = ENETDOWN;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sys_getaddrinfo (const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (load_ws2 () != 0)
|
||||
{
|
||||
errno = ENETDOWN;
|
||||
return WSANO_RECOVERY;
|
||||
}
|
||||
|
||||
if (pfn_getaddrinfo)
|
||||
rc = pfn_getaddrinfo (node, service, hints, res);
|
||||
else
|
||||
{
|
||||
int port = 0;
|
||||
struct hostent *host_info;
|
||||
struct gai_storage {
|
||||
struct addrinfo addrinfo;
|
||||
struct sockaddr_in sockaddr_in;
|
||||
} *gai_storage;
|
||||
|
||||
/* We don't support any flags besides AI_CANONNAME. */
|
||||
if (hints && (hints->ai_flags & ~(AI_CANONNAME)) != 0)
|
||||
return WSAEINVAL;
|
||||
/* NODE cannot be NULL, since pop.c has fallbacks for that. */
|
||||
if (!node)
|
||||
return WSAHOST_NOT_FOUND;
|
||||
|
||||
if (service)
|
||||
{
|
||||
const char *protocol =
|
||||
(hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
|
||||
struct servent *srv = getservbyname (service, protocol);
|
||||
|
||||
if (srv)
|
||||
port = srv->s_port;
|
||||
else
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
gai_storage = calloc (1, sizeof *gai_storage);
|
||||
gai_storage->sockaddr_in.sin_port = port;
|
||||
host_info = gethostbyname (node);
|
||||
if (host_info)
|
||||
{
|
||||
memcpy (&gai_storage->sockaddr_in.sin_addr,
|
||||
host_info->h_addr, host_info->h_length);
|
||||
gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (gai_storage);
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
gai_storage->addrinfo.ai_addr =
|
||||
(struct sockaddr *)&gai_storage->sockaddr_in;
|
||||
gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
|
||||
if (hints && (hints->ai_flags & AI_CANONNAME) != 0)
|
||||
{
|
||||
gai_storage->addrinfo.ai_canonname = strdup (host_info->h_name);
|
||||
if (!gai_storage->addrinfo.ai_canonname)
|
||||
{
|
||||
free (gai_storage);
|
||||
return WSA_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
}
|
||||
gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
|
||||
gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
|
||||
gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
|
||||
gai_storage->addrinfo.ai_next = NULL;
|
||||
|
||||
*res = &gai_storage->addrinfo;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
sys_freeaddrinfo (struct addrinfo *ai)
|
||||
{
|
||||
if (load_ws2 () != 0)
|
||||
{
|
||||
errno = ENETDOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pfn_freeaddrinfo)
|
||||
pfn_freeaddrinfo (ai);
|
||||
else
|
||||
{
|
||||
if (ai->ai_canonname)
|
||||
free (ai->ai_canonname);
|
||||
free (ai);
|
||||
}
|
||||
}
|
||||
#endif /* WINDOWSNT */
|
||||
#endif /* MAIL_USE_POP */
|
||||
|
|
|
@ -98,6 +98,8 @@ typedef unsigned short uint16_t;
|
|||
#define accept sys_accept
|
||||
#define recvfrom sys_recvfrom
|
||||
#define sendto sys_sendto
|
||||
#define getaddrinfo sys_getaddrinfo
|
||||
#define freeaddrinfo sys_freeaddrinfo
|
||||
|
||||
int sys_socket(int af, int type, int protocol);
|
||||
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,
|
|||
struct sockaddr *from, int * fromlen);
|
||||
int sys_sendto (int s, const char * buf, int len, int flags,
|
||||
const struct sockaddr *to, int tolen);
|
||||
int sys_getaddrinfo (const char * node, const char * service,
|
||||
const struct addrinfo * hints, struct addrinfo ** res);
|
||||
void sys_freeaddrinfo (struct addrinfo * ai);
|
||||
|
||||
/* In addition to wrappers for the winsock functions, we also provide
|
||||
an fcntl function, for setting sockets to non-blocking mode. */
|
||||
|
|
|
@ -68,6 +68,10 @@ ac_cv_func_getsockname=yes
|
|||
ac_cv_func_getpeername=yes
|
||||
# Implemented as sys_socket in w32.c
|
||||
ac_cv_func_socket=yes
|
||||
# Implemented as sys_getaddrinfo in w32.c
|
||||
ac_cv_func_getaddrinfo=yes
|
||||
# Implemented as an inline function in ws2tcpip.h
|
||||
ac_cv_func_gai_strerror=yes
|
||||
# Implemented in w32.c
|
||||
ac_cv_func_mkostemp=yes
|
||||
ac_cv_func_readlink=yes
|
||||
|
|
125
src/w32.c
125
src/w32.c
|
@ -7202,6 +7202,10 @@ int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
|
|||
int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
|
||||
const struct sockaddr * to, int tolen);
|
||||
|
||||
int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
|
||||
const struct addrinfo *, struct addrinfo **);
|
||||
void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
|
||||
|
||||
/* SetHandleInformation is only needed to make sockets non-inheritable. */
|
||||
BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
|
||||
#ifndef HANDLE_FLAG_INHERIT
|
||||
|
@ -7284,6 +7288,16 @@ init_winsock (int load_now)
|
|||
LOAD_PROC (sendto);
|
||||
#undef LOAD_PROC
|
||||
|
||||
/* Try loading functions not available before XP. */
|
||||
pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
|
||||
pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
|
||||
/* Paranoia: these two functions should go together, so if one
|
||||
is absent, we cannot use the other. */
|
||||
if (pfn_getaddrinfo == NULL)
|
||||
pfn_freeaddrinfo = NULL;
|
||||
else if (pfn_freeaddrinfo == NULL)
|
||||
pfn_getaddrinfo = NULL;
|
||||
|
||||
/* specify version 1.1 of winsock */
|
||||
if (pfn_WSAStartup (0x101, &winsockData) == 0)
|
||||
{
|
||||
|
@ -7733,6 +7747,117 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen)
|
|||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
sys_getaddrinfo (const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (winsock_lib == NULL)
|
||||
{
|
||||
errno = ENETDOWN;
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
check_errno ();
|
||||
if (pfn_getaddrinfo)
|
||||
rc = pfn_getaddrinfo (node, service, hints, res);
|
||||
else
|
||||
{
|
||||
int port = 0;
|
||||
struct hostent *host_info;
|
||||
struct gai_storage {
|
||||
struct addrinfo addrinfo;
|
||||
struct sockaddr_in sockaddr_in;
|
||||
} *gai_storage;
|
||||
|
||||
/* We don't (yet) support any flags, as Emacs doesn't need that. */
|
||||
if (hints && hints->ai_flags != 0)
|
||||
return WSAEINVAL;
|
||||
/* NODE cannot be NULL, since process.c has fallbacks for that. */
|
||||
if (!node)
|
||||
return WSAHOST_NOT_FOUND;
|
||||
|
||||
if (service)
|
||||
{
|
||||
const char *protocol =
|
||||
(hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
|
||||
struct servent *srv = sys_getservbyname (service, protocol);
|
||||
|
||||
if (srv)
|
||||
port = srv->s_port;
|
||||
else if (*service >= '0' && *service <= '9')
|
||||
{
|
||||
char *endp;
|
||||
|
||||
port = strtoul (service, &endp, 10);
|
||||
if (*endp || port > 65536)
|
||||
return WSAHOST_NOT_FOUND;
|
||||
port = sys_htons ((unsigned short) port);
|
||||
}
|
||||
else
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
gai_storage = xzalloc (sizeof *gai_storage);
|
||||
gai_storage->sockaddr_in.sin_port = port;
|
||||
host_info = sys_gethostbyname (node);
|
||||
if (host_info)
|
||||
{
|
||||
memcpy (&gai_storage->sockaddr_in.sin_addr,
|
||||
host_info->h_addr, host_info->h_length);
|
||||
gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Attempt to interpret host as numeric inet address. */
|
||||
unsigned long numeric_addr = sys_inet_addr (node);
|
||||
|
||||
if (numeric_addr == -1)
|
||||
{
|
||||
free (gai_storage);
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
|
||||
sizeof (gai_storage->sockaddr_in.sin_addr));
|
||||
gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
|
||||
}
|
||||
|
||||
gai_storage->addrinfo.ai_addr =
|
||||
(struct sockaddr *)&gai_storage->sockaddr_in;
|
||||
gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
|
||||
gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
|
||||
gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
|
||||
gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
|
||||
gai_storage->addrinfo.ai_next = NULL;
|
||||
|
||||
*res = &gai_storage->addrinfo;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
sys_freeaddrinfo (struct addrinfo *ai)
|
||||
{
|
||||
if (winsock_lib == NULL)
|
||||
{
|
||||
errno = ENETDOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
check_errno ();
|
||||
if (pfn_freeaddrinfo)
|
||||
pfn_freeaddrinfo (ai);
|
||||
else
|
||||
{
|
||||
eassert (ai->ai_next == NULL);
|
||||
xfree (ai);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sys_shutdown (int s, int how)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue