From 32cbb1bc7767b77dc05764afedb4867b8e58e15a Mon Sep 17 00:00:00 2001
From: Tobias <thm.frey@gmail.com>
Date: Fri, 17 Apr 2020 02:50:28 +0200
Subject: [PATCH] input_common/udp: Port various changes from yuzu (#5133)

---
 src/common/thread.h               |   2 +-
 src/input_common/udp/client.cpp   |  49 +++++++++------
 src/input_common/udp/client.h     |  12 ++--
 src/input_common/udp/protocol.cpp |  17 +++--
 src/input_common/udp/protocol.h   | 101 ++++++++++++++++--------------
 src/input_common/udp/udp.cpp      |   3 +-
 6 files changed, 102 insertions(+), 82 deletions(-)

diff --git a/src/common/thread.h b/src/common/thread.h
index 70dcf4601..618236b59 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -30,7 +30,7 @@ public:
 
     template <class Duration>
     bool WaitFor(const std::chrono::duration<Duration>& time) {
-        std::unique_lock lk(mutex);
+        std::unique_lock lk{mutex};
         if (!condvar.wait_for(lk, time, [this] { return is_set; }))
             return false;
         is_set = false;
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index c9ffe899c..287a064c6 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -32,8 +32,16 @@ public:
                     SocketCallback callback)
         : callback(std::move(callback)), timer(io_service),
           socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id),
-          pad_index(pad_index),
-          send_endpoint(udp::endpoint(boost::asio::ip::make_address_v4(host), port)) {}
+          pad_index(pad_index) {
+        boost::system::error_code ec{};
+        auto ipv4 = boost::asio::ip::make_address_v4(host, ec);
+        if (ec.value() != boost::system::errc::success) {
+            LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided to socket", host);
+            ipv4 = boost::asio::ip::address_v4{};
+        }
+
+        send_endpoint = {udp::endpoint(ipv4, port)};
+    }
 
     void Stop() {
         io_service.stop();
@@ -85,17 +93,18 @@ private:
     }
 
     void HandleSend(const boost::system::error_code& error) {
+        boost::system::error_code _ignored{};
         // Send a request for getting port info for the pad
         Request::PortInfo port_info{1, {pad_index, 0, 0, 0}};
-        auto port_message = Request::Create(port_info, client_id);
+        const auto port_message = Request::Create(port_info, client_id);
         std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE);
-        std::size_t len = socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint);
+        socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored);
 
         // Send a request for getting pad data for the pad
         Request::PadData pad_data{Request::PadData::Flags::Id, pad_index, EMPTY_MAC_ADDRESS};
-        auto pad_message = Request::Create(pad_data, client_id);
+        const auto pad_message = Request::Create(pad_data, client_id);
         std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE);
-        std::size_t len2 = socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint);
+        socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored);
         StartSend(timer.expiry());
     }
 
@@ -104,8 +113,8 @@ private:
     boost::asio::basic_waitable_timer<clock> timer;
     udp::socket socket;
 
-    u32 client_id;
-    u8 pad_index;
+    u32 client_id{};
+    u8 pad_index{};
 
     static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>);
     static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message<Request::PadData>);
@@ -170,16 +179,16 @@ void Client::OnPadData(Response::PadData data) {
 
         // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
         // between a simple "tap" and a hard press that causes the touch screen to click.
-        bool is_active = data.touch_1.is_active != 0;
+        const bool is_active = data.touch_1.is_active != 0;
 
         float x = 0;
         float y = 0;
 
         if (is_active && status->touch_calibration) {
-            u16 min_x = status->touch_calibration->min_x;
-            u16 max_x = status->touch_calibration->max_x;
-            u16 min_y = status->touch_calibration->min_y;
-            u16 max_y = status->touch_calibration->max_y;
+            const u16 min_x = status->touch_calibration->min_x;
+            const u16 max_x = status->touch_calibration->max_x;
+            const u16 min_y = status->touch_calibration->min_y;
+            const u16 max_y = status->touch_calibration->max_y;
 
             x = (std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - min_x) /
                 static_cast<float>(max_x - min_x);
@@ -212,10 +221,11 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
         bool result = success_event.WaitFor(std::chrono::seconds(8));
         socket.Stop();
         worker_thread.join();
-        if (result)
+        if (result) {
             success_callback();
-        else
+        } else {
             failure_callback();
+        }
     })
         .detach();
 }
