WvStreams
wverror.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * A class for managing error numbers and strings.  See wverror.h.
00006  */
00007 #include "wverror.h"
00008 #include <assert.h>
00009 
00010 #ifdef _WIN32
00011 #include "windows.h"
00012 
00013 struct WvErrMap {
00014     int num;
00015     const char *str;
00016 };
00017 
00018 static WvErrMap wverrmap[] = {
00019     { WSAEINTR, "Interrupted" },
00020     { WSAEBADF, "Bad file descriptor" },
00021     { WSAEACCES, "Access denied" },
00022     { WSAEFAULT, "Bad address" },
00023     { WSAEINVAL, "Invalid argument" },
00024     { WSAEMFILE, "Too many open files" },
00025     { WSAEWOULDBLOCK, "Operation would block" },
00026     { WSAEINPROGRESS, "Operation now in progress" },
00027     { WSAEALREADY, "Operation already in progress" },
00028     { WSAENOTSOCK, "Socket operation on non-socket" },
00029     { WSAEDESTADDRREQ, "Destination address required" },
00030     { WSAEMSGSIZE, "Message too long" },
00031     { WSAEPROTOTYPE, "Protocol wrong type for socket" },
00032     { WSAENOPROTOOPT, "Protocol not available" },
00033     { WSAEPROTONOSUPPORT, "Protocol not supported" },
00034     { WSAESOCKTNOSUPPORT, "Socket type not supported" },
00035     { WSAEOPNOTSUPP, "Operation not supported on transport endpoint" },
00036     { WSAEPFNOSUPPORT, "Protocol family not supported" },
00037     { WSAEAFNOSUPPORT, "Address family not supported by protocol" },
00038     { WSAEADDRINUSE, "Address already in use" },
00039     { WSAEADDRNOTAVAIL, "Cannot assign requested address" },
00040     { WSAENETDOWN, "Network is down" },
00041     { WSAENETUNREACH, "Network is unreachable" },
00042     { WSAENETRESET, "Network dropped connection because of reset" },
00043     { WSAECONNABORTED, "Software caused connection abort" },
00044     { WSAECONNRESET, "Connection reset by peer" },
00045     { WSAENOBUFS, "No buffer space available" },
00046     { WSAEISCONN, "Transport endpoint is already connected" },
00047     { WSAENOTCONN, "Transport endpoint is not connected" },
00048     { WSAESHUTDOWN, "Cannot send after transport endpoint shutdown" },
00049     { WSAETOOMANYREFS, "Too many references: cannot splice" },
00050     { WSAETIMEDOUT, "Connection timed out" },
00051     { WSAECONNREFUSED, "Connection refused" },
00052     { WSAELOOP, "Too many symbolic links encountered" },
00053     { WSAENAMETOOLONG, "File name too long" },
00054     { WSAEHOSTDOWN, "Host is down" },
00055     { WSAEHOSTUNREACH, "No route to host" },
00056     { WSAENOTEMPTY, "Directory not empty" },
00057     { WSAEPROCLIM, "Process limit reached" },
00058     { WSAEUSERS, "Too many users" },
00059     { WSAEDQUOT, "Disk quota exceeded" },
00060     { WSAESTALE, "Stale file handle" },
00061     { WSAEREMOTE, "Object is remote" },
00062     { WSAEDISCON, "Disconnected" },
00063     { WSAENOMORE, "No more data" },
00064     { WSAECANCELLED, "Operation cancelled" },
00065     { WSAEINVALIDPROCTABLE, "Invalid process table" },
00066     { WSAEINVALIDPROVIDER, "Invalid provider" },
00067     { WSAEPROVIDERFAILEDINIT, "Provider failed to initialize" },
00068     { WSAEREFUSED, "Operation refused" },
00069     { 0, NULL }
00070 };
00071 
00072 static const char *wv_errmap(int errnum)
00073 {
00074     
00075     for (WvErrMap *i = wverrmap; i->num; i++)
00076         if (i->num == errnum)
00077             return i->str;
00078     return NULL;
00079 }
00080 
00081 #endif
00082 
00083 WvErrorBase::~WvErrorBase()
00084 {
00085     // nothing special
00086 }
00087 
00088 
00089 // win32's strerror() function is incredibly weak, so we'll provide a better
00090 // one.
00091 WvString WvErrorBase::strerror(int errnum)
00092 {
00093     assert(errnum >= 0);
00094 
00095 #ifndef _WIN32
00096     return ::strerror(errnum);
00097 #else
00098     const char *wverr = wv_errmap(errnum);
00099     if (wverr)
00100         return wverr;
00101     else if (errnum >= WSABASEERR && errnum < WSABASEERR+2000)
00102     {
00103         // otherwise, an unrecognized winsock error: try getting the error
00104         // message from win32.
00105         char msg[4096];
00106         const HMODULE module = GetModuleHandle("winsock.dll");
00107         DWORD result = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
00108                          module, errnum, 0, msg, sizeof(msg), 0);
00109         if (result)
00110             return msg;
00111             
00112         DWORD e = GetLastError();
00113         return WvString("Unknown format %s for error %s", e, errnum);
00114     }
00115     else
00116     {
00117         const char *str = ::strerror(errnum);
00118         if (!strcmp(str, "Unknown error"))
00119             return WvString("Unknown win32 error #%s", errnum);
00120         else
00121             return str;
00122     }
00123 #endif
00124 }
00125 
00126 
00127 WvString WvErrorBase::errstr() const
00128 {
00129     int errnum = geterr();
00130     
00131     if (errnum < 0)
00132     {
00133         assert(!!errstring);
00134         return errstring;
00135     }
00136     else
00137     {
00138         if (!!errstring) return errstring;
00139         return WvErrorBase::strerror(errnum);
00140     }
00141 }
00142 
00143 
00144 void WvErrorBase::seterr(int _errnum)
00145 {
00146     if (!errnum)
00147     {
00148         assert(_errnum != -1 || !!errstring
00149             && "attempt to set errnum to -1 without also setting errstring");
00150 #ifdef _WIN32
00151         if (_errnum == WSAECONNABORTED)
00152             _errnum = WSAECONNREFUSED; // work around WINE bug
00153 #endif
00154         errnum = _errnum;
00155     }
00156 }
00157 
00158 
00159 void WvErrorBase::seterr(WvStringParm specialerr)
00160 {
00161     assert(!!specialerr);
00162     if (!errnum)
00163     {
00164         errstring = specialerr;
00165         seterr(-1);
00166     }
00167 }
00168 
00169 
00170 void WvErrorBase::seterr(const WvErrorBase &err)
00171 {
00172     if (err.geterr() > 0)
00173         seterr(err.geterr());
00174     else if (err.geterr() < 0)
00175         seterr(err.errstr());
00176 }
00177 
00178 
00179 void WvErrorBase::seterr_both(int _errnum, WvStringParm specialerr)
00180 {
00181     assert(!!specialerr);
00182     if (!errnum)
00183     {
00184         errstring = specialerr;
00185         seterr(_errnum);
00186     }
00187 }