This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix a problem with mod_perl on Windows using VS2010+.
authorSteve Hay <steve.m.hay@googlemail.com>
Tue, 3 Sep 2013 21:57:29 +0000 (22:57 +0100)
committerSteve Hay <steve.m.hay@googlemail.com>
Mon, 16 Sep 2013 14:37:30 +0000 (15:37 +0100)
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.

MANIFEST
ext/Errno/Errno_pm.PL
ext/POSIX/POSIX.xs
ext/POSIX/lib/POSIX.pm
win32/include/sys/errno2.h [new file with mode: 0644]
win32/include/sys/socket.h
win32/win32.c
win32/win32sck.c

index c83d0d0..81f2149 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -5608,6 +5608,7 @@ win32/FindExt.pm          Scan for extensions
 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)
index b372875..8267cbc 100644 (file)
@@ -2,10 +2,9 @@ use ExtUtils::MakeMaker;
 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";
@@ -84,10 +83,6 @@ sub process_file {
     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);
@@ -161,8 +156,7 @@ sub get_files {
        } 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];
            }
        }
 
@@ -216,15 +210,7 @@ sub write_errno_pm {
     }
     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) {
index 655fda3..b3319fb 100644 (file)
@@ -28,6 +28,9 @@
 #include <dirent.h>
 #endif
 #include <errno.h>
+#ifdef WIN32
+#include <sys/errno2.h>
+#endif
 #ifdef I_FLOAT
 #include <float.h>
 #endif
@@ -193,160 +196,6 @@ char *tzname[] = { "" , "" };
 #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;
index 40b02ac..b3e1272 100644 (file)
@@ -4,7 +4,7 @@ use warnings;
 
 our ($AUTOLOAD, %SIGRT);
 
-our $VERSION = '1.34';
+our $VERSION = '1.35';
 
 require XSLoader;
 
diff --git a/win32/include/sys/errno2.h b/win32/include/sys/errno2.h
new file mode 100644 (file)
index 0000000..076ed01
--- /dev/null
@@ -0,0 +1,169 @@
+#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 */
index 6009572..d658913 100644 (file)
 #  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
index c31e3a2..1a64f9f 100644 (file)
@@ -2513,7 +2513,7 @@ win32_flock(int fd, int oper)
     }
     if (i == -1) {
         if (GetLastError() == ERROR_LOCK_VIOLATION)
-            errno = WSAEWOULDBLOCK;
+            errno = EWOULDBLOCK;
         else
             errno = EINVAL;
     }
index 3773f40..0b42507 100644 (file)
@@ -42,7 +42,7 @@
     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)
@@ -60,6 +60,129 @@ EndSockets(void)
        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) 
 {
@@ -401,7 +524,7 @@ win32_socket(int af, int type, int protocol)
     StartSockets();
 
     if((s = open_ifs_socket(af, type, protocol)) == INVALID_SOCKET)
-       errno = WSAGetLastError();
+       errno = get_last_socket_error();
     else
        s = OPEN_SOCKET(s);
 
@@ -429,8 +552,8 @@ int my_close(int fd)
            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;
@@ -457,8 +580,8 @@ my_fclose (FILE *pf)
            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;
@@ -558,11 +681,12 @@ win32_ioctl(int i, unsigned int u, char *data)
     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;
 }