Browse Source

Build ASIO without exceptions

pull/5866/head
staphen 3 years ago committed by Stephen C. Wills
parent
commit
13b5fb82fa
  1. 5
      3rdParty/asio/CMakeLists.txt
  2. 18
      3rdParty/asio/asio_handle_exception.cpp
  3. 17
      3rdParty/asio/asio_handle_exception.hpp
  4. 2
      Source/dvlnet/base.h
  5. 5
      Source/dvlnet/base_protocol.h
  6. 10
      Source/dvlnet/packet.h
  7. 50
      Source/dvlnet/tcp_client.cpp
  8. 7
      Source/dvlnet/tcp_client.h
  9. 24
      Source/dvlnet/tcp_server.cpp
  10. 5
      Source/dvlnet/tcp_server.h
  11. 8
      uwp-project/devilutionx.vcxproj

5
3rdParty/asio/CMakeLists.txt vendored

@ -7,8 +7,9 @@ FetchContent_Declare(asio
) )
FetchContent_MakeAvailableExcludeFromAll(asio) FetchContent_MakeAvailableExcludeFromAll(asio)
add_library(asio INTERFACE) add_library(asio STATIC ${CMAKE_CURRENT_LIST_DIR}/asio_handle_exception.cpp)
target_include_directories(asio INTERFACE ${asio_SOURCE_DIR}/asio/include) target_compile_definitions(asio PUBLIC ASIO_NO_EXCEPTIONS)
target_include_directories(asio PUBLIC ${asio_SOURCE_DIR}/asio/include ${CMAKE_CURRENT_LIST_DIR})
if(NINTENDO_3DS OR NINTENDO_SWITCH) if(NINTENDO_3DS OR NINTENDO_SWITCH)
include(asio_defs REQUIRED) include(asio_defs REQUIRED)

18
3rdParty/asio/asio_handle_exception.cpp vendored

@ -0,0 +1,18 @@
#include <string_view>
#define ErrAsio(message) devilution::ErrDlg("ASIO Error", message, __FILE__, __LINE__)
namespace devilution {
extern void ErrDlg(const char* title, std::string_view error, std::string_view logFilePath, int logLineNr);
} // namespace devilution
namespace asio::detail {
void fatal_exception(const char* message)
{
ErrAsio(message);
}
} // namespace asio::detail

17
3rdParty/asio/asio_handle_exception.hpp vendored

@ -0,0 +1,17 @@
#pragma once
#include <asio/detail/throw_exception.hpp>
namespace asio::detail {
void fatal_exception(const char *message);
template <typename Exception>
void throw_exception(
const Exception &e
ASIO_SOURCE_LOCATION_PARAM)
{
fatal_exception(e.what());
}
} // namespace asio::detail

2
Source/dvlnet/base.h

@ -29,7 +29,7 @@ public:
bool SNetGetOwnerTurnsWaiting(uint32_t *turns) override; bool SNetGetOwnerTurnsWaiting(uint32_t *turns) override;
bool SNetGetTurnsInTransit(uint32_t *turns) override; bool SNetGetTurnsInTransit(uint32_t *turns) override;
virtual void poll() = 0; virtual tl::expected<void, PacketError> poll() = 0;
virtual void send(packet &pkt) = 0; virtual void send(packet &pkt) = 0;
virtual void DisconnectNet(plr_t plr); virtual void DisconnectNet(plr_t plr);

5
Source/dvlnet/base_protocol.h

@ -17,7 +17,7 @@ class base_protocol : public base {
public: public:
int create(std::string addrstr) override; int create(std::string addrstr) override;
int join(std::string addrstr) override; int join(std::string addrstr) override;
void poll() override; tl::expected<void, PacketError> poll() override;
void send(packet &pkt) override; void send(packet &pkt) override;
void DisconnectNet(plr_t plr) override; void DisconnectNet(plr_t plr) override;
@ -190,9 +190,10 @@ bool base_protocol<P>::IsGameHost()
} }
template <class P> template <class P>
void base_protocol<P>::poll() tl::expected<void, PacketError> base_protocol<P>::poll()
{ {
recv(); recv();
return {};
} }
template <class P> template <class P>

