blob: f50d20b9f9918e3244b5bca826f36a39170f9f96 [file] [log] [blame]
[email protected]d7a93ad2011-04-22 13:13:071// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]182c44fa2009-11-26 00:28:022// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/sync_socket.h"
6
7#include <errno.h>
8#include <limits.h>
9#include <stdio.h>
10#include <sys/types.h>
[email protected]1e1f1a72009-12-06 19:45:0811#include <sys/ioctl.h>
[email protected]182c44fa2009-11-26 00:28:0212#include <sys/socket.h>
13
[email protected]94f8c952011-06-25 04:54:4114#if defined(OS_SOLARIS)
15#include <sys/filio.h>
16#endif
17
[email protected]182c44fa2009-11-26 00:28:0218#include "base/file_util.h"
19#include "base/logging.h"
20
21
22namespace base {
23
24namespace {
25// To avoid users sending negative message lengths to Send/Receive
26// we clamp message lengths, which are size_t, to no more than INT_MAX.
27const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
28
29static const SyncSocket::Handle kInvalidHandle = -1;
30
31} // namespace
32
33bool SyncSocket::CreatePair(SyncSocket* pair[2]) {
34 Handle handles[2] = { kInvalidHandle, kInvalidHandle };
35 SyncSocket* tmp_sockets[2] = { NULL, NULL };
36#if defined(OS_MACOSX)
37 int nosigpipe = 1;
38#endif // defined(OS_MACOSX)
39
40 // Create the two SyncSocket objects first to avoid ugly cleanup issues.
41 tmp_sockets[0] = new SyncSocket(kInvalidHandle);
42 if (tmp_sockets[0] == NULL) {
43 goto cleanup;
44 }
45 tmp_sockets[1] = new SyncSocket(kInvalidHandle);
46 if (tmp_sockets[1] == NULL) {
47 goto cleanup;
48 }
49 if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
50 goto cleanup;
51 }
52#if defined(OS_MACOSX)
53 // On OSX an attempt to read or write to a closed socket may generate a
54 // SIGPIPE rather than returning -1. setsockopt will shut this off.
55 if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE,
56 &nosigpipe, sizeof nosigpipe) ||
57 0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE,
58 &nosigpipe, sizeof nosigpipe)) {
59 goto cleanup;
60 }
61#endif
62 // Copy the handles out for successful return.
63 tmp_sockets[0]->handle_ = handles[0];
64 pair[0] = tmp_sockets[0];
65 tmp_sockets[1]->handle_ = handles[1];
66 pair[1] = tmp_sockets[1];
67 return true;
68
[email protected]2fdc86a2010-01-26 23:08:0269 cleanup:
[email protected]be60b9a2011-02-23 21:37:4170 if (handles[0] != kInvalidHandle) {
71 if (HANDLE_EINTR(close(handles[0])) < 0)
[email protected]a42d4632011-10-26 21:48:0072 DPLOG(ERROR) << "close";
[email protected]be60b9a2011-02-23 21:37:4173 }
74 if (handles[1] != kInvalidHandle) {
75 if (HANDLE_EINTR(close(handles[1])) < 0)
[email protected]a42d4632011-10-26 21:48:0076 DPLOG(ERROR) << "close";
[email protected]be60b9a2011-02-23 21:37:4177 }
[email protected]182c44fa2009-11-26 00:28:0278 delete tmp_sockets[0];
79 delete tmp_sockets[1];
80 return false;
81}
82
83bool SyncSocket::Close() {
84 if (handle_ == kInvalidHandle) {
85 return false;
86 }
[email protected]be60b9a2011-02-23 21:37:4187 int retval = HANDLE_EINTR(close(handle_));
88 if (retval < 0)
[email protected]a42d4632011-10-26 21:48:0089 DPLOG(ERROR) << "close";
[email protected]182c44fa2009-11-26 00:28:0290 handle_ = kInvalidHandle;
91 return (retval == 0);
92}
93
94size_t SyncSocket::Send(const void* buffer, size_t length) {
[email protected]d7a93ad2011-04-22 13:13:0795 DCHECK_LE(length, kMaxMessageLength);
[email protected]182c44fa2009-11-26 00:28:0296 const char* charbuffer = static_cast<const char*>(buffer);
97 int len = file_util::WriteFileDescriptor(handle_, charbuffer, length);
98 return static_cast<size_t>(len);
99}
100
101size_t SyncSocket::Receive(void* buffer, size_t length) {
[email protected]d7a93ad2011-04-22 13:13:07102 DCHECK_LE(length, kMaxMessageLength);
[email protected]182c44fa2009-11-26 00:28:02103 char* charbuffer = static_cast<char*>(buffer);
104 if (file_util::ReadFromFD(handle_, charbuffer, length)) {
105 return length;
106 } else {
107 return -1;
108 }
109}
110
[email protected]d8b65912009-12-04 22:53:22111size_t SyncSocket::Peek() {
[email protected]1e1f1a72009-12-06 19:45:08112 int number_chars;
113 if (-1 == ioctl(handle_, FIONREAD, &number_chars)) {
114 // If there is an error in ioctl, signal that the channel would block.
115 return 0;
116 }
117 return (size_t) number_chars;
[email protected]d8b65912009-12-04 22:53:22118}
119
[email protected]182c44fa2009-11-26 00:28:02120} // namespace base