diff options
author | amit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-24 02:36:05 +0000 |
---|---|---|
committer | amit@chromium.org <amit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-24 02:36:05 +0000 |
commit | a7c03d4f3c5b36df2375ff24d5e279221ae65ed1 (patch) | |
tree | ee5d8eeab67c65059c0e24697b88ba7532b591c1 /ipc | |
parent | e855c3245ecfcb88e8782c2e6f9ad4f75e9eb912 (diff) | |
download | chromium_src-a7c03d4f3c5b36df2375ff24d5e279221ae65ed1.zip chromium_src-a7c03d4f3c5b36df2375ff24d5e279221ae65ed1.tar.gz chromium_src-a7c03d4f3c5b36df2375ff24d5e279221ae65ed1.tar.bz2 |
Initialize IPC:ChannelHandle from existing HANDLE
1] Add a ctor to IPC:ChannelHandle that takes a pipe HANDLE.
2] Corresponding change in Channel::ChannelImpl::CreatePipe to
attach to the given pipe instead of creating a new one.
Being able to hand over a pipe handle to IPC::Channel in this way has
other advantages such as using anonymous pipes and safer connections
between process with different level of privileges. Here's how it
can be done:
Server Process:
- Create a server pipe, anonymous pipe is fine too.
- Server creates a client handle of pipe using CreateFile.
- Use DuplicateHandle to duplicate this handle for the client process.
- pass over the handle value to the client process, say using comman line.
Client process:
- Simply receive the handle from the server and hand it over to
IPC:Channel using IPC::ChannelHandle.
Apart from being more flexible, this is more secure as it removes
the 'connection window' while using names.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/9150030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118786 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/ipc_channel_handle.h | 30 | ||||
-rw-r--r-- | ipc/ipc_channel_win.cc | 41 | ||||
-rw-r--r-- | ipc/ipc_message_utils.cc | 6 | ||||
-rw-r--r-- | ipc/ipc_tests.cc | 41 |
4 files changed, 105 insertions, 13 deletions
diff --git a/ipc/ipc_channel_handle.h b/ipc/ipc_channel_handle.h index ba034cc..7eceebb 100644 --- a/ipc/ipc_channel_handle.h +++ b/ipc/ipc_channel_handle.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,17 +12,24 @@ #if defined(OS_POSIX) #include "base/file_descriptor_posix.h" -#endif +#elif defined(OS_WIN) +#include <windows.h> +#endif // defined (OS_WIN) // On Windows, any process can create an IPC channel and others can fetch // it by name. We pass around the channel names over IPC. +// On Windows the initialization of ChannelHandle with an existing pipe +// handle is provided for convenience. +// NOTE: A ChannelHandle with a pipe handle Will NOT be marshalled over IPC. + // On POSIX, we instead pass around handles to channel endpoints via IPC. // When it's time to IPC a new channel endpoint around, we send both the // channel name as well as a base::FileDescriptor, which is itself a special // type that knows how to copy a socket endpoint over IPC. // -// In sum, when passing a handle to a channel over IPC, use this data structure -// to work on both Windows and POSIX. +// In sum, this data structure can be used to pass channel information by name +// in both Windows and Posix. When passing a handle to a channel over IPC, +// use this data structure only for POSIX. namespace IPC { @@ -35,7 +42,9 @@ struct ChannelHandle { // processes with different working directories. ChannelHandle(const std::string& n) : name(n) {} ChannelHandle(const char* n) : name(n) {} -#if defined(OS_POSIX) +#if defined(OS_WIN) + explicit ChannelHandle(HANDLE h) : pipe(h) {} +#elif defined(OS_POSIX) ChannelHandle(const std::string& n, const base::FileDescriptor& s) : name(n), socket(s) {} #endif // defined(OS_POSIX) @@ -43,8 +52,15 @@ struct ChannelHandle { std::string name; #if defined(OS_POSIX) base::FileDescriptor socket; -#endif // defined(OS_POSIX) - +#elif defined(OS_WIN) + // A simple container to automatically initialize pipe handle + struct PipeHandle { + PipeHandle() : handle(NULL) {} + PipeHandle(HANDLE h) : handle(h) {} + HANDLE handle; + }; + PipeHandle pipe; +#endif // defined (OS_WIN) }; } // namespace IPC diff --git a/ipc/ipc_channel_win.cc b/ipc/ipc_channel_win.cc index cd313d2..7b4f174 100644 --- a/ipc/ipc_channel_win.cc +++ b/ipc/ipc_channel_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -114,11 +114,39 @@ const std::wstring Channel::ChannelImpl::PipeName( bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, Mode mode) { DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); - const std::wstring pipe_name = PipeName(channel_handle.name); - if (mode & MODE_SERVER_FLAG) { + string16 pipe_name; + // If we already have a valid pipe for channel just copy it. + if (channel_handle.pipe.handle) { + DCHECK(channel_handle.name.empty()); + pipe_name = L"Not Available"; // Just used for LOG + // Check that the given pipe confirms to the specified mode. We can + // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the + // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0. + DWORD flags = 0; + GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL); + DCHECK(!(flags & PIPE_TYPE_MESSAGE)); + if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) || + ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) { + LOG(WARNING) << "Inconsistent open mode. Mode :" << mode; + return false; + } + if (!DuplicateHandle(GetCurrentProcess(), + channel_handle.pipe.handle, + GetCurrentProcess(), + &pipe_, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError(); + return false; + } + } else if (mode & MODE_SERVER_FLAG) { + DCHECK(!channel_handle.pipe.handle); + const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE; + pipe_name = PipeName(channel_handle.name); pipe_ = CreateNamedPipeW(pipe_name.c_str(), - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | - FILE_FLAG_FIRST_PIPE_INSTANCE, + open_mode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, Channel::kReadBufferSize, @@ -126,6 +154,8 @@ bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, 5000, NULL); } else if (mode & MODE_CLIENT_FLAG) { + DCHECK(!channel_handle.pipe.handle); + pipe_name = PipeName(channel_handle.name); pipe_ = CreateFileW(pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, @@ -137,6 +167,7 @@ bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, } else { NOTREACHED(); } + if (pipe_ == INVALID_HANDLE_VALUE) { // If this process is being closed, the pipe may be gone already. LOG(WARNING) << "Unable to create pipe \"" << pipe_name << diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc index bc5f645..03d326b 100644 --- a/ipc/ipc_message_utils.cc +++ b/ipc/ipc_message_utils.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -433,6 +433,10 @@ void ParamTraits<base::FileDescriptor>::Log(const param_type& p, #endif // defined(OS_POSIX) void ParamTraits<IPC::ChannelHandle>::Write(Message* m, const param_type& p) { +#if defined(OS_WIN) + // On Windows marshalling pipe handle is not supported. + DCHECK(p.pipe.handle == NULL); +#endif // defined (OS_WIN) WriteParam(m, p.name); #if defined(OS_POSIX) WriteParam(m, p.socket); diff --git a/ipc/ipc_tests.cc b/ipc/ipc_tests.cc index b6fd38b..2a78f44 100644 --- a/ipc/ipc_tests.cc +++ b/ipc/ipc_tests.cc @@ -240,6 +240,47 @@ TEST_F(IPCChannelTest, ChannelTest) { base::CloseProcessHandle(process_handle); } +#if defined(OS_WIN) +TEST_F(IPCChannelTest, ChannelTestExistingPipe) { + MyChannelListener channel_listener; + // Setup IPC channel with existing pipe. Specify name in Chrome format. + std::string name("\\\\.\\pipe\\chrome."); + name.append(kTestClientChannel); + const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE; + HANDLE pipe = CreateNamedPipeA(name.c_str(), + open_mode, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, + 1, + 4096, + 4096, + 5000, + NULL); + IPC::Channel chan(IPC::ChannelHandle(pipe), IPC::Channel::MODE_SERVER, + &channel_listener); + // Channel will duplicate the handle. + CloseHandle(pipe); + ASSERT_TRUE(chan.Connect()); + + channel_listener.Init(&chan); + + base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan); + ASSERT_TRUE(process_handle); + + Send(&chan, "hello from parent"); + + // Run message loop. + MessageLoop::current()->Run(); + + // Close Channel so client gets its OnChannelError() callback fired. + chan.Close(); + + // Cleanup child process. + EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000)); + base::CloseProcessHandle(process_handle); +} +#endif // defined (OS_WIN) + TEST_F(IPCChannelTest, ChannelProxyTest) { MyChannelListener channel_listener; |