diff options
| author | Odd Stranne <odd@mullvad.net> | 2018-09-08 22:46:03 +0200 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2018-09-12 13:20:20 +0200 |
| commit | df4d2b64449cae87ddab43c634b7f35485e919b3 (patch) | |
| tree | c8245dc17936e3bd776e03589fa61af8f0324814 /windows | |
| parent | 4cea1a683f2abfb4ee6b0549bdcf9db2517bb400 (diff) | |
| download | mullvadvpn-df4d2b64449cae87ddab43c634b7f35485e919b3.tar.xz mullvadvpn-df4d2b64449cae87ddab43c634b7f35485e919b3.zip | |
Include output from 'netsh' if requested operation fails or times out
Diffstat (limited to 'windows')
| -rw-r--r-- | windows/windns/src/windns/netsh.cpp | 56 | ||||
| -rw-r--r-- | windows/windns/src/windns/netsh.h | 23 |
2 files changed, 75 insertions, 4 deletions
diff --git a/windows/windns/src/windns/netsh.cpp b/windows/windns/src/windns/netsh.cpp index af65ace2a9..fc46d824c2 100644 --- a/windows/windns/src/windns/netsh.cpp +++ b/windows/windns/src/windns/netsh.cpp @@ -1,21 +1,69 @@ #include "stdafx.h" #include "netsh.h" #include "libcommon/applicationrunner.h" +#include "libcommon/string.h" #include <sstream> #include <stdexcept> namespace { +std::vector<std::string> BlockToRows(const std::string &textBlock) +{ + // + // TODO: Formalize and move to libcommon. + // There is a recurring need to split a text block into lines, ignoring blank lines. + // + // Also, changing the encoding back and forth is terribly wasteful. + // Should look into replacing all of this with Boost some day. + // + + const auto wideTextBlock = common::string::ToWide(textBlock); + const auto wideRows = common::string::Tokenize(wideTextBlock, L"\r\n"); + + std::vector<std::string> result; + + result.reserve(wideRows.size()); + + std::transform(wideRows.begin(), wideRows.end(), std::back_inserter(result), [](const std::wstring &str) + { + return common::string::ToAnsi(str); + }); + + return result; +} + +__declspec(noreturn) void ThrowWithDetails(std::string &&error, common::ApplicationRunner &netsh) +{ + std::vector<std::string> details { "Failed to capture output from 'netsh'" }; + + std::string output; + + static const size_t MAX_CHARS = 2048; + static const size_t TIMEOUT_MILLISECONDS = 2000; + + if (netsh.read(output, MAX_CHARS, TIMEOUT_MILLISECONDS)) + { + auto outputRows = BlockToRows(output); + + if (false == outputRows.empty()) + { + details = std::move(outputRows); + } + } + + throw NetShError(std::move(error), std::move(details)); +} + void ValidateShellOut(common::ApplicationRunner &netsh) { - static const uint32_t TIMEOUT_TWO_SECONDS = 2000; + static const size_t TIMEOUT_MILLISECONDS = 2000; DWORD returnCode; - if (false == netsh.join(returnCode, TIMEOUT_TWO_SECONDS)) + if (false == netsh.join(returnCode, TIMEOUT_MILLISECONDS)) { - throw std::runtime_error("'netsh' did not complete in a timely manner"); + ThrowWithDetails("'netsh' did not complete in a timely manner", netsh); } if (returnCode != 0) @@ -24,7 +72,7 @@ void ValidateShellOut(common::ApplicationRunner &netsh) ss << "'netsh' failed the requested operation. Error: " << returnCode; - throw std::runtime_error(ss.str()); + ThrowWithDetails(ss.str(), netsh); } } diff --git a/windows/windns/src/windns/netsh.h b/windows/windns/src/windns/netsh.h index d299cf6f87..7aa5b800f0 100644 --- a/windows/windns/src/windns/netsh.h +++ b/windows/windns/src/windns/netsh.h @@ -2,6 +2,7 @@ #include <string> #include <cstdint> +#include <stdexcept> class NetSh { @@ -24,3 +25,25 @@ private: NetSh(); }; + +class NetShError : public std::exception +{ +public: + + NetShError(std::string &&error, std::vector<std::string> &&details) + : std::exception(error.c_str()) + , m_error(std::move(error)) + , m_details(std::move(details)) + { + } + + const std::vector<std::string> &details() + { + return m_details; + } + +private: + + const std::string m_error; + const std::vector<std::string> m_details; +}; |
