1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/edk/embedder/platform_channel_pair.h" 6 7 #include <windows.h> 8 9 #include <string> 10 11 #include "base/command_line.h" 12 #include "base/logging.h" 13 #include "base/rand_util.h" 14 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/win/windows_version.h" 17 #include "mojo/edk/embedder/platform_handle.h" 18 19 namespace mojo { 20 namespace edk { 21 22 namespace { 23 24 std::wstring GeneratePipeName() { 25 return base::StringPrintf(L"\\\\.\\pipe\\mojo.%u.%u.%I64u", 26 GetCurrentProcessId(), GetCurrentThreadId(), 27 base::RandUint64()); 28 } 29 30 } // namespace 31 32 PlatformChannelPair::PlatformChannelPair(bool client_is_blocking) { 33 std::wstring pipe_name = GeneratePipeName(); 34 35 DWORD kOpenMode = 36 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE; 37 const DWORD kPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE; 38 server_handle_.reset(PlatformHandle( 39 CreateNamedPipeW(pipe_name.c_str(), kOpenMode, kPipeMode, 40 1, // Max instances. 41 4096, // Out buffer size. 42 4096, // In buffer size. 43 5000, // Timeout in milliseconds. 44 nullptr))); // Default security descriptor. 45 PCHECK(server_handle_.is_valid()); 46 47 const DWORD kDesiredAccess = GENERIC_READ | GENERIC_WRITE; 48 // The SECURITY_ANONYMOUS flag means that the server side cannot impersonate 49 // the client. 50 DWORD kFlags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS; 51 if (!client_is_blocking) 52 kFlags |= FILE_FLAG_OVERLAPPED; 53 // Allow the handle to be inherited by child processes. 54 SECURITY_ATTRIBUTES security_attributes = { 55 sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE}; 56 client_handle_.reset( 57 PlatformHandle(CreateFileW(pipe_name.c_str(), kDesiredAccess, 58 0, // No sharing. 59 &security_attributes, OPEN_EXISTING, kFlags, 60 nullptr))); // No template file. 61 PCHECK(client_handle_.is_valid()); 62 63 // Since a client has connected, ConnectNamedPipe() should return zero and 64 // GetLastError() should return ERROR_PIPE_CONNECTED. 65 CHECK(!ConnectNamedPipe(server_handle_.get().handle, nullptr)); 66 PCHECK(GetLastError() == ERROR_PIPE_CONNECTED); 67 } 68 69 // static 70 ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess( 71 const base::CommandLine& command_line) { 72 std::string client_handle_string = 73 command_line.GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch); 74 return PassClientHandleFromParentProcessFromString(client_handle_string); 75 } 76 77 ScopedPlatformHandle 78 PlatformChannelPair::PassClientHandleFromParentProcessFromString( 79 const std::string& value) { 80 int client_handle_value = 0; 81 if (value.empty() || 82 !base::StringToInt(value, &client_handle_value)) { 83 LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch; 84 return ScopedPlatformHandle(); 85 } 86 87 return ScopedPlatformHandle( 88 PlatformHandle(LongToHandle(client_handle_value))); 89 } 90 91 void PlatformChannelPair::PrepareToPassClientHandleToChildProcess( 92 base::CommandLine* command_line, 93 base::HandlesToInheritVector* handle_passing_info) const { 94 DCHECK(command_line); 95 96 // Log a warning if the command line already has the switch, but "clobber" it 97 // anyway, since it's reasonably likely that all the switches were just copied 98 // from the parent. 99 LOG_IF(WARNING, command_line->HasSwitch(kMojoPlatformChannelHandleSwitch)) 100 << "Child command line already has switch --" 101 << kMojoPlatformChannelHandleSwitch << "=" 102 << command_line->GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch); 103 // (Any existing switch won't actually be removed from the command line, but 104 // the last one appended takes precedence.) 105 command_line->AppendSwitchASCII( 106 kMojoPlatformChannelHandleSwitch, 107 PrepareToPassClientHandleToChildProcessAsString(handle_passing_info)); 108 } 109 110 std::string 111 PlatformChannelPair::PrepareToPassClientHandleToChildProcessAsString( 112 HandlePassingInformation* handle_passing_info) const { 113 DCHECK(handle_passing_info); 114 DCHECK(client_handle_.is_valid()); 115 116 if (base::win::GetVersion() >= base::win::VERSION_VISTA) 117 handle_passing_info->push_back(client_handle_.get().handle); 118 119 return base::IntToString(HandleToLong(client_handle_.get().handle)); 120 } 121 122 } // namespace edk 123 } // namespace mojo 124