summaryrefslogtreecommitdiffstats
path: root/lib/asio/impl/error_code.ipp
blob: 0c8a82782f69f7c4da29b99434effe4b0e0e52b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//
// impl/error_code.ipp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 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_IMPL_ERROR_CODE_IPP
#define ASIO_IMPL_ERROR_CODE_IPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
# include <winerror.h>
#elif defined(ASIO_WINDOWS_RUNTIME)
# include <windows.h>
#else
# include <cerrno>
# include <cstring>
# include <string>
#endif
#include "asio/detail/local_free_on_block_exit.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/error_code.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {
namespace detail {

class system_category : public error_category
{
public:
  const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
  {
    return "asio.system";
  }

  std::string message(int value) const
  {
#if defined(ASIO_WINDOWS_RUNTIME) || defined(ASIO_WINDOWS_APP)
    std::wstring wmsg(128, wchar_t());
    for (;;)
    {
      DWORD wlength = ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
          | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,
          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
          &wmsg[0], static_cast<DWORD>(wmsg.size()), 0);
      if (wlength == 0 && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
      {
        wmsg.resize(wmsg.size() + wmsg.size() / 2);
        continue;
      }
      if (wlength && wmsg[wlength - 1] == '\n')
        --wlength;
      if (wlength && wmsg[wlength - 1] == '\r')
        --wlength;
      if (wlength)
      {
        std::string msg(wlength * 2, char());
        int length = ::WideCharToMultiByte(CP_ACP, 0,
            wmsg.c_str(), static_cast<int>(wlength),
            &msg[0], static_cast<int>(wlength * 2), 0, 0);
        if (length <= 0)
          return "asio.system error";
        msg.resize(static_cast<std::size_t>(length));
        return msg;
      }
      else
        return "asio.system error";
    }
#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
    char* msg = 0;
    DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
        | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);
    detail::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)
      return msg;
    else
      return "asio.system error";
#else // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)
#if !defined(__sun)
    if (value == ECANCELED)
      return "Operation aborted.";
#endif // !defined(__sun)
#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__)
    using namespace std;
    return strerror(value);
#else
    char buf[256] = "";
    using namespace std;
    return strerror_result(strerror_r(value, buf, sizeof(buf)), buf);
#endif
#endif // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)
  }

#if defined(ASIO_HAS_STD_ERROR_CODE)
  std::error_condition default_error_condition(
      int ev) const ASIO_ERROR_CATEGORY_NOEXCEPT
  {
    switch (ev)
    {
    case access_denied:
      return std::errc::permission_denied;
    case address_family_not_supported:
      return std::errc::address_family_not_supported;
    case address_in_use:
      return std::errc::address_in_use;
    case already_connected:
      return std::errc::already_connected;
    case already_started:
      return std::errc::connection_already_in_progress;
    case broken_pipe:
      return std::errc::broken_pipe;
    case connection_aborted:
      return std::errc::connection_aborted;
    case connection_refused:
      return std::errc::connection_refused;
    case connection_reset:
      return std::errc::connection_reset;
    case bad_descriptor:
      return std::errc::bad_file_descriptor;
    case fault:
      return std::errc::bad_address;
    case host_unreachable:
      return std::errc::host_unreachable;
    case in_progress:
      return std::errc::operation_in_progress;
    case interrupted:
      return std::errc::interrupted;
    case invalid_argument:
      return std::errc::invalid_argument;
    case message_size:
      return std::errc::message_size;
    case name_too_long:
      return std::errc::filename_too_long;
    case network_down:
      return std::errc::network_down;
    case network_reset:
      return std::errc::network_reset;
    case network_unreachable:
      return std::errc::network_unreachable;
    case no_descriptors:
      return std::errc::too_many_files_open;
    case no_buffer_space:
      return std::errc::no_buffer_space;
    case no_memory:
      return std::errc::not_enough_memory;
    case no_permission:
      return std::errc::operation_not_permitted;
    case no_protocol_option:
      return std::errc::no_protocol_option;
    case no_such_device:
      return std::errc::no_such_device;
    case not_connected:
      return std::errc::not_connected;
    case not_socket:
      return std::errc::not_a_socket;
    case operation_aborted:
      return std::errc::operation_canceled;
    case operation_not_supported:
      return std::errc::operation_not_supported;
    case shut_down:
      return std::make_error_condition(ev, *this);
    case timed_out:
      return std::errc::timed_out;
    case try_again:
      return std::errc::resource_unavailable_try_again;
    case would_block:
      return std::errc::operation_would_block;
    default:
      return std::make_error_condition(ev, *this);
  }
#endif // defined(ASIO_HAS_STD_ERROR_CODE)

private:
  // Helper function to adapt the result from glibc's variant of strerror_r.
  static const char* strerror_result(int, const char* s) { return s; }
  static const char* strerror_result(const char* s, const char*) { return s; }
};

} // namespace detail

const error_category& system_category()
{
  static detail::system_category instance;
  return instance;
}

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_IMPL_ERROR_CODE_IPP