diff options
Diffstat (limited to 'src/interfaces/libpq/win32.c')
-rw-r--r-- | src/interfaces/libpq/win32.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/interfaces/libpq/win32.c b/src/interfaces/libpq/win32.c new file mode 100644 index 00000000000..9c7d379456c --- /dev/null +++ b/src/interfaces/libpq/win32.c @@ -0,0 +1,182 @@ +/* + * FILE + * win32.c + * + * DESCRIPTION + * Win32 support functions. + * + * Contains table and functions for looking up win32 socket error + * descriptions. But will/may contain other win32 helper functions + * for libpq. + * + * The error constants are taken from the Frambak Bakfram LGSOCKET + * library guys who in turn took them from the Winsock FAQ. + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + */ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winsock.h> +#include <stdio.h> +#include "win32.h" + +static struct WSErrorEntry { + DWORD error; + const char* description; +} WSErrors [] = { + {0, "No error"}, + {WSAEINTR, "Interrupted system call"}, + {WSAEBADF, "Bad file number"}, + {WSAEACCES, "Permission denied"}, + {WSAEFAULT, "Bad address"}, + {WSAEINVAL, "Invalid argument"}, + {WSAEMFILE, "Too many open sockets"}, + {WSAEWOULDBLOCK, "Operation would block"}, + {WSAEINPROGRESS, "Operation now in progress"}, + {WSAEALREADY, "Operation already in progress"}, + {WSAENOTSOCK, "Socket operation on non-socket"}, + {WSAEDESTADDRREQ, "Destination address required"}, + {WSAEMSGSIZE, "Message too long"}, + {WSAEPROTOTYPE, "Protocol wrong type for socket"}, + {WSAENOPROTOOPT, "Bad protocol option"}, + {WSAEPROTONOSUPPORT, "Protocol not supported"}, + {WSAESOCKTNOSUPPORT, "Socket type not supported"}, + {WSAEOPNOTSUPP, "Operation not supported on socket"}, + {WSAEPFNOSUPPORT, "Protocol family not supported"}, + {WSAEAFNOSUPPORT, "Address family not supported"}, + {WSAEADDRINUSE, "Address already in use"}, + {WSAEADDRNOTAVAIL, "Can't assign requested address"}, + {WSAENETDOWN, "Network is down"}, + {WSAENETUNREACH, "Network is unreachable"}, + {WSAENETRESET, "Net connection reset"}, + {WSAECONNABORTED, "Software caused connection abort"}, + {WSAECONNRESET, "Connection reset by peer"}, + {WSAENOBUFS, "No buffer space available"}, + {WSAEISCONN, "Socket is already connected"}, + {WSAENOTCONN, "Socket is not connected"}, + {WSAESHUTDOWN, "Can't send after socket shutdown"}, + {WSAETOOMANYREFS, "Too many references, can't splice"}, + {WSAETIMEDOUT, "Connection timed out"}, + {WSAECONNREFUSED, "Connection refused"}, + {WSAELOOP, "Too many levels of symbolic links"}, + {WSAENAMETOOLONG, "File name too long"}, + {WSAEHOSTDOWN, "Host is down"}, + {WSAEHOSTUNREACH, "No route to host"}, + {WSAENOTEMPTY, "Directory not empty"}, + {WSAEPROCLIM, "Too many processes"}, + {WSAEUSERS, "Too many users"}, + {WSAEDQUOT, "Disc quota exceeded"}, + {WSAESTALE, "Stale NFS file handle"}, + {WSAEREMOTE, "Too many levels of remote in path"}, + {WSASYSNOTREADY, "Network system is unavailable"}, + {WSAVERNOTSUPPORTED, "Winsock version out of range"}, + {WSANOTINITIALISED, "WSAStartup not yet called"}, + {WSAEDISCON, "Graceful shutdown in progress"}, + {WSAHOST_NOT_FOUND, "Host not found"}, + {WSATRY_AGAIN, "NA Host not found / SERVFAIL"}, + {WSANO_RECOVERY, "Non recoverable FORMERR||REFUSED||NOTIMP"}, + {WSANO_DATA, "No host data of that type was found"}, + {0,0} /* End of table */ +}; + + +/* + * Returns 0 if not found, linear but who cares, at this moment + * we're already in pain :) + */ + +static int LookupWSErrorMessage(DWORD err,char*dest) +{ + struct WSErrorEntry *e; + for (e = WSErrors;e->description;e++) + { + if (e->error == err) + { + strcpy(dest,e->description); + return 1; + } + } + return 0; +} + + +struct MessageDLL{ + const char *dll_name; + void *handle; + int loaded; /* BOOL */ +}dlls[]={ + {"netmsg.dll",0,0}, + {"winsock.dll",0,0}, + {"wsock32.dll",0,0}, + {"ws2_32.dll",0,0}, + {"wsock32n.dll",0,0}, + {"mswsock.dll",0,0}, + {"ws2help.dll",0,0}, + {"ws2thk.dll",0,0}, + {0,0,1} /* Last one, no dll, always loaded */ +}; + +#define DLLS_SIZE (sizeof(dlls)/sizeof(struct MessageDLL)) + +/* + * Returns a description of the socket error by first trying + * to find it in the lookup table, and if that fails, tries + * to load any of the winsock dlls to find that message. + * The DLL thing works from Nt4 (spX ?) up, but some special + * versions of winsock might have this aswell (seen on Win98 SE + * special install) / Magnus Naeslund (mag@fbab.net) + * + */ + +const char *winsock_strerror(int err){ + static char buf[512]; /* Not threadsafe */ + unsigned long flags; + int offs,i; + int success = LookupWSErrorMessage(err,buf); + + for (i=0;!success && i<DLLS_SIZE;i++) + { + + if (!dlls[i].loaded) + { + dlls[i].loaded = 1; /* Only load once */ + dlls[i].handle = (void*)LoadLibraryEx( + dlls[i].dll_name, + 0, + LOAD_LIBRARY_AS_DATAFILE); + } + + if (dlls[i].dll_name && !dlls[i].handle) + continue; /* Didn't load */ + + flags = FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS + | (dlls[i].handle?FORMAT_MESSAGE_FROM_HMODULE:0); + + success = 0 != FormatMessage( + flags, + dlls[i].handle,err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf,sizeof(buf)-64, + 0 + ); + } + + if (!success) + { + sprintf(buf,"Unknown socket error (0x%08X/%lu)",err,err); + } + else + { + buf[sizeof(buf)-1]='\0'; + offs = strlen(buf); + if (offs>sizeof(buf)-64) + offs = sizeof(buf)-64; + sprintf(buf+offs," (0x%08X/%lu)",err,err); + } + return buf; +} + |