@@ -228,8 +238,10 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
     std::thread([=] {
         constexpr u16 CALIBRATION_THRESHOLD = 100;
 
-        u16 min_x{UINT16_MAX}, min_y{UINT16_MAX};
-        u16 max_x, max_y;
+        u16 min_x{UINT16_MAX};
+        u16 min_y{UINT16_MAX};
+        u16 max_x{};
+        u16 max_y{};
 
         Status current_status{Status::Initialized};
         SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {},
@@ -239,8 +251,9 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
                                         current_status = Status::Ready;
                                         status_callback(current_status);
                                     }
-                                    if (!data.touch_1.is_active)
+                                    if (!data.touch_1.is_active) {
                                         return;
+                                    }
                                     LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x,
                                               data.touch_1.y);
                                     min_x = std::min(min_x, static_cast<u16>(data.touch_1.x));
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 82bdb68d9..b8c654755 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -17,8 +17,8 @@
 
 namespace InputCommon::CemuhookUDP {
 
-static constexpr u16 DEFAULT_PORT = 26760;
-static constexpr const char* DEFAULT_ADDR = "127.0.0.1";
+constexpr u16 DEFAULT_PORT = 26760;
+constexpr char DEFAULT_ADDR[] = "127.0.0.1";
 
 class Socket;
 
@@ -35,10 +35,10 @@ struct DeviceStatus {
 
     // calibration data for scaling the device's touch area to 3ds
     struct CalibrationData {
-        u16 min_x;
-        u16 min_y;
-        u16 max_x;
-        u16 max_y;
+        u16 min_x{};
+        u16 min_y{};
+        u16 max_x{};
+        u16 max_y{};
     };
     std::optional<CalibrationData> touch_calibration;
 };
diff --git a/src/input_common/udp/protocol.cpp b/src/input_common/udp/protocol.cpp
index d65069207..5e50bd612 100644
--- a/src/input_common/udp/protocol.cpp
+++ b/src/input_common/udp/protocol.cpp
@@ -9,7 +9,7 @@
 
 namespace InputCommon::CemuhookUDP {
 
-static const std::size_t GetSizeOfResponseType(Type t) {
+static constexpr std::size_t GetSizeOfResponseType(Type t) {
     switch (t) {
     case Type::Version:
         return sizeof(Response::Version);
@@ -31,22 +31,21 @@ namespace Response {
  */
 std::optional<Type> Validate(u8* data, std::size_t size) {
     if (size < sizeof(Header)) {
-        LOG_DEBUG(Input, "Invalid UDP packet received");
-        return {};
+        return std::nullopt;
     }
-    Header header;
+    Header header{};
     std::memcpy(&header, data, sizeof(Header));
     if (header.magic != SERVER_MAGIC) {
         LOG_ERROR(Input, "UDP Packet has an unexpected magic value");
-        return {};
+        return std::nullopt;
     }
     if (header.protocol_version != PROTOCOL_VERSION) {
         LOG_ERROR(Input, "UDP Packet protocol mismatch");
-        return {};
+        return std::nullopt;
     }
     if (header.type < Type::Version || header.type > Type::PadData) {
         LOG_ERROR(Input, "UDP Packet is an unknown type");
-        return {};
+        return std::nullopt;
     }
 
     // Packet size must equal sizeof(Header) + sizeof(Data)
@@ -59,7 +58,7 @@ std::optional<Type> Validate(u8* data, std::size_t size) {
             Input,
             "UDP Packet payload length doesn't match. Received: {} PayloadLength: {} Expected: {}",
             size, header.payload_length, data_len + sizeof(Type));
-        return {};
+        return std::nullopt;
     }
 
     const u32 crc32 = header.crc;
@@ -70,7 +69,7 @@ std::optional<Type> Validate(u8* data, std::size_t size) {
     result.process_bytes(data, data_len + sizeof(Header));
     if (crc32 != result.checksum()) {
         LOG_ERROR(Input, "UDP Packet CRC check failed. Offset: {}", offsetof(Header, crc));
-        return {};
+        return std::nullopt;
     }
     return header.type;
 }
diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h
index 5b1852d55..3ba4d1fc8 100644
--- a/src/input_common/udp/protocol.h
+++ b/src/input_common/udp/protocol.h
@@ -25,15 +25,15 @@ enum class Type : u32 {
 };
 
 struct Header {
-    u32_le magic;
-    u16_le protocol_version;
-    u16_le payload_length;
-    u32_le crc;
-    u32_le id;
+    u32_le magic{};
+    u16_le protocol_version{};
+    u16_le payload_length{};
+    u32_le crc{};
+    u32_le id{};
     ///> In the protocol, the type of the packet is not part of the header, but its convenient to
     ///> include in the header so the callee doesn't have to duplicate the type twice when building
     ///> the data
-    Type type;
+    Type type{};
 };
 static_assert(sizeof(Header) == 20, "UDP Message Header struct has wrong size");
 static_assert(std::is_trivially_copyable_v<Header>, "UDP Message Header is not trivially copyable");
@@ -44,7 +44,7 @@ constexpr MacAddress EMPTY_MAC_ADDRESS = {0, 0, 0, 0, 0, 0};
 #pragma pack(push, 1)
 template <typename T>
 struct Message {
-    Header header;
+    Header header{};
     T data;
 };
 #pragma pack(pop)
@@ -63,7 +63,7 @@ struct Version {};
  */
 constexpr u32 MAX_PORTS = 4;
 struct PortInfo {
-    u32_le pad_count; ///> Number of ports to request data for
+    u32_le pad_count{}; ///> Number of ports to request data for
     std::array<u8, MAX_PORTS> port;
 };
 static_assert(std::is_trivially_copyable_v<PortInfo>,
@@ -81,9 +81,9 @@ struct PadData {
         Mac,
     };
     /// Determines which method will be used as a look up for the controller
-    Flags flags;
+    Flags flags{};
     /// Index of the port of the controller to retrieve data about
-    u8 port_id;
+    u8 port_id{};
     /// Mac address of the controller to retrieve data about
     MacAddress mac;
 };
@@ -112,20 +112,20 @@ Message<T> Create(const T data, const u32 client_id = 0) {
 namespace Response {
 
 struct Version {
-    u16_le version;
+    u16_le version{};
 };
 static_assert(sizeof(Version) == 2, "UDP Response Version struct has wrong size");
 static_assert(std::is_trivially_copyable_v<Version>,
               "UDP Response Version is not trivially copyable");
 
 struct PortInfo {
-    u8 id;
-    u8 state;
-    u8 model;
-    u8 connection_type;
+    u8 id{};
+    u8 state{};
+    u8 model{};
+    u8 connection_type{};
     MacAddress mac;
-    u8 battery;
-    u8 is_pad_active;
+    u8 battery{};
+    u8 is_pad_active{};
 };
 static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size");
 static_assert(std::is_trivially_copyable_v<PortInfo>,
@@ -133,10 +133,10 @@ static_assert(std::is_trivially_copyable_v<PortInfo>,
 
 #pragma pack(push, 1)
 struct PadData {
-    PortInfo info;
-    u32_le packet_counter;
+    PortInfo info{};
+    u32_le packet_counter{};
 
-    u16_le digital_button;
+    u16_le digital_button{};
     // The following union isn't trivially copyable but we don't use this input anyway.
     // union DigitalButton {
     //     u16_le button;
@@ -160,46 +160,46 @@ struct PadData {
 
     u8 home;
     /// If the device supports a "click" on the touchpad, this will change to 1 when a click happens
-    u8 touch_hard_press;
-    u8 left_stick_x;
-    u8 left_stick_y;
-    u8 right_stick_x;
-    u8 right_stick_y;
+    u8 touch_hard_press{};
+    u8 left_stick_x{};
+    u8 left_stick_y{};
+    u8 right_stick_x{};
+    u8 right_stick_y{};
 
     struct AnalogButton {
-        u8 button_8;
-        u8 button_7;
-        u8 button_6;
-        u8 button_5;
-        u8 button_12;
-        u8 button_11;
-        u8 button_10;
-        u8 button_9;
-        u8 button_16;
-        u8 button_15;
-        u8 button_14;
-        u8 button_13;
+        u8 button_8{};
+        u8 button_7{};
+        u8 button_6{};
+        u8 button_5{};
+        u8 button_12{};
+        u8 button_11{};
+        u8 button_10{};
+        u8 button_9{};
+        u8 button_16{};
+        u8 button_15{};
+        u8 button_14{};
+        u8 button_13{};
     } analog_button;
 
     struct TouchPad {
-        u8 is_active;
-        u8 id;
-        u16_le x;
-        u16_le y;
+        u8 is_active{};
+        u8 id{};
+        u16_le x{};
+        u16_le y{};
     } touch_1, touch_2;
 
     u64_le motion_timestamp;
 
     struct Accelerometer {
-        float x;
-        float y;
-        float z;
+        float x{};
+        float y{};
+        float z{};
     } accel;
 
     struct Gyroscope {
-        float pitch;
-        float yaw;
-        float roll;
+        float pitch{};
+        float yaw{};
+        float roll{};
     } gyro;
 };
 #pragma pack(pop)
@@ -211,6 +211,13 @@ static_assert(std::is_trivially_copyable_v<PadData>,
 static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE,
               "UDP MAX_PACKET_SIZE is no longer larger than Message<PadData>");
 
+static_assert(sizeof(PadData::AnalogButton) == 12,
+              "UDP Response AnalogButton struct has wrong size ");
+static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size ");
+static_assert(sizeof(PadData::Accelerometer) == 12,
+              "UDP Response Accelerometer struct has wrong size ");
+static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size ");
+
 /**
  * Create a Response Message from the data
  * @param data array of bytes sent from the server
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index c4d5121b9..c1d417abb 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <mutex>
+#include <optional>
 #include <tuple>
 #include "common/param_package.h"
 #include "core/frontend/input.h"
@@ -43,7 +44,7 @@ public:
     std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override {
         {
             std::lock_guard guard(status->update_mutex);
-            status->touch_calibration.emplace();
+            status->touch_calibration = DeviceStatus::CalibrationData{};
             // These default values work well for DS4 but probably not other touch inputs
             status->touch_calibration->min_x = params.Get("min_x", 100);
             status->touch_calibration->min_y = params.Get("min_y", 50);