Commit 12f01906 authored by Dominik Charousset's avatar Dominik Charousset

Map WSA error codes to POSIX/STL error codes

parent 43e84135
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <system_error>
#include <type_traits> #include <type_traits>
#include "caf/config.hpp" #include "caf/config.hpp"
...@@ -52,21 +53,12 @@ void close(socket x); ...@@ -52,21 +53,12 @@ void close(socket x);
/// Returns the last socket error in this thread as an integer. /// Returns the last socket error in this thread as an integer.
/// @relates socket /// @relates socket
int last_socket_error(); std::errc last_socket_error();
/// Returns the last socket error as human-readable string. /// Returns the last socket error as human-readable string.
/// @relates socket /// @relates socket
std::string last_socket_error_as_string(); std::string last_socket_error_as_string();
/// Returns a human-readable string for a given socket error.
/// @relates socket
std::string socket_error_as_string(int errcode);
/// Returns whether `errcode` indicates that an operation would block or return
/// nothing at the moment and can be tried again at a later point.
/// @relates socket
bool would_block_or_temporarily_unavailable(int errcode);
/// Sets x to be inherited by child processes if `new_value == true` /// Sets x to be inherited by child processes if `new_value == true`
/// or not if `new_value == false`. Not implemented on Windows. /// or not if `new_value == false`. Not implemented on Windows.
/// @relates socket /// @relates socket
...@@ -76,9 +68,5 @@ error child_process_inherit(socket x, bool new_value); ...@@ -76,9 +68,5 @@ error child_process_inherit(socket x, bool new_value);
/// @relates socket /// @relates socket
error nonblocking(socket x, bool new_value); error nonblocking(socket x, bool new_value);
/// Convenience functions for checking the result of `recv` or `send`.
/// @relates socket
bool is_error(std::make_signed<size_t>::type res, bool is_nonblock);
} // namespace net } // namespace net
} // namespace caf } // namespace caf
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/net_syscall.hpp" #include "caf/detail/net_syscall.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/detail/socket_sys_aliases.hpp" #include "caf/detail/socket_sys_aliases.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/expected.hpp" #include "caf/expected.hpp"
#include "caf/io/network/protocol.hpp" #include "caf/io/network/protocol.hpp"
......
...@@ -85,14 +85,14 @@ variant<size_t, std::errc> write(pipe_socket x, const void* buf, ...@@ -85,14 +85,14 @@ variant<size_t, std::errc> write(pipe_socket x, const void* buf,
size_t buf_size) { size_t buf_size) {
auto res = ::write(x.id, buf, buf_size); auto res = ::write(x.id, buf, buf_size);
if (res < 0) if (res < 0)
return static_cast<std::errc>(last_socket_error()); return last_socket_error();
return static_cast<size_t>(res); return static_cast<size_t>(res);
} }
variant<size_t, std::errc> read(pipe_socket x, void* buf, size_t buf_size) { variant<size_t, std::errc> read(pipe_socket x, void* buf, size_t buf_size) {
auto res = ::read(x.id, buf, buf_size); auto res = ::read(x.id, buf, buf_size);
if (res < 0) if (res < 0)
return static_cast<std::errc>(last_socket_error()); return last_socket_error();
return static_cast<size_t>(res); return static_cast<size_t>(res);
} }
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "caf/net/socket.hpp" #include "caf/net/socket.hpp"
#include <system_error>
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/detail/net_syscall.hpp" #include "caf/detail/net_syscall.hpp"
#include "caf/detail/socket_sys_includes.hpp" #include "caf/detail/socket_sys_includes.hpp"
...@@ -32,15 +34,80 @@ void close(socket fd) { ...@@ -32,15 +34,80 @@ void close(socket fd) {
closesocket(fd.id); closesocket(fd.id);
} }
int last_socket_error() { # define ERRC_CASE(wsa_code, stl_code) \
return WSAGetLastError(); case wsa_code: \
return errc::stl_code
std::errc last_socket_error() {
// Unfortunately, MS does not define errc consistent with the WSA error
// codes. Hence, we cannot simply use static_cast<> but have to perform a
// switch-case.
using std::errc;
int wsa_code = WSAGetLastError();
switch (wsa_code) {
ERRC_CASE(WSA_INVALID_HANDLE, invalid_argument);
ERRC_CASE(WSA_NOT_ENOUGH_MEMORY, not_enough_memory);
ERRC_CASE(WSA_INVALID_PARAMETER, invalid_argument);
ERRC_CASE(WSAEINTR, interrupted);
ERRC_CASE(WSAEBADF, bad_file_descriptor);
ERRC_CASE(WSAEACCES, permission_denied);
ERRC_CASE(WSAEFAULT, bad_address);
ERRC_CASE(WSAEINVAL, invalid_argument);
ERRC_CASE(WSAEMFILE, too_many_files_open);
ERRC_CASE(WSAEWOULDBLOCK, operation_would_block);
ERRC_CASE(WSAEINPROGRESS, operation_in_progress);
ERRC_CASE(WSAEALREADY, connection_already_in_progress);
ERRC_CASE(WSAENOTSOCK, not_a_socket);
ERRC_CASE(WSAEDESTADDRREQ, destination_address_required);
ERRC_CASE(WSAEMSGSIZE, message_size);
ERRC_CASE(WSAEPROTOTYPE, wrong_protocol_type);
ERRC_CASE(WSAENOPROTOOPT, no_protocol_option);
ERRC_CASE(WSAEPROTONOSUPPORT, protocol_not_supported);
// Windows returns this error code if the *type* argument to socket() is
// invalid. POSIX returns EINVAL.
ERRC_CASE(WSAESOCKTNOSUPPORT, invalid_argument);
ERRC_CASE(WSAEOPNOTSUPP, operation_not_supported);
// Windows returns this error code if the *protocol* argument to socket() is
// invalid. POSIX returns EINVAL.
ERRC_CASE(WSAEPFNOSUPPORT, invalid_argument);
ERRC_CASE(WSAEAFNOSUPPORT, address_family_not_supported);
ERRC_CASE(WSAEADDRINUSE, address_in_use);
ERRC_CASE(WSAEADDRNOTAVAIL, address_not_available);
ERRC_CASE(WSAENETDOWN, network_down);
ERRC_CASE(WSAENETUNREACH, network_unreachable);
ERRC_CASE(WSAENETRESET, network_reset);
ERRC_CASE(WSAECONNABORTED, connection_aborted);
ERRC_CASE(WSAECONNRESET, connection_reset);
ERRC_CASE(WSAENOBUFS, no_buffer_space);
ERRC_CASE(WSAEISCONN, already_connected);
ERRC_CASE(WSAENOTCONN, not_connected);
// Windows returns this error code when writing to a socket with closed
// output channel. POSIX returns EPIPE.
ERRC_CASE(WSAESHUTDOWN, broken_pipe);
ERRC_CASE(WSAETIMEDOUT, timed_out);
ERRC_CASE(WSAECONNREFUSED, connection_refused);
ERRC_CASE(WSAELOOP, too_many_symbolic_link_levels);
ERRC_CASE(WSAENAMETOOLONG, filename_too_long);
ERRC_CASE(WSAEHOSTUNREACH, host_unreachable);
ERRC_CASE(WSAENOTEMPTY, directory_not_empty);
ERRC_CASE(WSANOTINITIALISED, network_down);
ERRC_CASE(WSAEDISCON, already_connected);
ERRC_CASE(WSAENOMORE, not_connected);
ERRC_CASE(WSAECANCELLED, operation_canceled);
ERRC_CASE(WSATRY_AGAIN, resource_unavailable_try_again);
ERRC_CASE(WSANO_RECOVERY, state_not_recoverable);
}
fprintf(stderr, "[FATAL] %s:%u: unrecognized WSA error code (%d)\n", __FILE__,
__LINE__, wsa_code);
abort();
} }
std::string socket_error_as_string(int errcode) { std::string last_socket_error_as_string() {
int wsa_code = WSAGetLastError();
LPTSTR errorText = NULL; LPTSTR errorText = NULL;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS, | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), nullptr, wsa_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &errorText, 0, nullptr); (LPTSTR) &errorText, 0, nullptr);
std::string result; std::string result;
if (errorText != nullptr) { if (errorText != nullptr) {
...@@ -51,10 +118,6 @@ std::string socket_error_as_string(int errcode) { ...@@ -51,10 +118,6 @@ std::string socket_error_as_string(int errcode) {
return result; return result;
} }
std::string last_socket_error_as_string() {
return socket_error_as_string(last_socket_error());
}
bool would_block_or_temporarily_unavailable(int errcode) { bool would_block_or_temporarily_unavailable(int errcode) {
return errcode == WSAEWOULDBLOCK || errcode == WSATRY_AGAIN; return errcode == WSAEWOULDBLOCK || errcode == WSATRY_AGAIN;
} }
...@@ -79,12 +142,10 @@ void close(socket fd) { ...@@ -79,12 +142,10 @@ void close(socket fd) {
::close(fd.id); ::close(fd.id);
} }
int last_socket_error() { std::errc last_socket_error() {
return errno; // TODO: Linux and macOS both have some non-POSIX error codes that should get
} // mapped accordingly.
return static_cast<std::errc>(errno);
std::string socket_error_as_string(int error_code) {
return strerror(error_code);
} }
std::string last_socket_error_as_string() { std::string last_socket_error_as_string() {
...@@ -117,13 +178,5 @@ error nonblocking(socket x, bool new_value) { ...@@ -117,13 +178,5 @@ error nonblocking(socket x, bool new_value) {
#endif // CAF_WINDOWS #endif // CAF_WINDOWS
bool is_error(std::make_signed<size_t>::type res, bool is_nonblock) {
if (res < 0) {
auto err = last_socket_error();
return !is_nonblock || !would_block_or_temporarily_unavailable(err);
}
return false;
}
} // namespace net } // namespace net
} // namespace caf } // namespace caf
...@@ -165,7 +165,7 @@ variant<size_t, std::errc> read(stream_socket x, void* buf, size_t buf_size) { ...@@ -165,7 +165,7 @@ variant<size_t, std::errc> read(stream_socket x, void* buf, size_t buf_size) {
auto res = ::recv(x.id, reinterpret_cast<socket_recv_ptr>(buf), buf_size, auto res = ::recv(x.id, reinterpret_cast<socket_recv_ptr>(buf), buf_size,
no_sigpipe_io_flag); no_sigpipe_io_flag);
if (res < 0) if (res < 0)
return static_cast<std::errc>(last_socket_error()); return last_socket_error();
return static_cast<size_t>(res); return static_cast<size_t>(res);
} }
...@@ -174,7 +174,7 @@ variant<size_t, std::errc> write(stream_socket x, const void* buf, ...@@ -174,7 +174,7 @@ variant<size_t, std::errc> write(stream_socket x, const void* buf,
auto res = ::send(x.id, reinterpret_cast<socket_send_ptr>(buf), buf_size, auto res = ::send(x.id, reinterpret_cast<socket_send_ptr>(buf), buf_size,
no_sigpipe_io_flag); no_sigpipe_io_flag);
if (res < 0) if (res < 0)
return static_cast<std::errc>(last_socket_error()); return last_socket_error();
return static_cast<size_t>(res); return static_cast<size_t>(res);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment