added better network error message support.
This commit is contained in:
parent
4586f88188
commit
fec679cfe5
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
// win32 wants a const char* argument to std::exception c'tor
|
// win32 wants a const char* argument to std::exception c'tor
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
#include <windows.h>
|
||||||
#define STDEXCEPTARG ""
|
#define STDEXCEPTARG ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -85,17 +86,32 @@ XBase::format(const char* /*id*/, const char* fmt, ...) const throw()
|
||||||
//
|
//
|
||||||
|
|
||||||
MXErrno::MXErrno() :
|
MXErrno::MXErrno() :
|
||||||
m_errno(errno)
|
#if WINDOWS_LIKE
|
||||||
|
m_errno(GetLastError()),
|
||||||
|
#else
|
||||||
|
m_errno(errno),
|
||||||
|
#endif
|
||||||
|
m_string(NULL)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
MXErrno::MXErrno(int err) :
|
MXErrno::MXErrno(int err) :
|
||||||
m_errno(err)
|
m_errno(err),
|
||||||
|
m_string(NULL)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MXErrno::~MXErrno()
|
||||||
|
{
|
||||||
|
if (m_string != NULL) {
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
LocalFree(m_string);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
MXErrno::getErrno() const
|
MXErrno::getErrno() const
|
||||||
{
|
{
|
||||||
|
@ -105,5 +121,23 @@ MXErrno::getErrno() const
|
||||||
const char*
|
const char*
|
||||||
MXErrno::getErrstr() const
|
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);
|
return strerror(m_errno);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ private:
|
||||||
//! Mix-in for handling \c errno
|
//! Mix-in for handling \c errno
|
||||||
/*!
|
/*!
|
||||||
This mix-in class for exception classes provides storage and query of
|
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 {
|
class MXErrno {
|
||||||
public:
|
public:
|
||||||
|
@ -63,6 +63,7 @@ public:
|
||||||
MXErrno();
|
MXErrno();
|
||||||
//! Save \c err as the error code
|
//! Save \c err as the error code
|
||||||
MXErrno(int err);
|
MXErrno(int err);
|
||||||
|
virtual ~MXErrno();
|
||||||
|
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -71,12 +72,13 @@ public:
|
||||||
int getErrno() const;
|
int getErrno() const;
|
||||||
|
|
||||||
//! Get the human readable string for the error code
|
//! Get the human readable string for the error code
|
||||||
const char* getErrstr() const;
|
virtual const char* getErrstr() const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_errno;
|
int m_errno;
|
||||||
|
mutable char* m_string;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,34 +14,6 @@
|
||||||
|
|
||||||
#include "XIO.h"
|
#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
|
// XIOClosed
|
||||||
//
|
//
|
||||||
|
|
13
lib/io/XIO.h
13
lib/io/XIO.h
|
@ -20,22 +20,11 @@
|
||||||
//! Generic I/O exception
|
//! Generic I/O exception
|
||||||
class XIO : public XBase { };
|
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
|
//! I/O closing exception
|
||||||
/*!
|
/*!
|
||||||
Thrown if a stream cannot be closed.
|
Thrown if a stream cannot be closed.
|
||||||
*/
|
*/
|
||||||
class XIOClose: public XIOErrno {
|
class XIOClose : public XIO { };
|
||||||
protected:
|
|
||||||
// XBase overrides
|
|
||||||
virtual CString getWhat() const throw();
|
|
||||||
};
|
|
||||||
|
|
||||||
//! I/O already closed exception
|
//! I/O already closed exception
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -84,7 +84,7 @@ CTCPListenSocket::close()
|
||||||
throw XIOClosed();
|
throw XIOClosed();
|
||||||
}
|
}
|
||||||
if (CNetwork::close(m_fd) == CNetwork::Error) {
|
if (CNetwork::close(m_fd) == CNetwork::Error) {
|
||||||
throw XIOClose();
|
throw XSocketIOClose();
|
||||||
}
|
}
|
||||||
m_fd = CNetwork::Null;
|
m_fd = CNetwork::Null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ CTCPSocket::close()
|
||||||
// close socket
|
// close socket
|
||||||
if (m_fd != CNetwork::Null) {
|
if (m_fd != CNetwork::Null) {
|
||||||
if (CNetwork::close(m_fd) == CNetwork::Error) {
|
if (CNetwork::close(m_fd) == CNetwork::Error) {
|
||||||
throw XIOClose();
|
throw XSocketIOClose();
|
||||||
}
|
}
|
||||||
m_fd = CNetwork::Null;
|
m_fd = CNetwork::Null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "XSocket.h"
|
#include "XSocket.h"
|
||||||
|
#include "CNetwork.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// XSocketAddress
|
// XSocketAddress
|
||||||
|
@ -71,7 +72,7 @@ XSocketAddress::getWhat() const throw()
|
||||||
//
|
//
|
||||||
|
|
||||||
XSocketErrno::XSocketErrno() :
|
XSocketErrno::XSocketErrno() :
|
||||||
MXErrno()
|
MXErrno(CNetwork::getsockerror())
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -82,6 +83,92 @@ XSocketErrno::XSocketErrno(int err) :
|
||||||
// do nothing
|
// 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
|
// XSocketBind
|
||||||
|
@ -90,7 +177,8 @@ XSocketErrno::XSocketErrno(int err) :
|
||||||
CString
|
CString
|
||||||
XSocketBind::getWhat() const throw()
|
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
|
CString
|
||||||
XSocketConnect::getWhat() const throw()
|
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
|
CString
|
||||||
XSocketCreate::getWhat() const throw()
|
XSocketCreate::getWhat() const throw()
|
||||||
{
|
{
|
||||||
return format("XSocketCreate", "cannot create socket");
|
return format("XSocketCreate", "cannot create socket: %{1}",
|
||||||
|
getErrstr());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#ifndef XSOCKET_H
|
#ifndef XSOCKET_H
|
||||||
#define XSOCKET_H
|
#define XSOCKET_H
|
||||||
|
|
||||||
|
#include "XIO.h"
|
||||||
#include "XBase.h"
|
#include "XBase.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "BasicTypes.h"
|
#include "BasicTypes.h"
|
||||||
|
@ -61,17 +62,30 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Generic socket exception using \c errno
|
//! Generic socket exception using \c errno
|
||||||
class XSocketErrno : public XSocket, public MXErrno {
|
class XSocketErrno : public MXErrno {
|
||||||
public:
|
public:
|
||||||
XSocketErrno();
|
XSocketErrno();
|
||||||
XSocketErrno(int);
|
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
|
//! Socket cannot bind address exception
|
||||||
/*!
|
/*!
|
||||||
Thrown when a socket cannot be bound to an address.
|
Thrown when a socket cannot be bound to an address.
|
||||||
*/
|
*/
|
||||||
class XSocketBind : public XSocketErrno {
|
class XSocketBind : public XSocket, public XSocketErrno {
|
||||||
public:
|
public:
|
||||||
XSocketBind() { }
|
XSocketBind() { }
|
||||||
XSocketBind(int e) : XSocketErrno(e) { }
|
XSocketBind(int e) : XSocketErrno(e) { }
|
||||||
|
@ -96,7 +110,7 @@ public:
|
||||||
/*!
|
/*!
|
||||||
Thrown when a socket cannot connect to a remote endpoint.
|
Thrown when a socket cannot connect to a remote endpoint.
|
||||||
*/
|
*/
|
||||||
class XSocketConnect : public XSocketErrno {
|
class XSocketConnect : public XSocket, public XSocketErrno {
|
||||||
public:
|
public:
|
||||||
XSocketConnect() { }
|
XSocketConnect() { }
|
||||||
XSocketConnect(int e) : XSocketErrno(e) { }
|
XSocketConnect(int e) : XSocketErrno(e) { }
|
||||||
|
@ -110,7 +124,7 @@ protected:
|
||||||
/*!
|
/*!
|
||||||
Thrown when a socket cannot be created (by the operating system).
|
Thrown when a socket cannot be created (by the operating system).
|
||||||
*/
|
*/
|
||||||
class XSocketCreate : public XSocketErrno {
|
class XSocketCreate : public XSocket, public XSocketErrno {
|
||||||
public:
|
public:
|
||||||
XSocketCreate() { }
|
XSocketCreate() { }
|
||||||
XSocketCreate(int e) : XSocketErrno(e) { }
|
XSocketCreate(int e) : XSocketErrno(e) { }
|
||||||
|
|
Loading…
Reference in New Issue