blob: 82ad91c9558b07f2d101aaf70368ef0035a7d4e8 [file] [log] [blame]
kushi.p@gmail.come4869772011-04-22 22:13:07 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
sehr@google.comfdc90062009-11-26 09:28:02 +09002// 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>
sehr@google.comb72918f2009-12-07 04:45:08 +090011#include <sys/ioctl.h>
sehr@google.comfdc90062009-11-26 09:28:02 +090012#include <sys/socket.h>
13
chromium@hybridsource.org8f85a6a2011-06-25 13:54:41 +090014#if defined(OS_SOLARIS)
15#include <sys/filio.h>
16#endif
17
sehr@google.comfdc90062009-11-26 09:28:02 +090018#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
erg@google.combf6ce9f2010-01-27 08:08:02 +090069 cleanup:
piman@google.com36c06252011-02-24 06:37:41 +090070 if (handles[0] != kInvalidHandle) {
71 if (HANDLE_EINTR(close(handles[0])) < 0)
72 PLOG(ERROR) << "close";
73 }
74 if (handles[1] != kInvalidHandle) {
75 if (HANDLE_EINTR(close(handles[1])) < 0)
76 PLOG(ERROR) << "close";
77 }
sehr@google.comfdc90062009-11-26 09:28:02 +090078 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 }
piman@google.com36c06252011-02-24 06:37:41 +090087 int retval = HANDLE_EINTR(close(handle_));
88 if (retval < 0)
89 PLOG(ERROR) << "close";
sehr@google.comfdc90062009-11-26 09:28:02 +090090 handle_ = kInvalidHandle;
91 return (retval == 0);
92}
93
94size_t SyncSocket::Send(const void* buffer, size_t length) {
kushi.p@gmail.come4869772011-04-22 22:13:07 +090095 DCHECK_LE(length, kMaxMessageLength);
sehr@google.comfdc90062009-11-26 09:28:02 +090096 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) {
kushi.p@gmail.come4869772011-04-22 22:13:07 +0900102 DCHECK_LE(length, kMaxMessageLength);
sehr@google.comfdc90062009-11-26 09:28:02 +0900103 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
cpu@chromium.org750392c2009-12-05 07:53:22 +0900111size_t SyncSocket::Peek() {
sehr@google.comb72918f2009-12-07 04:45:08 +0900112 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;
cpu@chromium.org750392c2009-12-05 07:53:22 +0900118}
119
sehr@google.comfdc90062009-11-26 09:28:02 +0900120} // namespace base