* fhandler_socket.cc: On x86_64, define u_long as __ms_u_long before

including the windows headers.  Explain why.
	(get_inet_addr): Convert ANY address to LOOPBACK address.  Explain why.
	(fhandler_socket::evaluate_events): Forcibly set SO_ERROR socket option
	in case a connection attempt failed.  Explain why.
	(fhandler_socket::ioctl): Drop x86_64 re-definition of u_long here.
	* fhandler_procnet.cc: On x86_64, define u_long as __ms_u_long before
	including the windows headers.  Explain why.
	* net.cc: Ditto.
This commit is contained in:
Corinna Vinschen 2014-04-24 13:44:23 +00:00
parent ef7e42ec0f
commit 8e22028339
5 changed files with 72 additions and 11 deletions

View File

@ -1,3 +1,15 @@
2014-04-24 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc: On x86_64, define u_long as __ms_u_long before
including the windows headers. Explain why.
(get_inet_addr): Convert ANY address to LOOPBACK address. Explain why.
(fhandler_socket::evaluate_events): Forcibly set SO_ERROR socket option
in case a connection attempt failed. Explain why.
(fhandler_socket::ioctl): Drop x86_64 re-definition of u_long here.
* fhandler_procnet.cc: On x86_64, define u_long as __ms_u_long before
including the windows headers. Explain why.
* net.cc: Ditto.
2014-04-23 Corinna Vinschen <corinna@vinschen.de>
* miscfuncs.cc (check_iovec): Allow 0 as valid iovcnt value.

View File

@ -11,6 +11,13 @@ details. */
#define __INSIDE_CYGWIN_NET__
#define USE_SYS_TYPES_FD_SET
#include "winsup.h"
#ifdef __x86_64__
/* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte)
because a redefinition for LP64 systems is missing. This leads to a wrong
definition and size of sockaddr_in6 when building with winsock headers. */
#undef u_long
#define u_long __ms_u_long
#endif
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include "cygerrno.h"

View File

@ -1,7 +1,7 @@
/* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013 Red Hat, Inc.
2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@ -17,6 +17,15 @@
#define _BSDTYPES_DEFINED
#include "winsup.h"
#undef _BSDTYPES_DEFINED
#ifdef __x86_64__
/* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte)
because a redefinition for LP64 systems is missing. This leads to a wrong
definition and size of sockaddr_in6 when building with winsock headers.
This definition is also required to use the right u_long type in subsequent
function calls. */
#undef u_long
#define u_long __ms_u_long
#endif
#include <ws2tcpip.h>
#include <mswsock.h>
#include <iphlpapi.h>
@ -89,9 +98,20 @@ get_inet_addr (const struct sockaddr *in, int inlen,
}
break;
case AF_INET:
memcpy (out, in, inlen);
*outlen = inlen;
/* If the peer address given in connect or sendto is the ANY address,
Winsock fails with WSAEADDRNOTAVAIL, while Linux converts that into
a connection/send attempt to LOOPBACK. We're doing the same here. */
if (((struct sockaddr_in *) out)->sin_addr.s_addr == htonl (INADDR_ANY))
((struct sockaddr_in *) out)->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
return 0;
case AF_INET6:
memcpy (out, in, inlen);
*outlen = inlen;
/* See comment in AF_INET case. */
if (IN6_IS_ADDR_UNSPECIFIED (&((struct sockaddr_in6 *) out)->sin6_addr))
((struct sockaddr_in6 *) out)->sin6_addr = in6addr_loopback;
return 0;
default:
set_errno (EAFNOSUPPORT);
@ -614,6 +634,17 @@ fhandler_socket::evaluate_events (const long event_mask, long &events,
if ((wsa_err = wsock_events->connect_errorcode) != 0)
{
WSASetLastError (wsa_err);
/* CV 2014-04-23: This is really weird. If you call connect
asynchronously on a socket and then select, an error like
"Connection refused" is set in the event and in the SO_ERROR
socket option. If you call connect, then dup, then select,
the error is set in the event, but not in the SO_ERROR socket
option, even if the dup'ed socket handle refers to the same
socket. We're trying to workaround this problem here by
taking the connect errorcode from the event and write it back
into the SO_ERROR socket option. */
setsockopt (get_socket (), SOL_SOCKET, SO_ERROR,
(const char *) &wsa_err, sizeof wsa_err);
ret = SOCKET_ERROR;
}
else
@ -2073,16 +2104,6 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK);
break;
case FIONREAD:
#ifdef __x86_64__
/* FIXME: This looks broken in the Mingw64 headers. If I make sure
to use the Windows u_long definition, I'd expect that it's defined
as a 4 byte type on LP64 as well. But that's not the case right now.
The *additional* type __ms_u_long is available on LP64, and that's
used in subsequent function declarations, but that's not available
on 32 bit or LLP64. The LP64-ness shouldn't require to use another
type name in the application code. */
#define u_long __ms_u_long
#endif
res = ioctlsocket (get_socket (), FIONREAD, (u_long *) p);
if (res == SOCKET_ERROR)
set_winsock_errno ();

View File

@ -20,6 +20,15 @@ details. */
system functions on Vista and later. */
#define _INC_NETIOAPI
#include "winsup.h"
#ifdef __x86_64__
/* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte)
because a redefinition for LP64 systems is missing. This leads to a wrong
definition and size of sockaddr_in6 when building with winsock headers.
This definition is also required to use the right u_long type in subsequent
function calls. */
#undef u_long
#define u_long __ms_u_long
#endif
#include <ws2tcpip.h>
#include <mswsock.h>
#include <iphlpapi.h>

View File

@ -13,6 +13,10 @@ What changed:
it returns WSAENOPROTOOPT. Cygwin now ignores this error condition and
returns a fake success to the application, just as with IP_TOS for years.
- Connect and sendto to the AF_INET and AF_INET6 ANY address is converted to
the LOOPBACK address, as on Linux.
Addresses: http://cygwin.com/ml/cygwin/2014-04/msg00510.html
Bug Fixes
---------
@ -22,3 +26,11 @@ Bug Fixes
- Fix calls to readv/writev/recvmsg/sendmsg with 0 iovlen.
Fixes: http://cygwin.com/ml/cygwin/2014-04/msg00509.html
- Workaround a problem with Mingw64 Winsock headers which lead to an incorrect
definition of struct sockaddr_in6, and which in turn broke /proc/net/if_inet6.
- Workaround a Winsock bug which neglects to set the SO_ERROR socket option
when calling select on a dup'ed socket after an asynchronous connection
attempt.
Fixes: http://cygwin.com/ml/cygwin/2014-04/msg00510.html