diff --git a/lib/base/XBase.cpp b/lib/base/XBase.cpp index 0d1d5b32..c72c425e 100644 --- a/lib/base/XBase.cpp +++ b/lib/base/XBase.cpp @@ -18,6 +18,7 @@ // win32 wants a const char* argument to std::exception c'tor #if WINDOWS_LIKE +#include #define STDEXCEPTARG "" #endif @@ -85,17 +86,32 @@ XBase::format(const char* /*id*/, const char* fmt, ...) const throw() // MXErrno::MXErrno() : - m_errno(errno) +#if WINDOWS_LIKE + m_errno(GetLastError()), +#else + m_errno(errno), +#endif + m_string(NULL) { // do nothing } MXErrno::MXErrno(int err) : - m_errno(err) + m_errno(err), + m_string(NULL) { // do nothing } +MXErrno::~MXErrno() +{ + if (m_string != NULL) { +#if WINDOWS_LIKE + LocalFree(m_string); +#endif + } +} + int MXErrno::getErrno() const { @@ -105,5 +121,23 @@ MXErrno::getErrno() const const char* MXErrno::getErrstr() const { +#if WINDOWS_LIKE + if (m_string != NULL) { + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + 0, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&m_string, + 0, + NULL) == 0) { + m_string = NULL; + return "unknown error"; + } + } + return m_string; +#else return strerror(m_errno); +#endif } diff --git a/lib/base/XBase.h b/lib/base/XBase.h index 579e328e..aac354f0 100644 --- a/lib/base/XBase.h +++ b/lib/base/XBase.h @@ -55,7 +55,7 @@ private: //! Mix-in for handling \c errno /*! This mix-in class for exception classes provides storage and query of -\c errno. +\c errno. On Windows, it uses GetLastError() instead of errno. */ class MXErrno { public: @@ -63,6 +63,7 @@ public: MXErrno(); //! Save \c err as the error code MXErrno(int err); + virtual ~MXErrno(); //! @name accessors //@{ @@ -71,12 +72,13 @@ public: int getErrno() const; //! Get the human readable string for the error code - const char* getErrstr() const; + virtual const char* getErrstr() const; //@} private: int m_errno; + mutable char* m_string; }; #endif diff --git a/lib/io/XIO.cpp b/lib/io/XIO.cpp index 6c7a0552..710c4190 100644 --- a/lib/io/XIO.cpp +++ b/lib/io/XIO.cpp @@ -14,34 +14,6 @@ #include "XIO.h" -// -// XIOErrno -// - -XIOErrno::XIOErrno() : - MXErrno() -{ - // do nothing -} - -XIOErrno::XIOErrno(int err) : - MXErrno(err) -{ - // do nothing -} - - -// -// XIOClose -// - -CString -XIOClose::getWhat() const throw() -{ - return format("XIOClose", "close: %{1}", XIOErrno::getErrstr()); -} - - // // XIOClosed // diff --git a/lib/io/XIO.h b/lib/io/XIO.h index 4bbd10c4..3cb1d944 100644 --- a/lib/io/XIO.h +++ b/lib/io/XIO.h @@ -20,22 +20,11 @@ //! Generic I/O exception class XIO : public XBase { }; -//! Generic I/O exception using \c errno -class XIOErrno : public XIO, public MXErrno { -public: - XIOErrno(); - XIOErrno(int); -}; - //! I/O closing exception /*! Thrown if a stream cannot be closed. */ -class XIOClose: public XIOErrno { -protected: - // XBase overrides - virtual CString getWhat() const throw(); -}; +class XIOClose : public XIO { }; //! I/O already closed exception /*! diff --git a/lib/net/CTCPListenSocket.cpp b/lib/net/CTCPListenSocket.cpp index 57203c31..83278166 100644 --- a/lib/net/CTCPListenSocket.cpp +++ b/lib/net/CTCPListenSocket.cpp @@ -84,7 +84,7 @@ CTCPListenSocket::close() throw XIOClosed(); } if (CNetwork::close(m_fd) == CNetwork::Error) { - throw XIOClose(); + throw XSocketIOClose(); } m_fd = CNetwork::Null; } diff --git a/lib/net/CTCPSocket.cpp b/lib/net/CTCPSocket.cpp index b0d6f18b..aa8dd065 100644 --- a/lib/net/CTCPSocket.cpp +++ b/lib/net/CTCPSocket.cpp @@ -114,7 +114,7 @@ CTCPSocket::close() // close socket if (m_fd != CNetwork::Null) { if (CNetwork::close(m_fd) == CNetwork::Error) { - throw XIOClose(); + throw XSocketIOClose(); } m_fd = CNetwork::Null; } diff --git a/lib/net/XSocket.cpp b/lib/net/XSocket.cpp index ccc7ab04..8d372675 100644 --- a/lib/net/XSocket.cpp +++ b/lib/net/XSocket.cpp @@ -13,6 +13,7 @@ */ #include "XSocket.h" +#include "CNetwork.h" // // XSocketAddress @@ -71,7 +72,7 @@ XSocketAddress::getWhat() const throw() // XSocketErrno::XSocketErrno() : - MXErrno() + MXErrno(CNetwork::getsockerror()) { // do nothing } @@ -82,6 +83,92 @@ XSocketErrno::XSocketErrno(int err) : // do nothing } +const char* +XSocketErrno::getErrstr() const +{ +#if WINDOWS_LIKE + // built-in windows function for looking up error message strings + // may not look up network error messages correctly. we'll have + // to do it ourself. + static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = { + /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"}, + /* 10009 */{WSAEBADF, "Bad file handle"}, + /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"}, + /* 10014 */{WSAEFAULT, "WSAEFAULT"}, + /* 10022 */{WSAEINVAL, "WSAEINVAL"}, + /* 10024 */{WSAEMFILE, "No more file descriptors available"}, + /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"}, + /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"}, + /* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"}, + /* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"}, + /* 10039 */{WSAEDESTADDRREQ, "A destination address is required"}, + /* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"}, + /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"}, + /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"}, + /* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"}, + /* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"}, + /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"}, + /* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"}, + /* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"}, + /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"}, + /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"}, + /* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"}, + /* 10051 */{WSAENETUNREACH, "The network can't be reached from this hos at this time"}, + /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"}, + /* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"}, + /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"}, + /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"}, + /* 10056 */{WSAEISCONN, "The socket is already connected"}, + /* 10057 */{WSAENOTCONN, "The socket is not connected"}, + /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"}, + /* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"}, + /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"}, + /* 10061 */{WSAECONNREFUSED, "The attempt to connect was forcefully rejected"}, + /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"}, + /* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"}, + /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"}, + /* 10065 */{WSAEHOSTUNREACH, "No route to host"}, + /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"}, + /* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"}, + /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"}, + /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"}, + /* 10070 */{WSAESTALE, "Undocumented WinSock error code"}, + /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"}, + /* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"}, + /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"}, + /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"}, + /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"}, + /* 11001 */{WSAHOST_NOT_FOUND, "Host not found"}, + /* 11002 */{WSATRY_AGAIN, "Host not found"}, + /* 11003 */{WSANO_RECOVERY, "Host name lookup error"}, + /* 11004 */{WSANO_DATA, "No data for host"}, + /* end */{0, NULL} + }; + + const int err = getErrno(); + for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) { + if (s_netErrorCodes[i].m_code == err) { + return s_netErrorCodes[i].m_msg; + } + } +#endif + + // not a network error code. fallback to system error message. + return MXErrno::getErrstr(); +} + + +// +// XSocketIOClose +// + +CString +XSocketIOClose::getWhat() const throw() +{ + return format("XSocketIOClose", "close: %{1}", + getErrstr()); +} + // // XSocketBind @@ -90,7 +177,8 @@ XSocketErrno::XSocketErrno(int err) : CString XSocketBind::getWhat() const throw() { - return format("XSocketBind", "cannot bind address"); + return format("XSocketBind", "cannot bind address: %{1}", + getErrstr()); } @@ -101,7 +189,8 @@ XSocketBind::getWhat() const throw() CString XSocketConnect::getWhat() const throw() { - return format("XSocketConnect", "cannot connect socket"); + return format("XSocketConnect", "cannot connect socket: %{1}", + getErrstr()); } @@ -112,5 +201,6 @@ XSocketConnect::getWhat() const throw() CString XSocketCreate::getWhat() const throw() { - return format("XSocketCreate", "cannot create socket"); + return format("XSocketCreate", "cannot create socket: %{1}", + getErrstr()); } diff --git a/lib/net/XSocket.h b/lib/net/XSocket.h index fd67ecb1..131a3f1f 100644 --- a/lib/net/XSocket.h +++ b/lib/net/XSocket.h @@ -15,6 +15,7 @@ #ifndef XSOCKET_H #define XSOCKET_H +#include "XIO.h" #include "XBase.h" #include "CString.h" #include "BasicTypes.h" @@ -61,17 +62,30 @@ private: }; //! Generic socket exception using \c errno -class XSocketErrno : public XSocket, public MXErrno { +class XSocketErrno : public MXErrno { public: XSocketErrno(); XSocketErrno(int); + + // MXErrno overrides + virtual const char* getErrstr() const; +}; + +//! I/O closing exception +/*! +Thrown if a stream cannot be closed. +*/ +class XSocketIOClose : public XIOClose, public XSocketErrno { +protected: + // XBase overrides + virtual CString getWhat() const throw(); }; //! Socket cannot bind address exception /*! Thrown when a socket cannot be bound to an address. */ -class XSocketBind : public XSocketErrno { +class XSocketBind : public XSocket, public XSocketErrno { public: XSocketBind() { } XSocketBind(int e) : XSocketErrno(e) { } @@ -96,7 +110,7 @@ public: /*! Thrown when a socket cannot connect to a remote endpoint. */ -class XSocketConnect : public XSocketErrno { +class XSocketConnect : public XSocket, public XSocketErrno { public: XSocketConnect() { } XSocketConnect(int e) : XSocketErrno(e) { } @@ -110,7 +124,7 @@ protected: /*! Thrown when a socket cannot be created (by the operating system). */ -class XSocketCreate : public XSocketErrno { +class XSocketCreate : public XSocket, public XSocketErrno { public: XSocketCreate() { } XSocketCreate(int e) : XSocketErrno(e) { }