10
Source/dvlnet/packet.h

@ -76,6 +76,11 @@ public:
{ {
} }
PacketError(std::string_view message)
: message_(message)
{
}
PacketError(const PacketError &error) PacketError(const PacketError &error)
: message_(std::string(error.message_)) : message_(std::string(error.message_))
{ {
@ -95,6 +100,11 @@ private:
StringOrView message_; StringOrView message_;
}; };
inline PacketError IoHandlerError(std::string message)
{
return PacketError(std::move(message));
}
PacketError PacketTypeError(std::uint8_t unknownPacketType); PacketError PacketTypeError(std::uint8_t unknownPacketType);
PacketError PacketTypeError(std::initializer_list<packet_type> expectedTypes, std::uint8_t actual); PacketError PacketTypeError(std::initializer_list<packet_type> expectedTypes, std::uint8_t actual);

50
Source/dvlnet/tcp_client.cpp

@ -12,6 +12,7 @@
#include "options.h" #include "options.h"
#include "utils/language.h" #include "utils/language.h"
#include "utils/str_cat.hpp"
namespace devilution::net { namespace devilution::net {
@ -55,15 +56,14 @@ int tcp_client::join(std::string addrstr)
PLR_BROADCAST, PLR_MASTER, cookie_self, game_init_info); PLR_BROADCAST, PLR_MASTER, cookie_self, game_init_info);
if (!pkt.has_value()) { if (!pkt.has_value()) {
const std::string_view message = pkt.error().what(); const std::string_view message = pkt.error().what();
SDL_SetError("make_packet: %.*s\n", static_cast<int>(message.size()), message.data()); SDL_SetError("make_packet: %.*s", static_cast<int>(message.size()), message.data());
return -1; return -1;
} }
send(**pkt); send(**pkt);
for (auto i = 0; i < NoSleep; ++i) { for (auto i = 0; i < NoSleep; ++i) {
try { if (tl::expected<void, PacketError> result = poll(); !result.has_value()) {
poll(); const std::string_view message = result.error().what();
} catch (const std::runtime_error &e) { SDL_SetError("%.*s", static_cast<int>(message.size()), message.data());
SDL_SetError("%s", e.what());
return -1; return -1;
} }
if (plr_self != PLR_BROADCAST) if (plr_self != PLR_BROADCAST)
@ -72,7 +72,8 @@ int tcp_client::join(std::string addrstr)
} }
} }
if (plr_self == PLR_BROADCAST) { if (plr_self == PLR_BROADCAST) {
SDL_SetError("%s", _("Unable to connect").data()); const std::string_view message = _("Unable to connect");
SDL_SetError("%.*s", static_cast<int>(message.size()), message.data());
return -1; return -1;
} }
@ -84,21 +85,34 @@ bool tcp_client::IsGameHost()
return local_server != nullptr; return local_server != nullptr;
} }
void tcp_client::poll() tl::expected<void, PacketError> tcp_client::poll()
{ {
ioc.poll(); while (ioc.poll_one() > 0) {
if (IsGameHost()) {
tl::expected<void, PacketError> serverResult = local_server->CheckIoHandlerError();
if (!serverResult.has_value())
return serverResult;
}
if (ioHandlerResult == std::nullopt)
continue;
tl::expected<void, PacketError> packetError = tl::make_unexpected(*ioHandlerResult);
ioHandlerResult = std::nullopt;
return packetError;
}
return {};
} }
void tcp_client::HandleReceive(const asio::error_code &error, size_t bytesRead) void tcp_client::HandleReceive(const asio::error_code &error, size_t bytesRead)
{ {
if (error) { if (error) {
// error in recv from server PacketError packetError = IoHandlerError(error.message());
// returning and doing nothing should be the same RaiseIoHandlerError(packetError);
// as if all connections to other clients were lost
return; return;
} }
if (bytesRead == 0) { if (bytesRead == 0) {
throw std::runtime_error(_("error: read 0 bytes from server").data()); PacketError packetError(_("error: read 0 bytes from server"));
RaiseIoHandlerError(packetError);
return;
} }
recv_buffer.resize(bytesRead); recv_buffer.resize(bytesRead);
recv_queue.Write(std::move(recv_buffer)); recv_queue.Write(std::move(recv_buffer));
@ -106,11 +120,11 @@ void tcp_client::HandleReceive(const asio::error_code &error, size_t bytesRead)
while (recv_queue.PacketReady()) { while (recv_queue.PacketReady()) {
tl::expected<std::unique_ptr<packet>, PacketError> pkt = pktfty->make_packet(recv_queue.ReadPacket()); tl::expected<std::unique_ptr<packet>, PacketError> pkt = pktfty->make_packet(recv_queue.ReadPacket());
if (!pkt.has_value()) { if (!pkt.has_value()) {
LogError("make_packet: {}", pkt.error().what()); RaiseIoHandlerError(pkt.error());
return; return;
} }
if (tl::expected<void, PacketError> result = RecvLocal(**pkt); !result.has_value()) { if (tl::expected<void, PacketError> result = RecvLocal(**pkt); !result.has_value()) {
LogError("RecvLocal: {}", result.error().what()); RaiseIoHandlerError(result.error());
return; return;
} }
} }
@ -126,7 +140,8 @@ void tcp_client::StartReceive()
void tcp_client::HandleSend(const asio::error_code &error, size_t bytesSent) void tcp_client::HandleSend(const asio::error_code &error, size_t bytesSent)
{ {
// empty for now if (error)
RaiseIoHandlerError(error.message());
} }
void tcp_client::send(packet &pkt) void tcp_client::send(packet &pkt)
@ -153,6 +168,11 @@ std::string tcp_client::make_default_gamename()
return std::string(sgOptions.Network.szBindAddress); return std::string(sgOptions.Network.szBindAddress);
} }
void tcp_client::RaiseIoHandlerError(const PacketError &error)
{
ioHandlerResult.emplace(error);
}
tcp_client::~tcp_client() tcp_client::~tcp_client()
= default; = default;

