summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gyp1
-rw-r--r--base/sync_socket_posix.cc101
-rw-r--r--ipc/ipc.gyp6
-rw-r--r--ipc/sync_socket_unittest.cc49
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);
}
-