diff options
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/sync_socket_posix.cc | 101 | ||||
-rw-r--r-- | ipc/ipc.gyp | 6 | ||||
-rw-r--r-- | ipc/sync_socket_unittest.cc | 49 |
4 files changed, 145 insertions, 12 deletions
diff --git a/base/base.gyp b/base/base.gyp index 49a6773..d225ef3 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -308,6 +308,7 @@ 'string_util_win.h', 'sync_socket.h', 'sync_socket_win.cc', + 'sync_socket_posix.cc', 'sys_info.h', 'sys_info_chromeos.cc', 'sys_info_freebsd.cc', diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc new file mode 100644 index 0000000..35d53b2 --- /dev/null +++ b/base/sync_socket_posix.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2009 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. + +#include "base/sync_socket.h" + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "base/atomicops.h" +#include "base/file_util.h" +#include "base/logging.h" + + +namespace base { + +namespace { +// To avoid users sending negative message lengths to Send/Receive +// we clamp message lengths, which are size_t, to no more than INT_MAX. +const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); + +static const SyncSocket::Handle kInvalidHandle = -1; + +} // namespace + +bool SyncSocket::CreatePair(SyncSocket* pair[2]) { + Handle handles[2] = { kInvalidHandle, kInvalidHandle }; + SyncSocket* tmp_sockets[2] = { NULL, NULL }; +#if defined(OS_MACOSX) + int nosigpipe = 1; +#endif // defined(OS_MACOSX) + + // Create the two SyncSocket objects first to avoid ugly cleanup issues. + tmp_sockets[0] = new SyncSocket(kInvalidHandle); + if (tmp_sockets[0] == NULL) { + goto cleanup; + } + tmp_sockets[1] = new SyncSocket(kInvalidHandle); + if (tmp_sockets[1] == NULL) { + goto cleanup; + } + if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) { + goto cleanup; + } +#if defined(OS_MACOSX) + // On OSX an attempt to read or write to a closed socket may generate a + // SIGPIPE rather than returning -1. setsockopt will shut this off. + if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE, + &nosigpipe, sizeof nosigpipe) || + 0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE, + &nosigpipe, sizeof nosigpipe)) { + goto cleanup; + } +#endif + // Copy the handles out for successful return. + tmp_sockets[0]->handle_ = handles[0]; + pair[0] = tmp_sockets[0]; + tmp_sockets[1]->handle_ = handles[1]; + pair[1] = tmp_sockets[1]; + return true; + +cleanup: + if (handles[0] != kInvalidHandle) + (void) close(handles[0]); + if (handles[1] != kInvalidHandle) + (void) close(handles[1]); + delete tmp_sockets[0]; + delete tmp_sockets[1]; + return false; +} + +bool SyncSocket::Close() { + if (handle_ == kInvalidHandle) { + return false; + } + int retval = close(handle_); + handle_ = kInvalidHandle; + return (retval == 0); +} + +size_t SyncSocket::Send(const void* buffer, size_t length) { + DCHECK(length <= kMaxMessageLength); + const char* charbuffer = static_cast<const char*>(buffer); + int len = file_util::WriteFileDescriptor(handle_, charbuffer, length); + return static_cast<size_t>(len); +} + +size_t SyncSocket::Receive(void* buffer, size_t length) { + DCHECK(length <= kMaxMessageLength); + char* charbuffer = static_cast<char*>(buffer); + if (file_util::ReadFromFD(handle_, charbuffer, length)) { + return length; + } else { + return -1; + } +} + +} // namespace base diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp index eecf1df..8a35b4f 100644 --- a/ipc/ipc.gyp +++ b/ipc/ipc.gyp @@ -89,6 +89,7 @@ 'ipc_sync_message_unittest.h', 'ipc_tests.cc', 'ipc_tests.h', + 'sync_socket_unittest.cc', ], 'conditions': [ ['OS=="linux"', { @@ -101,11 +102,6 @@ '../views/views.gyp:views', ], }], - ['OS=="win"', { - 'sources': [ - 'sync_socket_unittest.cc', - ], - }], ], }, ] diff --git a/ipc/sync_socket_unittest.cc b/ipc/sync_socket_unittest.cc index 47a907c..9820009 100644 --- a/ipc/sync_socket_unittest.cc +++ b/ipc/sync_socket_unittest.cc @@ -8,6 +8,9 @@ #include <sstream> #include "base/message_loop.h" +#if defined(OS_LINUX) || defined(OS_MACOSX) +#include "base/file_descriptor_posix.h" +#endif // defined(OS_LINUX) || defined(OS_MACOSX) #include "base/platform_thread.h" #include "base/process_util.h" #include "base/sync_socket.h" @@ -36,7 +39,10 @@ const char kHelloString[] = "Hello, SyncSocket Client"; const size_t kHelloStringLength = arraysize(kHelloString); } // namespace -// Message class to pass a HANDLE to another process. +// Message class to pass a base::SyncSocket::Handle to another process. +// This is not as easy as it sounds, because of the differences in transferring +// Windows HANDLEs versus posix file descriptors. +#if defined(OS_WIN) class MsgClassSetHandle : public IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> > { public: @@ -48,6 +54,21 @@ class MsgClassSetHandle private: DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle); }; +#elif defined(OS_POSIX) +class MsgClassSetHandle + : public IPC::MessageWithTuple< Tuple1<base::FileDescriptor> > { + public: + enum { ID = SERVER_FIRST_IPC_TYPE }; + explicit MsgClassSetHandle(const base::FileDescriptor& arg1) + : IPC::MessageWithTuple< Tuple1<base::FileDescriptor> >( + MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {} + + private: + DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle); +}; +#else +# error "What platform?" +#endif // defined(OS_WIN) // Message class to pass a response to the server. class MsgClassResponse @@ -99,7 +120,19 @@ class SyncSocketServerListener : public IPC::Channel::Listener { // This sort of message is sent first, causing the transfer of // the handle for the SyncSocket. This message sends a buffer // on the SyncSocket and then sends a response to the client. +#if defined(OS_WIN) void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) { + SetHandle(handle); + } +#elif defined(OS_POSIX) + void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) { + SetHandle(fd_struct.fd); + } +#else +# error "What platform?" +#endif // defined(OS_WIN) + + void SetHandle(base::SyncSocket::Handle handle) { base::SyncSocket sync_socket(handle); EXPECT_EQ(sync_socket.Send(static_cast<const void*>(kHelloString), kHelloStringLength), kHelloStringLength); @@ -184,20 +217,23 @@ TEST_F(SyncSocketTest, SanityTest) { base::SyncSocket* pair[2]; base::SyncSocket::CreatePair(pair); base::SyncSocket::Handle target_handle; + // Connect the channel and listener. + ASSERT_TRUE(chan.Connect()); + listener.Init(pair[0], &chan); #if defined(OS_WIN) // On windows we need to duplicate the handle into the server process. BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1]->handle(), server_process, &target_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); EXPECT_TRUE(retval); + // Set up a message to pass the handle to the server. + IPC::Message* msg = new MsgClassSetHandle(target_handle); #else target_handle = pair[1]->handle(); -#endif // defined(OS_WIN) - // Connect the channel and listener. - ASSERT_TRUE(chan.Connect()); - listener.Init(pair[0], &chan); // Set up a message to pass the handle to the server. - IPC::Message* msg = new MsgClassSetHandle(target_handle); + base::FileDescriptor filedesc(target_handle, false); + IPC::Message* msg = new MsgClassSetHandle(filedesc); +#endif // defined(OS_WIN) EXPECT_NE(msg, reinterpret_cast<IPC::Message*>(NULL)); EXPECT_TRUE(chan.Send(msg)); // Use the current thread as the I/O thread. @@ -208,4 +244,3 @@ TEST_F(SyncSocketTest, SanityTest) { EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000)); base::CloseProcessHandle(server_process); } - |