7
Source/dvlnet/tcp_client.h

@ -16,6 +16,7 @@
#include <asio/ts/internet.hpp> #include <asio/ts/internet.hpp>
#include <asio/ts/io_context.hpp> #include <asio/ts/io_context.hpp>
#include <asio/ts/net.hpp> #include <asio/ts/net.hpp>
#include <asio_handle_exception.hpp>
#include "dvlnet/base.h" #include "dvlnet/base.h"
#include "dvlnet/frame_queue.h" #include "dvlnet/frame_queue.h"
@ -29,7 +30,7 @@ public:
int create(std::string addrstr) override; int create(std::string addrstr) override;
int join(std::string addrstr) override; int join(std::string addrstr) override;
void poll() override; tl::expected<void, PacketError> poll() override;
void send(packet &pkt) override; void send(packet &pkt) override;
bool SNetLeaveGame(int type) override; bool SNetLeaveGame(int type) override;
@ -50,9 +51,13 @@ private:
asio::ip::tcp::socket sock = asio::ip::tcp::socket(ioc); asio::ip::tcp::socket sock = asio::ip::tcp::socket(ioc);
std::unique_ptr<tcp_server> local_server; // must be declared *after* ioc std::unique_ptr<tcp_server> local_server; // must be declared *after* ioc
std::optional<PacketError> ioHandlerResult;
void HandleReceive(const asio::error_code &error, size_t bytesRead); void HandleReceive(const asio::error_code &error, size_t bytesRead);
void StartReceive(); void StartReceive();
void HandleSend(const asio::error_code &error, size_t bytesSent); void HandleSend(const asio::error_code &error, size_t bytesSent);
void RaiseIoHandlerError(const PacketError &error);
}; };
} // namespace devilution::net } // namespace devilution::net

24
Source/dvlnet/tcp_server.cpp

