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 18 namespace base { 19 20 namespace { 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. 23 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); 24 25 static const SyncSocket::Handle kInvalidHandle = -1; 26 27 } // namespace 28 29 bool 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 79 bool 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 90 size_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 97 size_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 107 size_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