| Index: src/shared/Communication.cpp |
| =================================================================== |
| --- a/src/shared/Communication.cpp |
| +++ b/src/shared/Communication.cpp |
| @@ -1,34 +1,85 @@ |
| -#include "..\engine\stdafx.h" |
| - |
| +#include <Windows.h> |
| #include <Lmcons.h> |
| +#include <Sddl.h> |
| #include "Communication.h" |
| namespace |
| { |
| + std::string AppendErrorCode(const std::string& message) |
| + { |
| + std::stringstream stream; |
| + stream << message << " (Error code: " << GetLastError() << ")"; |
| + return stream.str(); |
| + } |
| + |
| std::wstring GetUserName() |
| { |
| const DWORD maxLength = UNLEN + 1; |
| std::auto_ptr<wchar_t> buffer(new wchar_t[maxLength]); |
| DWORD length = maxLength; |
| - if (!::GetUserName(buffer.get(), &length)) |
| - { |
| - std::stringstream stream; |
| - stream << "Failed to get the current user's name (Error code: " << GetLastError() << ")"; |
| - throw std::runtime_error("Failed to get the current user's name"); |
| - } |
| + if (!::GetUserNameW(buffer.get(), &length)) |
|
Felix Dahlke
2013/06/04 06:39:39
Agreed, we should do that with all the other calls
|
| + throw std::runtime_error(AppendErrorCode("Failed to get the current user's name")); |
| return std::wstring(buffer.get(), length); |
| } |
| } |
| const std::wstring Communication::pipeName = L"\\\\.\\pipe\\adblockplusengine_" + GetUserName(); |
| -Communication::InputBuffer Communication::ReadMessage(HANDLE pipe) |
| +Communication::PipeConnectionError::PipeConnectionError() |
| + : std::runtime_error(AppendErrorCode("Unable to connect to a named pipe")) |
| +{ |
| +} |
| + |
| +Communication::Pipe::Pipe(const std::wstring& pipeName, Communication::Pipe::Mode mode) |
| +{ |
| + pipe = INVALID_HANDLE_VALUE; |
| + if (mode == MODE_CREATE) |
| + { |
| + SECURITY_ATTRIBUTES sa; |
| + memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); |
| + sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
| + |
| + // Low mandatory label. See http://msdn.microsoft.com/en-us/library/bb625958.aspx |
| + LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)"; |
| + PSECURITY_DESCRIPTOR securitydescriptor; |
| + ConvertStringSecurityDescriptorToSecurityDescriptorW(accessControlEntry, SDDL_REVISION_1, &securitydescriptor, 0); |
| + |
| + sa.lpSecurityDescriptor = securitydescriptor; |
| + sa.bInheritHandle = TRUE; |
| + |
| + pipe = CreateNamedPipeW (pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, |
| + PIPE_UNLIMITED_INSTANCES, Communication::bufferSize, Communication::bufferSize, 0, &sa); |
| + LocalFree(securitydescriptor); |
| + } |
| + else |
| + { |
| + if (WaitNamedPipeW(pipeName.c_str(), 5000)) |
| + pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); |
| + } |
| + |
| + if (pipe == INVALID_HANDLE_VALUE) |
| + throw PipeConnectionError(); |
| + |
| + DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; |
| + if (!SetNamedPipeHandleState(pipe, &pipeMode, 0, 0)) |
| + throw std::runtime_error("SetNamedPipeHandleState failed: error " + GetLastError()); |
| + |
| + if (mode == MODE_CREATE && !ConnectNamedPipe(pipe, 0)) |
| + throw std::runtime_error("Client failed to connect: error " + GetLastError()); |
| +} |
| + |
| +Communication::Pipe::~Pipe() |
| +{ |
| + CloseHandle(pipe); |
| +} |
| + |
| +Communication::InputBuffer Communication::Pipe::ReadMessage() |
| { |
| std::stringstream stream; |
| std::auto_ptr<char> buffer(new char[bufferSize]); |
| bool doneReading = false; |
| while (!doneReading) |
| { |
| DWORD bytesRead; |
| if (ReadFile(pipe, buffer.get(), bufferSize * sizeof(char), &bytesRead, 0)) |
| @@ -39,15 +90,15 @@ Communication::InputBuffer Communication |
| stream << "Error reading from pipe: " << GetLastError(); |
| throw std::runtime_error(stream.str()); |
| } |
| stream << std::string(buffer.get(), bytesRead); |
| } |
| return Communication::InputBuffer(stream.str()); |
| } |
| -void Communication::WriteMessage(HANDLE pipe, Communication::OutputBuffer& message) |
| +void Communication::Pipe::WriteMessage(Communication::OutputBuffer& message) |
| { |
| DWORD bytesWritten; |
| std::string data = message.Get(); |
| if (!WriteFile(pipe, data.c_str(), data.length(), &bytesWritten, 0)) |
| throw std::runtime_error("Failed to write to pipe"); |
| } |