388 lines
10 KiB
C++
388 lines
10 KiB
C++
|
//
|
||
|
// error.hpp
|
||
|
// ~~~~~~~~~
|
||
|
//
|
||
|
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||
|
//
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
//
|
||
|
|
||
|
#ifndef ASIO_ERROR_HPP
|
||
|
#define ASIO_ERROR_HPP
|
||
|
|
||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||
|
# pragma once
|
||
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||
|
|
||
|
#include "asio/detail/push_options.hpp"
|
||
|
|
||
|
#include "asio/detail/push_options.hpp"
|
||
|
#include <boost/config.hpp>
|
||
|
#include <boost/scoped_ptr.hpp>
|
||
|
#include <cerrno>
|
||
|
#include <cstring>
|
||
|
#include <exception>
|
||
|
#include <string>
|
||
|
#include <boost/detail/workaround.hpp>
|
||
|
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||
|
# include <iostream>
|
||
|
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||
|
#include "asio/detail/pop_options.hpp"
|
||
|
|
||
|
#include "asio/detail/socket_types.hpp"
|
||
|
#include "asio/detail/win_local_free_on_block_exit.hpp"
|
||
|
|
||
|
namespace asio {
|
||
|
|
||
|
#if defined(GENERATING_DOCUMENTATION)
|
||
|
/// INTERNAL ONLY.
|
||
|
# define ASIO_SOCKET_ERROR(e) implementation_defined
|
||
|
/// INTERNAL ONLY.
|
||
|
# define ASIO_NETDB_ERROR(e) implementation_defined
|
||
|
/// INTERNAL ONLY.
|
||
|
# define ASIO_GETADDRINFO_ERROR(e) implementation_defined
|
||
|
/// INTERNAL ONLY.
|
||
|
# define ASIO_OS_ERROR(e_win, e_posix) implementation_defined
|
||
|
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||
|
# define ASIO_SOCKET_ERROR(e) WSA ## e
|
||
|
# define ASIO_NETDB_ERROR(e) WSA ## e
|
||
|
# define ASIO_GETADDRINFO_ERROR(e) e
|
||
|
# define ASIO_OS_ERROR(e_win, e_posix) e_win
|
||
|
#else
|
||
|
# define ASIO_SOCKET_ERROR(e) e
|
||
|
# define ASIO_NETDB_ERROR(e) 16384 + e
|
||
|
# define ASIO_GETADDRINFO_ERROR(e) 32768 + e
|
||
|
# define ASIO_OS_ERROR(e_win, e_posix) e_posix
|
||
|
#endif
|
||
|
|
||
|
/// The error class is used to encapsulate system error codes.
|
||
|
class error
|
||
|
: public std::exception
|
||
|
{
|
||
|
public:
|
||
|
/// Error codes.
|
||
|
enum code_type
|
||
|
{
|
||
|
/// Permission denied.
|
||
|
access_denied = ASIO_SOCKET_ERROR(EACCES),
|
||
|
|
||
|
/// Address family not supported by protocol.
|
||
|
address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT),
|
||
|
|
||
|
/// Address already in use.
|
||
|
address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE),
|
||
|
|
||
|
/// Transport endpoint is already connected.
|
||
|
already_connected = ASIO_SOCKET_ERROR(EISCONN),
|
||
|
|
||
|
/// Operation already in progress.
|
||
|
already_started = ASIO_SOCKET_ERROR(EALREADY),
|
||
|
|
||
|
/// A connection has been aborted.
|
||
|
connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED),
|
||
|
|
||
|
/// Connection refused.
|
||
|
connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED),
|
||
|
|
||
|
/// Connection reset by peer.
|
||
|
connection_reset = ASIO_SOCKET_ERROR(ECONNRESET),
|
||
|
|
||
|
/// Bad file descriptor.
|
||
|
bad_descriptor = ASIO_SOCKET_ERROR(EBADF),
|
||
|
|
||
|
/// End of file or stream.
|
||
|
eof = ASIO_OS_ERROR(ERROR_HANDLE_EOF, -1),
|
||
|
|
||
|
/// Bad address.
|
||
|
fault = ASIO_SOCKET_ERROR(EFAULT),
|
||
|
|
||
|
/// Host not found (authoritative).
|
||
|
host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND),
|
||
|
|
||
|
/// Host not found (non-authoritative).
|
||
|
host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN),
|
||
|
|
||
|
/// No route to host.
|
||
|
host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH),
|
||
|
|
||
|
/// Operation now in progress.
|
||
|
in_progress = ASIO_SOCKET_ERROR(EINPROGRESS),
|
||
|
|
||
|
/// Interrupted system call.
|
||
|
interrupted = ASIO_SOCKET_ERROR(EINTR),
|
||
|
|
||
|
/// Invalid argument.
|
||
|
invalid_argument = ASIO_SOCKET_ERROR(EINVAL),
|
||
|
|
||
|
/// Message too long.
|
||
|
message_size = ASIO_SOCKET_ERROR(EMSGSIZE),
|
||
|
|
||
|
/// Network is down.
|
||
|
network_down = ASIO_SOCKET_ERROR(ENETDOWN),
|
||
|
|
||
|
/// Network dropped connection on reset.
|
||
|
network_reset = ASIO_SOCKET_ERROR(ENETRESET),
|
||
|
|
||
|
/// Network is unreachable.
|
||
|
network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH),
|
||
|
|
||
|
/// Too many open files.
|
||
|
no_descriptors = ASIO_SOCKET_ERROR(EMFILE),
|
||
|
|
||
|
/// No buffer space available.
|
||
|
no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS),
|
||
|
|
||
|
/// The query is valid but does not have associated address data.
|
||
|
no_data = ASIO_NETDB_ERROR(NO_DATA),
|
||
|
|
||
|
/// Cannot allocate memory.
|
||
|
no_memory = ASIO_OS_ERROR(ERROR_OUTOFMEMORY, ENOMEM),
|
||
|
|
||
|
/// Operation not permitted.
|
||
|
no_permission = ASIO_OS_ERROR(ERROR_ACCESS_DENIED, EPERM),
|
||
|
|
||
|
/// Protocol not available.
|
||
|
no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT),
|
||
|
|
||
|
/// A non-recoverable error occurred.
|
||
|
no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY),
|
||
|
|
||
|
/// Transport endpoint is not connected.
|
||
|
not_connected = ASIO_SOCKET_ERROR(ENOTCONN),
|
||
|
|
||
|
/// Socket operation on non-socket.
|
||
|
not_socket = ASIO_SOCKET_ERROR(ENOTSOCK),
|
||
|
|
||
|
/// Operation not supported.
|
||
|
not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP),
|
||
|
|
||
|
/// Operation cancelled.
|
||
|
operation_aborted = ASIO_OS_ERROR(ERROR_OPERATION_ABORTED, ECANCELED),
|
||
|
|
||
|
/// The service is not supported for the given socket type.
|
||
|
service_not_found = ASIO_OS_ERROR(
|
||
|
WSATYPE_NOT_FOUND,
|
||
|
ASIO_GETADDRINFO_ERROR(EAI_SERVICE)),
|
||
|
|
||
|
/// The socket type is not supported.
|
||
|
socket_type_not_supported = ASIO_OS_ERROR(
|
||
|
WSAESOCKTNOSUPPORT,
|
||
|
ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)),
|
||
|
|
||
|
/// Cannot send after transport endpoint shutdown.
|
||
|
shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN),
|
||
|
|
||
|
/// Success.
|
||
|
success = 0,
|
||
|
|
||
|
/// Connection timed out.
|
||
|
timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT),
|
||
|
|
||
|
/// Resource temporarily unavailable.
|
||
|
try_again = ASIO_OS_ERROR(ERROR_RETRY, EAGAIN),
|
||
|
|
||
|
/// The socket is marked non-blocking and the requested operation would
|
||
|
/// block.
|
||
|
would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK)
|
||
|
};
|
||
|
|
||
|
/// Default constructor.
|
||
|
error()
|
||
|
: code_(success)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// Construct with a specific error code.
|
||
|
error(int code)
|
||
|
: code_(code)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// Copy constructor.
|
||
|
error(const error& e)
|
||
|
: std::exception(e),
|
||
|
code_(e.code_)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// Destructor.
|
||
|
virtual ~error() throw ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// Assignment operator.
|
||
|
error& operator=(const error& e)
|
||
|
{
|
||
|
code_ = e.code_;
|
||
|
what_.reset();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/// Get a string representation of the exception.
|
||
|
virtual const char* what() const throw ()
|
||
|
{
|
||
|
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
|
||
|
try
|
||
|
{
|
||
|
if (!what_)
|
||
|
{
|
||
|
char* msg = 0;
|
||
|
DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||
|
| FORMAT_MESSAGE_FROM_SYSTEM
|
||
|
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, code_,
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
|
||
|
detail::win_local_free_on_block_exit local_free_obj(msg);
|
||
|
if (length && msg[length - 1] == '\n')
|
||
|
msg[--length] = '\0';
|
||
|
if (length && msg[length - 1] == '\r')
|
||
|
msg[--length] = '\0';
|
||
|
if (length)
|
||
|
what_.reset(new std::string(msg));
|
||
|
else
|
||
|
return "asio error";
|
||
|
}
|
||
|
return what_->c_str();
|
||
|
}
|
||
|
catch (std::exception&)
|
||
|
{
|
||
|
return "asio error";
|
||
|
}
|
||
|
#else // defined(BOOST_WINDOWS)
|
||
|
switch (code_)
|
||
|
{
|
||
|
case error::eof:
|
||
|
return "End of file.";
|
||
|
case error::host_not_found:
|
||
|
return "Host not found (authoritative).";
|
||
|
case error::host_not_found_try_again:
|
||
|
return "Host not found (non-authoritative), try again later.";
|
||
|
case error::no_recovery:
|
||
|
return "A non-recoverable error occurred during database lookup.";
|
||
|
case error::no_data:
|
||
|
return "The query is valid, but it does not have associated data.";
|
||
|
#if !defined(__sun)
|
||
|
case error::operation_aborted:
|
||
|
return "Operation aborted.";
|
||
|
#endif // !defined(__sun)
|
||
|
case error::service_not_found:
|
||
|
return "Service not found.";
|
||
|
case error::socket_type_not_supported:
|
||
|
return "Socket type not supported.";
|
||
|
default:
|
||
|
#if defined(__sun) || defined(__QNX__)
|
||
|
return strerror(code_);
|
||
|
#elif defined(__MACH__) && defined(__APPLE__) \
|
||
|
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||
|
try
|
||
|
{
|
||
|
char buf[256] = "";
|
||
|
strerror_r(code_, buf, sizeof(buf));
|
||
|
what_.reset(new std::string(buf));
|
||
|
return what_->c_str();
|
||
|
}
|
||
|
catch (std::exception&)
|
||
|
{
|
||
|
return "asio error";
|
||
|
}
|
||
|
#else
|
||
|
try
|
||
|
{
|
||
|
char buf[256] = "";
|
||
|
what_.reset(new std::string(strerror_r(code_, buf, sizeof(buf))));
|
||
|
return what_->c_str();
|
||
|
}
|
||
|
catch (std::exception&)
|
||
|
{
|
||
|
return "asio error";
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
#endif // defined(BOOST_WINDOWS)
|
||
|
}
|
||
|
|
||
|
/// Get the code associated with the error.
|
||
|
int code() const
|
||
|
{
|
||
|
return code_;
|
||
|
}
|
||
|
|
||
|
struct unspecified_bool_type_t
|
||
|
{
|
||
|
};
|
||
|
|
||
|
typedef unspecified_bool_type_t* unspecified_bool_type;
|
||
|
|
||
|
/// Operator returns non-null if there is a non-success error code.
|
||
|
operator unspecified_bool_type() const
|
||
|
{
|
||
|
if (code_ == success)
|
||
|
return 0;
|
||
|
else
|
||
|
return reinterpret_cast<unspecified_bool_type>(1);
|
||
|
}
|
||
|
|
||
|
/// Operator to test if the error represents success.
|
||
|
bool operator!() const
|
||
|
{
|
||
|
return code_ == success;
|
||
|
}
|
||
|
|
||
|
/// Equality operator to compare two error objects.
|
||
|
friend bool operator==(const error& e1, const error& e2)
|
||
|
{
|
||
|
return e1.code_ == e2.code_;
|
||
|
}
|
||
|
|
||
|
/// Inequality operator to compare two error objects.
|
||
|
friend bool operator!=(const error& e1, const error& e2)
|
||
|
{
|
||
|
return e1.code_ != e2.code_;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// The code associated with the error.
|
||
|
int code_;
|
||
|
|
||
|
// The string representation of the error.
|
||
|
mutable boost::scoped_ptr<std::string> what_;
|
||
|
};
|
||
|
|
||
|
/// Output the string associated with an error.
|
||
|
/**
|
||
|
* Used to output a human-readable string that is associated with an error.
|
||
|
*
|
||
|
* @param os The output stream to which the string will be written.
|
||
|
*
|
||
|
* @param e The error to be written.
|
||
|
*
|
||
|
* @return The output stream.
|
||
|
*
|
||
|
* @relates asio::error
|
||
|
*/
|
||
|
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||
|
std::ostream& operator<<(std::ostream& os, const error& e)
|
||
|
{
|
||
|
os << e.what();
|
||
|
return os;
|
||
|
}
|
||
|
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||
|
template <typename Ostream>
|
||
|
Ostream& operator<<(Ostream& os, const error& e)
|
||
|
{
|
||
|
os << e.what();
|
||
|
return os;
|
||
|
}
|
||
|
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||
|
|
||
|
} // namespace asio
|
||
|
|
||
|
#undef ASIO_SOCKET_ERROR
|
||
|
#undef ASIO_NETDB_ERROR
|
||
|
#undef ASIO_GETADDRINFO_ERROR
|
||
|
#undef ASIO_OS_ERROR
|
||
|
|
||
|
#include "asio/detail/pop_options.hpp"
|
||
|
|
||
|
#endif // ASIO_ERROR_HPP
|