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)
add_library(asio INTERFACE)
target_include_directories(asio INTERFACE ${asio_SOURCE_DIR}/asio/include)
add_library(asio STATIC ${CMAKE_CURRENT_LIST_DIR}/asio_handle_exception.cpp)
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)
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 SNetGetTurnsInTransit(uint32_t *turns) override;
virtual void poll() = 0;
virtual tl::expected<void, PacketError> poll() = 0;
virtual void send(packet &pkt) = 0;
virtual void DisconnectNet(plr_t plr);

5
Source/dvlnet/base_protocol.h

@ -17,7 +17,7 @@ class base_protocol : public base {
public:
int create(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 DisconnectNet(plr_t plr) override;
@ -190,9 +190,10 @@ bool base_protocol<P>::IsGameHost()
}
template <class P>
void base_protocol<P>::poll()
tl::expected<void, PacketError> base_protocol<P>::poll()
{
recv();
return {};
}
template <class P>

10
Source/dvlnet/packet.h

@ -76,6 +76,11 @@ public:
{
}
PacketError(std::string_view message)
: message_(message)
{
}
PacketError(const PacketError &error)
: message_(std::string(error.message_))
{
@ -95,6 +100,11 @@ private:
StringOrView message_;
};
inline PacketError IoHandlerError(std::string message)
{
return PacketError(std::move(message));
}
PacketError PacketTypeError(std::uint8_t unknownPacketType);
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 "utils/language.h"
#include "utils/str_cat.hpp"
namespace devilution::net {
@ -55,15 +56,14 @@ int tcp_client::join(std::string addrstr)
PLR_BROADCAST, PLR_MASTER, cookie_self, game_init_info);
if (!pkt.has_value()) {
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;
}
send(**pkt);
for (auto i = 0; i < NoSleep; ++i) {
try {
poll();
} catch (const std::runtime_error &e) {
SDL_SetError("%s", e.what());
if (tl::expected<void, PacketError> result = poll(); !result.has_value()) {
const std::string_view message = result.error().what();
SDL_SetError("%.*s", static_cast<int>(message.size()), message.data());
return -1;
}
if (plr_self != PLR_BROADCAST)
@ -72,7 +72,8 @@ int tcp_client::join(std::string addrstr)
}
}
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;
}
@ -84,21 +85,34 @@ bool tcp_client::IsGameHost()
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)
{
if (error) {
// error in recv from server
// returning and doing nothing should be the same
// as if all connections to other clients were lost
PacketError packetError = IoHandlerError(error.message());
RaiseIoHandlerError(packetError);
return;
}
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_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()) {
tl::expected<std::unique_ptr<packet>, PacketError> pkt = pktfty->make_packet(recv_queue.ReadPacket());
if (!pkt.has_value()) {
LogError("make_packet: {}", pkt.error().what());
RaiseIoHandlerError(pkt.error());
return;
}
if (tl::expected<void, PacketError> result = RecvLocal(**pkt); !result.has_value()) {
LogError("RecvLocal: {}", result.error().what());
RaiseIoHandlerError(result.error());
return;
}
}
@ -126,7 +140,8 @@ void tcp_client::StartReceive()
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)
@ -153,6 +168,11 @@ std::string tcp_client::make_default_gamename()
return std::string(sgOptions.Network.szBindAddress);
}
void tcp_client::RaiseIoHandlerError(const PacketError &error)
{
ioHandlerResult.emplace(error);
}
tcp_client::~tcp_client()
= default;

7
Source/dvlnet/tcp_client.h

@ -16,6 +16,7 @@
#include <asio/ts/internet.hpp>
#include <asio/ts/io_context.hpp>
#include <asio/ts/net.hpp>
#include <asio_handle_exception.hpp>
#include "dvlnet/base.h"
#include "dvlnet/frame_queue.h"
@ -29,7 +30,7 @@ public:
int create(std::string addrstr) override;
int join(std::string addrstr) override;
void poll() override;
tl::expected<void, PacketError> poll() override;
void send(packet &pkt) override;
bool SNetLeaveGame(int type) override;
@ -50,9 +51,13 @@ private:
asio::ip::tcp::socket sock = asio::ip::tcp::socket(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 StartReceive();
void HandleSend(const asio::error_code &error, size_t bytesSent);
void RaiseIoHandlerError(const PacketError &error);
};
} // 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,
size_t bytesSent)
{
// empty for now
if (ec) {
Log("Network error: {}", ec.message());
DropConnection(con);
}
}
void tcp_server::StartAccept()
@ -202,8 +205,11 @@ void tcp_server::StartAccept()
void tcp_server::HandleAccept(const scc &con, const asio::error_code &ec)
{
if (ec)
if (ec) {
PacketError packetError = IoHandlerError(ec.message());
RaiseIoHandlerError(packetError);
return;
}
if (NextFree() == PLR_BROADCAST) {
DropConnection(con);
} else {
@ -261,6 +267,20 @@ void tcp_server::DropConnection(const scc &con)
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()
{
acceptor->close();

5
Source/dvlnet/tcp_server.h

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

8
uwp-project/devilutionx.vcxproj

@ -73,8 +73,8 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<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>
<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>
<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\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>
<ClCompile>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
@ -92,8 +92,8 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<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>
<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>
<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\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>
<ClCompile>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>

Loading…
Cancel
Save