1// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2// 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> 11#include <sys/ioctl.h> 12#include <sys/socket.h> 13 14#include "base/file_util.h" 15#include "base/logging.h" 16 17 18namespace base { 19 20namespace { 21// To avoid users sending negative message lengths to Send/Receive 22// we clamp message lengths, which are size_t, to no more than INT_MAX. 23const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); 24 25static const SyncSocket::Handle kInvalidHandle = -1; 26 27} // namespace 28 29bool SyncSocket::CreatePair(SyncSocket* pair[2]) { 30 Handle handles[2] = { kInvalidHandle, kInvalidHandle }; 31 SyncSocket* tmp_sockets[2] = { NULL, NULL }; 32#if defined(OS_MACOSX) 33 int nosigpipe = 1; 34#endif // defined(OS_MACOSX) 35 36 // Create the two SyncSocket objects first to avoid ugly cleanup issues. 37 tmp_sockets[0] = new SyncSocket(kInvalidHandle); 38 if (tmp_sockets[0] == NULL) { 39 goto cleanup; 40 } 41 tmp_sockets[1] = new SyncSocket(kInvalidHandle); 42 if (tmp_sockets[1] == NULL) { 43 goto cleanup; 44 } 45 if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) { 46 goto cleanup; 47 } 48#if defined(OS_MACOSX) 49 // On OSX an attempt to read or write to a closed socket may generate a 50 // SIGPIPE rather than returning -1. setsockopt will shut this off. 51 if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE, 52 &nosigpipe, sizeof nosigpipe) || 53 0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE, 54 &nosigpipe, sizeof nosigpipe)) { 55 goto cleanup; 56 } 57#endif 58 // Copy the handles out for successful return. 59 tmp_sockets[0]->handle_ = handles[0]; 60 pair[0] = tmp_sockets[0]; 61 tmp_sockets[1]->handle_ = handles[1]; 62 pair[1] = tmp_sockets[1]; 63 return true; 64 65 cleanup: 66 if (handles[0] != kInvalidHandle) { 67 if (HANDLE_EINTR(close(handles[0])) < 0) 68 PLOG(ERROR) << "close"; 69 } 70 if (handles[1] != kInvalidHandle) { 71 if (HANDLE_EINTR(close(handles[1])) < 0) 72 PLOG(ERROR) << "close"; 73 } 74 delete tmp_sockets[0]; 75 delete tmp_sockets[1]; 76 return false; 77} 78 79bool SyncSocket::Close() { 80 if (handle_ == kInvalidHandle) { 81 return false; 82 } 83 int retval = HANDLE_EINTR(close(handle_)); 84 if (retval < 0) 85 PLOG(ERROR) << "close"; 86 handle_ = kInvalidHandle; 87 return (retval == 0); 88} 89 90size_t SyncSocket::Send(const void* buffer, size_t length) { 91 DCHECK(length <= kMaxMessageLength); 92 const char* charbuffer = static_cast<const char*>(buffer); 93 int len = file_util::WriteFileDescriptor(handle_, charbuffer, length); 94 return static_cast<size_t>(len); 95} 96 97size_t SyncSocket::Receive(void* buffer, size_t length) { 98 DCHECK(length <= kMaxMessageLength); 99 char* charbuffer = static_cast<char*>(buffer); 100 if (file_util::ReadFromFD(handle_, charbuffer, length)) { 101 return length; 102 } else { 103 return -1; 104 } 105} 106 107size_t SyncSocket::Peek() { 108 int number_chars; 109 if (-1 == ioctl(handle_, FIONREAD, &number_chars)) { 110 // If there is an error in ioctl, signal that the channel would block. 111 return 0; 112 } 113 return (size_t) number_chars; 114} 115 116} // namespace base 117