diff options
| author | Odd Stranne <odd@mullvad.net> | 2018-06-07 11:38:47 +0200 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2018-06-18 08:45:16 +0200 |
| commit | bc557d2a36dafcb0c7cba8e0dd43fcb7e5613e6f (patch) | |
| tree | c37acd88f7a9c75ab1095424af82e6ef79d9bcb8 | |
| parent | ef99f821022c35eec1f2a4feb1f0f348d340f9f3 (diff) | |
| download | mullvadvpn-bc557d2a36dafcb0c7cba8e0dd43fcb7e5613e6f.tar.xz mullvadvpn-bc557d2a36dafcb0c7cba8e0dd43fcb7e5613e6f.zip | |
Add serialization classes
| -rw-r--r-- | windows/windns/src/windns/serialization/deserializer.cpp | 108 | ||||
| -rw-r--r-- | windows/windns/src/windns/serialization/deserializer.h | 34 | ||||
| -rw-r--r-- | windows/windns/src/windns/serialization/serializer.cpp | 111 | ||||
| -rw-r--r-- | windows/windns/src/windns/serialization/serializer.h | 33 | ||||
| -rw-r--r-- | windows/windns/src/windns/serialization/typetag.h | 21 | ||||
| -rw-r--r-- | windows/windns/src/windns/windns.vcxproj | 5 | ||||
| -rw-r--r-- | windows/windns/src/windns/windns.vcxproj.filters | 18 |
7 files changed, 330 insertions, 0 deletions
diff --git a/windows/windns/src/windns/serialization/deserializer.cpp b/windows/windns/src/windns/serialization/deserializer.cpp new file mode 100644 index 0000000000..dce6ada950 --- /dev/null +++ b/windows/windns/src/windns/serialization/deserializer.cpp @@ -0,0 +1,108 @@ +#include "stdafx.h" +#include "deserializer.h" +#include <stdexcept> + +namespace common::serialization +{ + +Deserializer::Deserializer(const uint8_t *blob, size_t size) + : m_blob(blob, blob + size) + , m_offset(0) +{ +} + +void Deserializer::operator>>(uint8_t &data) +{ + validateType(TypeTag::Uint8); + + read(&data, sizeof(data)); +} + +void Deserializer::operator>>(uint16_t &data) +{ + validateType(TypeTag::Uint16); + + read(&data, sizeof(data)); +} + +void Deserializer::operator>>(uint32_t &data) +{ + validateType(TypeTag::Uint32); + + read(&data, sizeof(data)); +} + +void Deserializer::operator>>(GUID &data) +{ + validateType(TypeTag::Guid); + + read(&data, sizeof(data)); +} + +void Deserializer::operator>>(std::wstring &data) +{ + validateType(TypeTag::String); + + uint32_t strByteLength; + + read(&strByteLength, sizeof(strByteLength)); + + if (0 == strByteLength) + { + data.clear(); + return; + } + + std::vector<uint8_t> raw(strByteLength); + + read(&raw[0], strByteLength); + + data = std::wstring + ( + reinterpret_cast<wchar_t *>(&raw[0]), + reinterpret_cast<wchar_t *>(&raw[0]) + (strByteLength / sizeof(wchar_t)) + ); +} + +void Deserializer::operator>>(std::vector<std::wstring> &data) +{ + validateType(TypeTag::StringArray); + + uint32_t elements; + + read(&elements, sizeof(elements)); + + data.clear(); + + for (uint32_t i = 0; i < elements; ++i) + { + data.emplace_back(std::wstring()); + *this >> *data.rbegin(); + } +} + +void Deserializer::validateType(TypeTag type) +{ + uint8_t readType; + + read(&readType, sizeof(uint8_t)); + + if (readType != static_cast<uint8_t>(type)) + { + throw std::runtime_error("Unexpected data type in stream"); + } +} + +void Deserializer::read(void *data, size_t length) +{ + if (m_offset + length > m_blob.size()) + { + throw std::runtime_error("Read probe passed end of stream"); + } + + memcpy(data, &m_blob[m_offset], length); + + m_offset += length; +} + +} diff --git a/windows/windns/src/windns/serialization/deserializer.h b/windows/windns/src/windns/serialization/deserializer.h new file mode 100644 index 0000000000..a2c59400fd --- /dev/null +++ b/windows/windns/src/windns/serialization/deserializer.h @@ -0,0 +1,34 @@ +#pragma once + +#include "typetag.h" +#include <vector> +#include <string> +#include <cstdint> +#include <guiddef.h> + +namespace common::serialization +{ + +class Deserializer +{ +public: + + Deserializer(const uint8_t *blob, size_t size); + + void operator>>(uint8_t &data); + void operator>>(uint16_t &data); + void operator>>(uint32_t &data); + void operator>>(GUID &data); + void operator>>(std::wstring &data); + void operator>>(std::vector<std::wstring> &data); + +private: + + std::vector<uint8_t> m_blob; + size_t m_offset; + + void validateType(TypeTag type); + void read(void *data, size_t length); +}; + +} diff --git a/windows/windns/src/windns/serialization/serializer.cpp b/windows/windns/src/windns/serialization/serializer.cpp new file mode 100644 index 0000000000..e4af65db98 --- /dev/null +++ b/windows/windns/src/windns/serialization/serializer.cpp @@ -0,0 +1,111 @@ +#include "stdafx.h" +#include "serializer.h" +#include <algorithm> + +namespace +{ + +void Append(std::vector<uint8_t> &v, const void *data, size_t length) +{ + if (0 == length) + { + return; + } + + const auto oldSize = v.size(); + + v.resize(oldSize + length); + memcpy(&v[oldSize], data, length); +} + +std::vector<uint8_t> PackageString(const wchar_t *str) +{ + const auto strByteLength = static_cast<uint32_t>(wcslen(str) * sizeof(wchar_t)); + + std::vector<uint8_t> data; + + Append(data, &strByteLength, sizeof(strByteLength)); + Append(data, str, strByteLength); + + return data; +} + +} // anonymous namespace + +namespace common::serialization +{ + +void Serializer::operator<<(uint8_t data) +{ + append(TypeTag::Uint8, &data, sizeof(uint8_t)); +} + +void Serializer::operator<<(uint16_t data) +{ + append(TypeTag::Uint16, &data, sizeof(uint16_t)); +} + +void Serializer::operator<<(uint32_t data) +{ + append(TypeTag::Uint32, &data, sizeof(uint32_t)); +} + +void Serializer::operator<<(const GUID &data) +{ + append(TypeTag::Guid, &data, sizeof(GUID)); +} + +void Serializer::operator<<(const std::wstring &data) +{ + auto packaged = PackageString(data.c_str()); + + append(TypeTag::String, &packaged[0], packaged.size()); +} + +void Serializer::operator<<(const wchar_t *data) +{ + auto packaged = PackageString(data); + + append(TypeTag::String, &packaged[0], packaged.size()); +} + +void Serializer::operator<<(const std::vector<std::wstring> &data) +{ + std::vector<uint8_t> arrayBlob; + + uint32_t count = static_cast<uint32_t>(data.size()); + + Append(arrayBlob, &count, sizeof(count)); + + std::for_each(data.begin(), data.end(), [&](const std::wstring &str) + { + auto packagedStr = PackageString(str.c_str()); + + // Hack? Makes parsing a lot simpler + arrayBlob.push_back(static_cast<uint8_t>(TypeTag::String)); + + Append(arrayBlob, &packagedStr[0], packagedStr.size()); + }); + + append(TypeTag::StringArray, &arrayBlob[0], arrayBlob.size()); +} + +const std::vector<uint8_t> &Serializer::blob() const +{ + return m_blob; +} + +void Serializer::append(TypeTag type, const void *data, size_t length) +{ + const auto elementSize = sizeof(uint8_t) + length; + const auto oldSize = m_blob.size(); + + m_blob.resize(oldSize + elementSize); + + auto dest = &m_blob[oldSize]; + + *dest++ = static_cast<uint8_t>(type); + memcpy(dest, data, length); +} + +} diff --git a/windows/windns/src/windns/serialization/serializer.h b/windows/windns/src/windns/serialization/serializer.h new file mode 100644 index 0000000000..63e9fdd5bb --- /dev/null +++ b/windows/windns/src/windns/serialization/serializer.h @@ -0,0 +1,33 @@ +#pragma once + +#include "typetag.h" +#include <vector> +#include <string> +#include <cstdint> +#include <guiddef.h> + +namespace common::serialization +{ + +class Serializer +{ +public: + + void operator<<(uint8_t data); + void operator<<(uint16_t data); + void operator<<(uint32_t data); + void operator<<(const GUID &data); + void operator<<(const std::wstring &data); + void operator<<(const wchar_t *data); + void operator<<(const std::vector<std::wstring> &data); + + const std::vector<uint8_t> &blob() const; + +private: + + std::vector<uint8_t> m_blob; + + void append(TypeTag type, const void *data, size_t length); +}; + +} diff --git a/windows/windns/src/windns/serialization/typetag.h b/windows/windns/src/windns/serialization/typetag.h new file mode 100644 index 0000000000..a2ab3cccc3 --- /dev/null +++ b/windows/windns/src/windns/serialization/typetag.h @@ -0,0 +1,21 @@ +#pragma once + +namespace common::serialization +{ + +enum class TypeTag +{ + Uint8, + Uint16, + Uint32, + Guid, // data = binary 16 bytes + String, // data = [uint32: byte length], [UCS-2 string], [NOT zero terminated] + StringArray // data = [uint32: count], count * String +}; + +// +// Each entry is serialized as: +// [uint8: type], [data] +// + +} diff --git a/windows/windns/src/windns/windns.vcxproj b/windows/windns/src/windns/windns.vcxproj index 6444255869..89d5c89d33 100644 --- a/windows/windns/src/windns/windns.vcxproj +++ b/windows/windns/src/windns/windns.vcxproj @@ -186,6 +186,9 @@ <ClInclude Include="netconfigeventsink.h" /> <ClInclude Include="netconfighelpers.h" /> <ClInclude Include="netsh.h" /> + <ClInclude Include="serialization\deserializer.h" /> + <ClInclude Include="serialization\serializer.h" /> + <ClInclude Include="serialization\typetag.h" /> <ClInclude Include="stdafx.h" /> <ClInclude Include="targetver.h" /> <ClInclude Include="windns.h" /> @@ -208,6 +211,8 @@ <ClCompile Include="netconfigeventsink.cpp" /> <ClCompile Include="netconfighelpers.cpp" /> <ClCompile Include="netsh.cpp" /> + <ClCompile Include="serialization\deserializer.cpp" /> + <ClCompile Include="serialization\serializer.cpp" /> <ClCompile Include="stdafx.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> diff --git a/windows/windns/src/windns/windns.vcxproj.filters b/windows/windns/src/windns/windns.vcxproj.filters index fcfb5045bc..ff323bfefa 100644 --- a/windows/windns/src/windns/windns.vcxproj.filters +++ b/windows/windns/src/windns/windns.vcxproj.filters @@ -37,6 +37,15 @@ </ClInclude> <ClInclude Include="netsh.h" /> <ClInclude Include="interfaceconfig.h" /> + <ClInclude Include="serialization\deserializer.h"> + <Filter>serialization</Filter> + </ClInclude> + <ClInclude Include="serialization\serializer.h"> + <Filter>serialization</Filter> + </ClInclude> + <ClInclude Include="serialization\typetag.h"> + <Filter>serialization</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="dllmain.cpp" /> @@ -66,10 +75,19 @@ </ClCompile> <ClCompile Include="netsh.cpp" /> <ClCompile Include="interfaceconfig.cpp" /> + <ClCompile Include="serialization\deserializer.cpp"> + <Filter>serialization</Filter> + </ClCompile> + <ClCompile Include="serialization\serializer.cpp"> + <Filter>serialization</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <Filter Include="wmi"> <UniqueIdentifier>{5deb73ee-53cc-49ac-bcdd-0a4b38914f0e}</UniqueIdentifier> </Filter> + <Filter Include="serialization"> + <UniqueIdentifier>{94b59808-58b6-431c-9b5a-e0bd5315a7af}</UniqueIdentifier> + </Filter> </ItemGroup> </Project>
\ No newline at end of file |
