"Hrvoje Niksic" wrote:

errno/WSAGetLastError() handling and reporting is still broken for all
Win32 compilers. Search for SET_ERRNO() in the mail-archive.

I remember that. At the time I disliked the idea of using the SET/GET_ERRNO pair instead of just using and assigning to errno. Another option was to simply set the (system) errno after the Winsock operations, and have our own strerror that recognizes them. (That assumes that Winsock errno values don't conflict with the system ones, which I believe is the case.)

That assumption is wrong I think.

Winsock errors are in range 10000 - 11004. Win32 API errors (from <WinErr.h>) and libc errors (from <errno.h>) *do* overlap. E.g. both EINTR and ERROR_TOO_MANY_OPEN_FILES both have the same value (4).

We must therefore be careful using strerror() with errno codes only
and FormatMessage() with GetLastError (and WSAGetLastError). *Or*
cook up a smarter strerror() replacement. It is "normal" to assume that
err_code < sys_nerr belongs to libc (MSVCRT.DLL). Use with care:

#undef strerror
char *win_strerror (int err)
{
 static char buf[512];
 char  *p;

 if (err >= 0 && err < sys_nerr)
   {
     strncpy (buf, strerror(err), sizeof(buf)-1);
     buf [sizeof(buf)-1] = '\0';
   }
 else
   {
     if (!get_winsock_error (err, buf, sizeof(buf)) &&
         !FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
                         LANG_NEUTRAL, buf, sizeof(buf)-1, NULL))
      sprintf (buf, "Unknown error %d (%#x)", err, err);
   }

 /* strip trailing '\r\n' or '\n'. */
 if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2)
    *p = '\0';
 if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
    *p = '\0';
 return buf;
}

static char *
get_winsock_error (int err, char *buf, size_t len)
{
 char *p;

 switch (err)
 {
   case WSAEINTR:
       p = "Call interrupted.";
       break;
   case WSAEBADF:
       p = "Bad file";
       break;
.....

--gv

Reply via email to