• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GeneratePipeName()24 std::wstring GeneratePipeName() {
25   return base::StringPrintf(L"\\\\.\\pipe\\mojo.%u.%u.%I64u",
26                             GetCurrentProcessId(),
27                             GetCurrentThreadId(),
28                             base::RandUint64());
29 }
30 
31 }  // namespace
32 
PlatformChannelPair()33 PlatformChannelPair::PlatformChannelPair() {
34   std::wstring pipe_name = GeneratePipeName();
35 
36   const DWORD kOpenMode =
37       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE;
38   const DWORD kPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE;
39   server_handle_.reset(PlatformHandle(
40       CreateNamedPipeW(pipe_name.c_str(),
41                        kOpenMode,
42                        kPipeMode,
43                        1,           // Max instances.
44                        4096,        // Out buffer size.
45                        4096,        // In buffer size.
46                        5000,        // Timeout in milliseconds.
47                        nullptr)));  // Default security descriptor.
48   PCHECK(server_handle_.is_valid());
49 
50   const DWORD kDesiredAccess = GENERIC_READ | GENERIC_WRITE;
51   // The SECURITY_ANONYMOUS flag means that the server side cannot impersonate
52   // the client.
53   const DWORD kFlags =
54       SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | FILE_FLAG_OVERLAPPED;
55   // Allow the handle to be inherited by child processes.
56   SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES),
57                                              nullptr, TRUE};
58   client_handle_.reset(
59       PlatformHandle(CreateFileW(pipe_name.c_str(),
60                                  kDesiredAccess,
61                                  0,  // No sharing.
62                                  &security_attributes,
63                                  OPEN_EXISTING,
64                                  kFlags,
65                                  nullptr)));  // 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, nullptr));
71   PCHECK(GetLastError() == ERROR_PIPE_CONNECTED);
72 }
73 
74 // static
PassClientHandleFromParentProcess(const base::CommandLine & command_line)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 
PrepareToPassClientHandleToChildProcess(base::CommandLine * command_line,base::HandlesToInheritVector * handle_passing_info) const91 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