The problem is caused by the following two commits, which sought to deal with
new Exxx values (with values >= 100) in errno.h which Microsoft added in VS2010:
http://perl5.git.perl.org/perl.git/commit/
b59e75b34cef3fedd214c9b6ee744146cf8b3308
http://perl5.git.perl.org/perl.git/commit/
912c63ed00375338703043928cac3c740d00cc9d
The former commit was mostly a patch to Errno and POSIX, together with some
other cleaning up in win32/win32.h and win32/include/sys/socket.h; the latter
commit was a fixup to win32/include/sys/socket.h which restored (more
aggressively) the ENOTSOCK->WSAENOTSOCK redefinition and added similar
redefinitions for ECONNABORTED, ECONNRESET and EAFNOSUPPORT.
It is the latter commit which causes this little program to output
ECONNABORTED=10053 rather than ECONNABORTED=106 as it ought to do in VC10 (and
higher) builds of perl:
#include <windows.h>
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
void main(void) {
printf("ECONNABORTED=%d\n", ECONNABORTED);
}
That change is now causing problems with mod_perl, in which the (Perl level)
APR::Status::is_ECONNABORTED() and the (C level) APR_STATUS_IS_ECONNABORTED()
which it calls are failing to recognize an aborted connection (indicated by
error code ECONNABORTED set by Apache httpd.exe).
The APR_STATUS_IS_ECONNABORTED() macro is picked up by mod_perl from APR's
apr_errno.h:
#define APR_STATUS_IS_ECONNABORTED(s) ((s) == APR_ECONNABORTED \
|| (s) == APR_OS_START_SYSERR + WSAECONNABORTED)
where
#ifdef ECONNABORTED
#define APR_ECONNABORTED ECONNABORTED
#else
#define APR_ECONNABORTED (APR_OS_START_CANONERR + 18)
#endif
When this is compiled into httpd.exe ECONNABORTED is 106 (from errno.h) and
APR_STATUS_IS_ECONNABORTED(s) amounts to
#define APR_STATUS_IS_ECONNABORTED(s) ((s) == 106 || (s) == 730053)
but when compiled into APR/Status.dll ECONNABORTED is 10053 (redefined to
WSAECONNABORTED as above) so APR_STATUS_IS_ECONNABORTED(s) then amounts to
#define APR_STATUS_IS_ECONNABORTED(s) ((s) == 10053 || (s) == 730053)
which doesn't pick up an error code of 106 coming from httpd.exe.
This could be worked around in mod_perl by redefining ECONNABORTED and the other
three back to their original errno.h values to match what httpd.exe is using,
but that might just cause problems in the other direction, with those values no
longer matching the values which perl.exe is using.
Moreoever, this problem could affect other XS interfaces (not just mod_perl), so
it really needs to be fixed in perl.
This commit implements the alternative solution mentioned the commit message for
the first commit cited above. (As noted in that previous commit message, this
solution equally has potential problems, missing out on the advantages of the
original solution implemented, namely, better backwards compatibility with other
perl code having hard-coded numeric error codes, but this will be unavoidable if
we want to get to a sane state.)
Note that changing the $! values is an incompatible change, so should probably
not be done for 5.18.x. That's unfortunate for mod_perl (and anything else
similarly affected), but that will just have to either live with the breakage
(which was introduced in 5.14.0) until 5.20.0 or else try the workaround
mentioned above for 5.14.x, 5.16.x and 5.18.x.
The main change is to use a new function throughout win32/win32sck.c to convert
WSAGetLastError() values into errno.h constants before assigning to errno. Every
possible WSAExxx value (as documented by MSDN) is mapped to an Exxx value,
although it is still possible for other WSAxxx values to get assigned to errno
unchanged (but that has always been the case, and any non-existent Exxx values
get mapped back to WSAExxx values anyway...).
We must then ensure that all of those Exxx values are defined, which is now done
(in the new file, win32/include/sys/errno2.h) in a friendlier manner, being
careful not to redefine any (specifically the new ones in VC++ 2010 and above)
which already exist. The rest are defined as the WSAExxx values, as mentioned
above.
Finally, we need the Errno module to know about these values, which is done by
having it include that same new header file to ensure that it gets the same
definitions, rather than having to play its own games. The new header is also
used in POSIX, which similarly wants definitions of as many as possible of its
hard-coded list of Exxx values.
win32/include/arpa/inet.h Win32 port
win32/include/dirent.h Win32 port
win32/include/netdb.h Win32 port
+win32/include/sys/errno2.h Win32 port
win32/include/sys/socket.h Win32 port
win32/list_static_libs.pl prints libraries for static linking
win32/Makefile Win32 makefile for NMAKE (Visual C++ build)
use Config;
use strict;
-our $VERSION = "1.19";
+our $VERSION = "1.20";
my %err = ();
-my %wsa = ();
# Symbian cross-compiling environment.
my $IsSymbian = exists $ENV{SDK} && -d "$ENV{SDK}\\epoc32";
while(<FH>) {
$err{$1} = 1
if /^\s*#\s*define\s+(E\w+)\s+/;
- if ($IsMSWin32) {
- $wsa{$1} = 1
- if /^\s*#\s*define\s+WSA(E\w+)\s+/;
- }
}
close(FH);
} else {
print CPPI "#include <errno.h>\n";
if ($IsMSWin32) {
- print CPPI "#define _WINSOCKAPI_\n"; # don't drag in everything
- print CPPI "#include <winsock.h>\n";
+ print CPPI qq[#include "../../win32/include/sys/errno2.h"\n];
}
}
}
if ($IsMSWin32) {
print CPPI "#include <winsock.h>\n";
- foreach $err (keys %wsa) {
- print CPPI "#if defined($err) && $err >= 100\n";
- print CPPI "#undef $err\n";
- print CPPI "#endif\n";
- print CPPI "#ifndef $err\n";
- print CPPI "#define $err WSA$err\n";
- print CPPI "#endif\n";
- $err{$err} = 1;
- }
+ print CPPI qq[#include "../../win32/include/sys/errno2.h"\n];
}
foreach $err (keys %err) {
#include <dirent.h>
#endif
#include <errno.h>
+#ifdef WIN32
+#include <sys/errno2.h>
+#endif
#ifdef I_FLOAT
#include <float.h>
#endif
#endif /* WIN32 || NETWARE */
#endif /* __VMS */
-#ifdef WIN32
- /* Perl on Windows assigns WSAGetLastError() return values to errno
- * (in win32/win32sck.c). Therefore we need to map these values
- * back to standard symbolic names, but only for those names having
- * no existing value or an existing value >= 100. (VC++ 2010 defines
- * a group of names with values >= 100 in its errno.h which we *do*
- * need to redefine.) The Errno.pm module does a similar mapping.
- */
-# ifdef EWOULDBLOCK
-# undef EWOULDBLOCK
-# endif
-# define EWOULDBLOCK WSAEWOULDBLOCK
-# ifdef EINPROGRESS
-# undef EINPROGRESS
-# endif
-# define EINPROGRESS WSAEINPROGRESS
-# ifdef EALREADY
-# undef EALREADY
-# endif
-# define EALREADY WSAEALREADY
-# ifdef ENOTSOCK
-# undef ENOTSOCK
-# endif
-# define ENOTSOCK WSAENOTSOCK
-# ifdef EDESTADDRREQ
-# undef EDESTADDRREQ
-# endif
-# define EDESTADDRREQ WSAEDESTADDRREQ
-# ifdef EMSGSIZE
-# undef EMSGSIZE
-# endif
-# define EMSGSIZE WSAEMSGSIZE
-# ifdef EPROTOTYPE
-# undef EPROTOTYPE
-# endif
-# define EPROTOTYPE WSAEPROTOTYPE
-# ifdef ENOPROTOOPT
-# undef ENOPROTOOPT
-# endif
-# define ENOPROTOOPT WSAENOPROTOOPT
-# ifdef EPROTONOSUPPORT
-# undef EPROTONOSUPPORT
-# endif
-# define EPROTONOSUPPORT WSAEPROTONOSUPPORT
-# ifdef ESOCKTNOSUPPORT
-# undef ESOCKTNOSUPPORT
-# endif
-# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
-# ifdef EOPNOTSUPP
-# undef EOPNOTSUPP
-# endif
-# define EOPNOTSUPP WSAEOPNOTSUPP
-# ifdef EPFNOSUPPORT
-# undef EPFNOSUPPORT
-# endif
-# define EPFNOSUPPORT WSAEPFNOSUPPORT
-# ifdef EAFNOSUPPORT
-# undef EAFNOSUPPORT
-# endif
-# define EAFNOSUPPORT WSAEAFNOSUPPORT
-# ifdef EADDRINUSE
-# undef EADDRINUSE
-# endif
-# define EADDRINUSE WSAEADDRINUSE
-# ifdef EADDRNOTAVAIL
-# undef EADDRNOTAVAIL
-# endif
-# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
-# ifdef ENETDOWN
-# undef ENETDOWN
-# endif
-# define ENETDOWN WSAENETDOWN
-# ifdef ENETUNREACH
-# undef ENETUNREACH
-# endif
-# define ENETUNREACH WSAENETUNREACH
-# ifdef ENETRESET
-# undef ENETRESET
-# endif
-# define ENETRESET WSAENETRESET
-# ifdef ECONNABORTED
-# undef ECONNABORTED
-# endif
-# define ECONNABORTED WSAECONNABORTED
-# ifdef ECONNRESET
-# undef ECONNRESET
-# endif
-# define ECONNRESET WSAECONNRESET
-# ifdef ENOBUFS
-# undef ENOBUFS
-# endif
-# define ENOBUFS WSAENOBUFS
-# ifdef EISCONN
-# undef EISCONN
-# endif
-# define EISCONN WSAEISCONN
-# ifdef ENOTCONN
-# undef ENOTCONN
-# endif
-# define ENOTCONN WSAENOTCONN
-# ifdef ESHUTDOWN
-# undef ESHUTDOWN
-# endif
-# define ESHUTDOWN WSAESHUTDOWN
-# ifdef ETOOMANYREFS
-# undef ETOOMANYREFS
-# endif
-# define ETOOMANYREFS WSAETOOMANYREFS
-# ifdef ETIMEDOUT
-# undef ETIMEDOUT
-# endif
-# define ETIMEDOUT WSAETIMEDOUT
-# ifdef ECONNREFUSED
-# undef ECONNREFUSED
-# endif
-# define ECONNREFUSED WSAECONNREFUSED
-# ifdef ELOOP
-# undef ELOOP
-# endif
-# define ELOOP WSAELOOP
-# ifdef EHOSTDOWN
-# undef EHOSTDOWN
-# endif
-# define EHOSTDOWN WSAEHOSTDOWN
-# ifdef EHOSTUNREACH
-# undef EHOSTUNREACH
-# endif
-# define EHOSTUNREACH WSAEHOSTUNREACH
-# ifdef EPROCLIM
-# undef EPROCLIM
-# endif
-# define EPROCLIM WSAEPROCLIM
-# ifdef EUSERS
-# undef EUSERS
-# endif
-# define EUSERS WSAEUSERS
-# ifdef EDQUOT
-# undef EDQUOT
-# endif
-# define EDQUOT WSAEDQUOT
-# ifdef ESTALE
-# undef ESTALE
-# endif
-# define ESTALE WSAESTALE
-# ifdef EREMOTE
-# undef EREMOTE
-# endif
-# define EREMOTE WSAEREMOTE
-# ifdef EDISCON
-# undef EDISCON
-# endif
-# define EDISCON WSAEDISCON
-#endif
-
typedef int SysRet;
typedef long SysRetLong;
typedef sigset_t* POSIX__SigSet;
our ($AUTOLOAD, %SIGRT);
-our $VERSION = '1.34';
+our $VERSION = '1.35';
require XSLoader;
--- /dev/null
+#ifndef _INC_SYS_ERRNO2
+#define _INC_SYS_ERRNO2
+
+#define _WINSOCKAPI_ /* Don't drag in everything */
+#include <winsock.h>
+
+/* Ensure all the Exxx constants required by get_last_socket_error() in
+ * win32/win32sck.c are defined. Many are defined in <errno.h> already (more in
+ * VC++ 2010 and above) so, for the sake of compatibility with third-party code
+ * linked into XS modules, we must be careful not to redefine them; for the
+ * remainder we define our own values, namely the corresponding WSAExxx values.
+ * These definitions are also used as a supplement to the use of <errno.h> in
+ * the Errno and POSIX modules, both of which may be used to test the value of
+ * $!, which may have these values assigned to it (via win32/win32sck.c). It
+ * also provides numerous otherwise missing values in the (hard-coded) list of
+ * Exxx constants exported by POSIX.
+ */
+#ifndef EINTR
+# define EINTR WSAEINTR
+#endif
+#ifndef EBADF
+# define EBADF WSAEBADF
+#endif
+#ifndef EACCES
+# define EACCES WSAEACCES
+#endif
+#ifndef EFAULT
+# define EFAULT WSAEFAULT
+#endif
+#ifndef EINVAL
+# define EINVAL WSAEINVAL
+#endif
+#ifndef EMFILE
+# define EMFILE WSAEMFILE
+#endif
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+#ifndef EINPROGRESS
+# define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef EALREADY
+# define EALREADY WSAEALREADY
+#endif
+#ifndef ENOTSOCK
+# define ENOTSOCK WSAENOTSOCK
+#endif
+#ifndef EDESTADDRREQ
+# define EDESTADDRREQ WSAEDESTADDRREQ
+#endif
+#ifndef EMSGSIZE
+# define EMSGSIZE WSAEMSGSIZE
+#endif
+#ifndef EPROTOTYPE
+# define EPROTOTYPE WSAEPROTOTYPE
+#endif
+#ifndef ENOPROTOOPT
+# define ENOPROTOOPT WSAENOPROTOOPT
+#endif
+#ifndef EPROTONOSUPPORT
+# define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#endif
+#ifndef ESOCKTNOSUPPORT
+# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#endif
+#ifndef EOPNOTSUPP
+# define EOPNOTSUPP WSAEOPNOTSUPP
+#endif
+#ifndef EPFNOSUPPORT
+# define EPFNOSUPPORT WSAEPFNOSUPPORT
+#endif
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef EADDRINUSE
+# define EADDRINUSE WSAEADDRINUSE
+#endif
+#ifndef EADDRNOTAVAIL
+# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#endif
+#ifndef ENETDOWN
+# define ENETDOWN WSAENETDOWN
+#endif
+#ifndef ENETUNREACH
+# define ENETUNREACH WSAENETUNREACH
+#endif
+#ifndef ENETRESET
+# define ENETRESET WSAENETRESET
+#endif
+#ifndef ECONNABORTED
+# define ECONNABORTED WSAECONNABORTED
+#endif
+#ifndef ECONNRESET
+# define ECONNRESET WSAECONNRESET
+#endif
+#ifndef ENOBUFS
+# define ENOBUFS WSAENOBUFS
+#endif
+#ifndef EISCONN
+# define EISCONN WSAEISCONN
+#endif
+#ifndef ENOTCONN
+# define ENOTCONN WSAENOTCONN
+#endif
+#ifndef ESHUTDOWN
+# define ESHUTDOWN WSAESHUTDOWN
+#endif
+#ifndef ETOOMANYREFS
+# define ETOOMANYREFS WSAETOOMANYREFS
+#endif
+#ifndef ETIMEDOUT
+# define ETIMEDOUT WSAETIMEDOUT
+#endif
+#ifndef ECONNREFUSED
+# define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef ELOOP
+# define ELOOP WSAELOOP
+#endif
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG WSAENAMETOOLONG
+#endif
+#ifndef EHOSTDOWN
+# define EHOSTDOWN WSAEHOSTDOWN
+#endif
+#ifndef EHOSTUNREACH
+# define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef ENOTEMPTY
+# define ENOTEMPTY WSAENOTEMPTY
+#endif
+#ifndef EPROCLIM
+# define EPROCLIM WSAEPROCLIM
+#endif
+#ifndef EUSERS
+# define EUSERS WSAEUSERS
+#endif
+#ifndef EDQUOT
+# define EDQUOT WSAEDQUOT
+#endif
+#ifndef ESTALE
+# define ESTALE WSAESTALE
+#endif
+#ifndef EREMOTE
+# define EREMOTE WSAEREMOTE
+#endif
+#ifndef EDISCON
+# define EDISCON WSAEDISCON
+#endif
+#ifndef ENOMORE
+# define ENOMORE WSAENOMORE
+#endif
+#ifndef ECANCELLED
+# define ECANCELLED WSAECANCELLED
+#endif
+#ifndef EINVALIDPROCTABLE
+# define EINVALIDPROCTABLE WSAEINVALIDPROCTABLE
+#endif
+#ifndef EINVALIDPROVIDER
+# define EINVALIDPROVIDER WSAEINVALIDPROVIDER
+#endif
+#ifndef EPROVIDERFAILEDINIT
+# define EPROVIDERFAILEDINIT WSAEPROVIDERFAILEDINIT
+#endif
+#ifndef EREFUSED
+# define EREFUSED WSAEREFUSED
+#endif
+
+#endif /* _INC_SYS_ERRNO2 */
# define EAI_NODATA WSANO_DATA
#endif
-#include "win32.h"
-
#ifdef __cplusplus
extern "C" {
#endif
-#undef ENOTSOCK
-#define ENOTSOCK WSAENOTSOCK
-
-#undef ECONNABORTED
-#define ECONNABORTED WSAECONNABORTED
-
-#undef ECONNRESET
-#define ECONNRESET WSAECONNRESET
-
-#undef EAFNOSUPPORT
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#include "errno2.h"
#ifndef PERL_FD_SETSIZE
#define PERL_FD_SETSIZE 64
}
if (i == -1) {
if (GetLastError() == ERROR_LOCK_VIOLATION)
- errno = WSAEWOULDBLOCK;
+ errno = EWOULDBLOCK;
else
errno = EINVAL;
}
STMT_START { \
StartSockets(); \
if((x) == (y)) \
- errno = WSAGetLastError(); \
+ errno = get_last_socket_error(); \
} STMT_END
#define SOCKET_TEST_ERROR(x) SOCKET_TEST(x, SOCKET_ERROR)
WSACleanup();
}
+int
+get_last_socket_error(void)
+{
+ int err = WSAGetLastError();
+
+ /* Translate WSAExxx values to corresponding Exxx values. Not all WSAExxx
+ * constants have corresponding Exxx constants in <errno.h> (even in VC++
+ * 2010 and above, which have expanded <errno.h> with more values), but any
+ * missing constants are provided by win32/include/sys/errno2.h.
+ * The list of possible WSAExxx values used here comes from the MSDN page
+ * titled "Windows Sockets Error Codes".
+ * (Note: Only the WSAExxx values are handled here; other WSAxxx values are
+ * returned unchanged. The return value normally ends up in errno/$! and at
+ * the Perl code level may be tested against the Exxx constants exported by
+ * the Errno and POSIX modules, which have never handled the other WSAxxx
+ * values themselves, apparently without any ill effect so far.)
+ */
+ switch (err) {
+ case WSAEINTR:
+ return EINTR;
+ case WSAEBADF:
+ return EBADF;
+ case WSAEACCES:
+ return EACCES;
+ case WSAEFAULT:
+ return EFAULT;
+ case WSAEINVAL:
+ return EINVAL;
+ case WSAEMFILE:
+ return EMFILE;
+ case WSAEWOULDBLOCK:
+ return EWOULDBLOCK;
+ case WSAEINPROGRESS:
+ return EINPROGRESS;
+ case WSAEALREADY:
+ return EALREADY;
+ case WSAENOTSOCK:
+ return ENOTSOCK;
+ case WSAEDESTADDRREQ:
+ return EDESTADDRREQ;
+ case WSAEMSGSIZE:
+ return EMSGSIZE;
+ case WSAEPROTOTYPE:
+ return EPROTOTYPE;
+ case WSAENOPROTOOPT:
+ return ENOPROTOOPT;
+ case WSAEPROTONOSUPPORT:
+ return EPROTONOSUPPORT;
+ case WSAESOCKTNOSUPPORT:
+ return ESOCKTNOSUPPORT;
+ case WSAEOPNOTSUPP:
+ return EOPNOTSUPP;
+ case WSAEPFNOSUPPORT:
+ return EPFNOSUPPORT;
+ case WSAEAFNOSUPPORT:
+ return EAFNOSUPPORT;
+ case WSAEADDRINUSE:
+ return EADDRINUSE;
+ case WSAEADDRNOTAVAIL:
+ return EADDRNOTAVAIL;
+ case WSAENETDOWN:
+ return ENETDOWN;
+ case WSAENETUNREACH:
+ return ENETUNREACH;
+ case WSAENETRESET:
+ return ENETRESET;
+ case WSAECONNABORTED:
+ return ECONNABORTED;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ case WSAENOBUFS:
+ return ENOBUFS;
+ case WSAEISCONN:
+ return EISCONN;
+ case WSAENOTCONN:
+ return ENOTCONN;
+ case WSAESHUTDOWN:
+ return ESHUTDOWN;
+ case WSAETOOMANYREFS:
+ return ETOOMANYREFS;
+ case WSAETIMEDOUT:
+ return ETIMEDOUT;
+ case WSAECONNREFUSED:
+ return ECONNREFUSED;
+ case WSAELOOP:
+ return ELOOP;
+ case WSAENAMETOOLONG:
+ return ENAMETOOLONG;
+ case WSAEHOSTDOWN:
+ return EHOSTDOWN;
+ case WSAEHOSTUNREACH:
+ return EHOSTUNREACH;
+ case WSAENOTEMPTY:
+ return ENOTEMPTY;
+ case WSAEPROCLIM:
+ return EPROCLIM;
+ case WSAEUSERS:
+ return EUSERS;
+ case WSAEDQUOT:
+ return EDQUOT;
+ case WSAESTALE:
+ return ESTALE;
+ case WSAEREMOTE:
+ return EREMOTE;
+ case WSAEDISCON:
+ return EDISCON;
+ case WSAENOMORE:
+ return ENOMORE;
+ case WSAECANCELLED:
+ return ECANCELLED;
+ case WSAEINVALIDPROCTABLE:
+ return EINVALIDPROCTABLE;
+ case WSAEINVALIDPROVIDER:
+ return EINVALIDPROVIDER;
+ case WSAEPROVIDERFAILEDINIT:
+ return EPROVIDERFAILEDINIT;
+ case WSAEREFUSED:
+ return EREFUSED;
+ }
+
+ return err;
+}
+
void
start_sockets(void)
{
StartSockets();
if((s = open_ifs_socket(af, type, protocol)) == INVALID_SOCKET)
- errno = WSAGetLastError();
+ errno = get_last_socket_error();
else
s = OPEN_SOCKET(s);
return 0;
}
else if (err == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err != WSAENOTSOCK) {
+ err = get_last_socket_error();
+ if (err != ENOTSOCK) {
(void)close(fd);
errno = err;
return EOF;
return 0;
}
else if (err == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err != WSAENOTSOCK) {
+ err = get_last_socket_error();
+ if (err != ENOTSOCK) {
(void)fclose(pf);
errno = err;
return EOF;
memcpy(data, &u_long_arg, sizeof u_long_arg);
if (retval == SOCKET_ERROR) {
- if (WSAGetLastError() == WSAENOTSOCK) {
+ int err = get_last_socket_error();
+ if (err == ENOTSOCK) {
Perl_croak_nocontext("ioctl implemented only on sockets");
/* NOTREACHED */
}
- errno = WSAGetLastError();
+ errno = err;
}
return retval;
}