@ -189,7 +189,10 @@ void tcp_server::StartSend(const scc &con, packet &pkt)
void tcp_server::HandleSend(const scc &con, const asio::error_code &ec, void tcp_server::HandleSend(const scc &con, const asio::error_code &ec,
size_t bytesSent) size_t bytesSent)
{ {
// empty for now if (ec) {
Log("Network error: {}", ec.message());
DropConnection(con);
}
} }
void tcp_server::StartAccept() void tcp_server::StartAccept()
@ -202,8 +205,11 @@ void tcp_server::StartAccept()
void tcp_server::HandleAccept(const scc &con, const asio::error_code &ec) void tcp_server::HandleAccept(const scc &con, const asio::error_code &ec)
{ {
if (ec) if (ec) {
PacketError packetError = IoHandlerError(ec.message());
RaiseIoHandlerError(packetError);
return; return;
}
if (NextFree() == PLR_BROADCAST) { if (NextFree() == PLR_BROADCAST) {
DropConnection(con); DropConnection(con);
} else { } else {
@ -261,6 +267,20 @@ void tcp_server::DropConnection(const scc &con)
con->socket.close(); con->socket.close();
} }
void tcp_server::RaiseIoHandlerError(const PacketError &error)
{
ioHandlerResult.emplace(error);
}
tl::expected<void, PacketError> tcp_server::CheckIoHandlerError()
{
if (ioHandlerResult == std::nullopt)
return {};
tl::expected<void, PacketError> packetError = tl::make_unexpected(*ioHandlerResult);
ioHandlerResult = std::nullopt;
return packetError;
}
void tcp_server::Close() void tcp_server::Close()
{ {
acceptor->close(); acceptor->close();

5
Source/dvlnet/tcp_server.h

@ -19,6 +19,7 @@
#include <asio/ts/internet.hpp> #include <asio/ts/internet.hpp>
#include <asio/ts/io_context.hpp> #include <asio/ts/io_context.hpp>
#include <asio/ts/net.hpp> #include <asio/ts/net.hpp>
#include <asio_handle_exception.hpp>
#include "dvlnet/abstract_net.h" #include "dvlnet/abstract_net.h"
#include "dvlnet/frame_queue.h" #include "dvlnet/frame_queue.h"
@ -37,6 +38,7 @@ public:
tcp_server(asio::io_context &ioc, const std::string &bindaddr, tcp_server(asio::io_context &ioc, const std::string &bindaddr,
unsigned short port, packet_factory &pktfty); unsigned short port, packet_factory &pktfty);
std::string LocalhostSelf(); std::string LocalhostSelf();
tl::expected<void, PacketError> CheckIoHandlerError();
void Close(); void Close();
virtual ~tcp_server(); virtual ~tcp_server();
@ -66,6 +68,8 @@ private:
std::array<scc, MAX_PLRS> connections; std::array<scc, MAX_PLRS> connections;
buffer_t game_init_info; buffer_t game_init_info;
std::optional<PacketError> ioHandlerResult;
scc MakeConnection(); scc MakeConnection();
plr_t NextFree(); plr_t NextFree();
bool Empty(); bool Empty();
@ -81,6 +85,7 @@ private:
void StartTimeout(const scc &con); void StartTimeout(const scc &con);
void HandleTimeout(const scc &con, const asio::error_code &ec); void HandleTimeout(const scc &con, const asio::error_code &ec);
void DropConnection(const scc &con); void DropConnection(const scc &con);
void RaiseIoHandlerError(const PacketError &error);
}; };
} // namespace devilution::net } // namespace devilution::net

8
uwp-project/devilutionx.vcxproj

@ -73,8 +73,8 @@
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link> <Link>
<AdditionalDependencies>sdl_image.lib;libpng16_staticd.lib;pkware.lib;fmtd.lib;zlibstatic.lib;bzip2.lib;libsmackerdec.lib;libmpq.lib;libdevilutionx.lib;sdl2.lib;sdl_audiolib.lib;sodium.lib;zt.lib;lwip_pic.lib;miniupnpc_pic.lib;natpmp_pic.lib;zt_pic.lib;zto_pic.lib;shlwapi.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>sdl_image.lib;libpng16_staticd.lib;pkware.lib;fmtd.lib;zlibstatic.lib;bzip2.lib;libsmackerdec.lib;libmpq.lib;libdevilutionx.lib;sdl2.lib;sdl_audiolib.lib;asio.lib;sodium.lib;zt.lib;lwip_pic.lib;miniupnpc_pic.lib;natpmp_pic.lib;zt_pic.lib;zto_pic.lib;shlwapi.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\build\SDL\VisualC-WinRT\x64\Debug\SDL-UWP;..\build\3rdParty\SDL_image\Debug;..\build\_deps\zlib-build\Debug;..\build\3rdParty\PKWare\Debug;..\build\3rdParty\bzip2\Debug;..\build\3rdParty\libsmackerdec\Debug;..\build\3rdParty\libmpq\Debug;..\build\_deps\sdl_audiolib-build\Debug;..\build\_deps\libsodium-build\Debug;..\build\_deps\libzt-build\lib\Debug;..\build\_deps\libfmt-build\Debug;..\build\_deps\libpng-build\Debug;..\build\Source\libdevilutionx.dir\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\build\SDL\VisualC-WinRT\x64\Debug\SDL-UWP;..\build\3rdParty\SDL_image\Debug;..\build\_deps\zlib-build\Debug;..\build\3rdParty\PKWare\Debug;..\build\3rdParty\bzip2\Debug;..\build\3rdParty\libsmackerdec\Debug;..\build\3rdParty\libmpq\Debug;..\build\_deps\sdl_audiolib-build\Debug;..\build\3rdParty\asio\Release;..\build\_deps\libsodium-build\Debug;..\build\_deps\libzt-build\lib\Debug;..\build\_deps\libfmt-build\Debug;..\build\_deps\libpng-build\Debug;..\build\Source\libdevilutionx.dir\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
<ClCompile> <ClCompile>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
@ -92,8 +92,8 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link> <Link>
<AdditionalDependencies>sdl_image.lib;libpng16_static.lib;pkware.lib;fmt.lib;zlibstatic.lib;bzip2.lib;libsmackerdec.lib;libmpq.lib;libdevilutionx.lib;sdl2.lib;sdl_audiolib.lib;sodium.lib;zt.lib;lwip_pic.lib;miniupnpc_pic.lib;natpmp_pic.lib;zt_pic.lib;zto_pic.lib;shlwapi.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>sdl_image.lib;libpng16_static.lib;pkware.lib;fmt.lib;zlibstatic.lib;bzip2.lib;libsmackerdec.lib;libmpq.lib;libdevilutionx.lib;sdl2.lib;sdl_audiolib.lib;asio.lib;sodium.lib;zt.lib;lwip_pic.lib;miniupnpc_pic.lib;natpmp_pic.lib;zt_pic.lib;zto_pic.lib;shlwapi.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\build\SDL\VisualC-WinRT\x64\Release\SDL-UWP;..\build\3rdParty\SDL_image\Release;..\build\_deps\zlib-build\Release;..\build\3rdParty\PKWare\Release;..\build\3rdParty\bzip2\Release;..\build\3rdParty\libsmackerdec\Release;..\build\3rdParty\libmpq\Release;..\build\_deps\sdl_audiolib-build\Release;..\build\_deps\libsodium-build\Release;..\build\_deps\libzt-build\lib\Release;..\build\_deps\libfmt-build\Release;..\build\_deps\libpng-build\Release;..\build\Source\libdevilutionx.dir\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\build\SDL\VisualC-WinRT\x64\Release\SDL-UWP;..\build\3rdParty\SDL_image\Release;..\build\_deps\zlib-build\Release;..\build\3rdParty\PKWare\Release;..\build\3rdParty\bzip2\Release;..\build\3rdParty\libsmackerdec\Release;..\build\3rdParty\libmpq\Release;..\build\_deps\sdl_audiolib-build\Release;..\build\3rdParty\asio\Release;..\build\_deps\libsodium-build\Release;..\build\_deps\libzt-build\lib\Release;..\build\_deps\libfmt-build\Release;..\build\_deps\libpng-build\Release;..\build\Source\libdevilutionx.dir\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link> </Link>
<ClCompile> <ClCompile>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>

Loading…
Cancel
Save