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/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/embedder/platform_handle.h" 18 19 namespace mojo { 20 namespace embedder { 21 22 namespace { 23 24 std::wstring GeneratePipeName() { 25 return base::StringPrintf( 26 L"\\\\.\\pipe\\mojo.%u.%u.%I64u", 27 GetCurrentProcessId(), GetCurrentThreadId(), base::RandUint64()); 28 } 29 30 } // namespace 31 32 PlatformChannelPair::PlatformChannelPair() { 33 std::wstring pipe_name = GeneratePipeName(); 34 35 const DWORD kOpenMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | 36 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(), 40 kOpenMode, 41 kPipeMode, 42 1, // Max instances. 43 4096, // Out buffer size. 44 4096, // In buffer size. 45 5000, // Timeout in milliseconds. 46 NULL))); // Default security descriptor. 47 PCHECK(server_handle_.is_valid()); 48 49 const DWORD kDesiredAccess = GENERIC_READ | GENERIC_WRITE; 50 // The SECURITY_ANONYMOUS flag means that the server side cannot impersonate 51 // the client. 52 const DWORD kFlags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | 53 FILE_FLAG_OVERLAPPED; 54 // Allow the handle to be inherited by child processes. 55 SECURITY_ATTRIBUTES security_attributes = { 56 sizeof(SECURITY_ATTRIBUTES), NULL, TRUE 57 }; 58 client_handle_.reset(PlatformHandle( 59 CreateFileW(pipe_name.c_str(), 60 kDesiredAccess, 61 0, // No sharing. 62 &security_attributes, 63 OPEN_EXISTING, 64 kFlags, 65 NULL))); // No template file. 66 PCHECK(client_handle_.is_valid()); 67 68 // Since a client has connected, ConnectNamedPipe() should return zero and 69 // GetLastError() should return ERROR_PIPE_CONNECTED. 70 CHECK(!ConnectNamedPipe(server_handle_.get().handle, NULL)); 71 PCHECK(GetLastError() == ERROR_PIPE_CONNECTED); 72 } 73 74 // static 75 ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess( 76 const base::CommandLine& command_line) { 77 std::string client_handle_string = 78 command_line.GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch); 79 80 int client_handle_value = 0; 81 if (client_handle_string.empty() || 82 !base::StringToInt(client_handle_string, &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 DCHECK(handle_passing_info); 96 DCHECK(client_handle_.is_valid()); 97 98 CHECK_GE(base::win::GetVersion(), base::win::VERSION_VISTA); 99 100 handle_passing_info->push_back(client_handle_.get().handle); 101 102 // Log a warning if the command line already has the switch, but "clobber" it 103 // anyway, since it's reasonably likely that all the switches were just copied 104 // from the parent. 105 LOG_IF(WARNING, command_line->HasSwitch(kMojoPlatformChannelHandleSwitch)) 106 << "Child command line already has switch --" 107 << kMojoPlatformChannelHandleSwitch << "=" 108 << command_line->GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch); 109 // (Any existing switch won't actually be removed from the command line, but 110 // the last one appended takes precedence.) 111 command_line->AppendSwitchASCII( 112 kMojoPlatformChannelHandleSwitch, 113 base::IntToString(HandleToLong(client_handle_.get().handle))); 114 } 115 116 } // namespace embedder 117 } // namespace mojo 118