| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/sync_socket.h" | 5 #include "base/sync_socket.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <limits.h> | 9 #include <limits.h> |
| 10 #include <poll.h> |
| 10 #include <stddef.h> | 11 #include <stddef.h> |
| 11 #include <stdio.h> | 12 #include <stdio.h> |
| 12 #include <sys/ioctl.h> | 13 #include <sys/ioctl.h> |
| 13 #include <sys/socket.h> | 14 #include <sys/socket.h> |
| 14 #include <sys/types.h> | 15 #include <sys/types.h> |
| 15 | 16 |
| 16 #if defined(OS_SOLARIS) | 17 #if defined(OS_SOLARIS) |
| 17 #include <sys/filio.h> | 18 #include <sys/filio.h> |
| 18 #endif | 19 #endif |
| 19 | 20 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 } | 136 } |
| 136 | 137 |
| 137 size_t SyncSocket::ReceiveWithTimeout(void* buffer, | 138 size_t SyncSocket::ReceiveWithTimeout(void* buffer, |
| 138 size_t length, | 139 size_t length, |
| 139 TimeDelta timeout) { | 140 TimeDelta timeout) { |
| 140 ThreadRestrictions::AssertIOAllowed(); | 141 ThreadRestrictions::AssertIOAllowed(); |
| 141 DCHECK_GT(length, 0u); | 142 DCHECK_GT(length, 0u); |
| 142 DCHECK_LE(length, kMaxMessageLength); | 143 DCHECK_LE(length, kMaxMessageLength); |
| 143 DCHECK_NE(handle_, kInvalidHandle); | 144 DCHECK_NE(handle_, kInvalidHandle); |
| 144 | 145 |
| 145 // TODO(dalecurtis): There's an undiagnosed issue on OSX where we're seeing | |
| 146 // large numbers of open files which prevents select() from being used. In | |
| 147 // this case, the best we can do is Peek() to see if we can Receive() now or | |
| 148 // return a timeout error (0) if not. See http://crbug.com/314364. | |
| 149 if (handle_ >= FD_SETSIZE) | |
| 150 return Peek() < length ? 0 : Receive(buffer, length); | |
| 151 | |
| 152 // Only timeouts greater than zero and less than one second are allowed. | 146 // Only timeouts greater than zero and less than one second are allowed. |
| 153 DCHECK_GT(timeout.InMicroseconds(), 0); | 147 DCHECK_GT(timeout.InMicroseconds(), 0); |
| 154 DCHECK_LT(timeout.InMicroseconds(), | 148 DCHECK_LT(timeout.InMicroseconds(), |
| 155 base::TimeDelta::FromSeconds(1).InMicroseconds()); | 149 TimeDelta::FromSeconds(1).InMicroseconds()); |
| 156 | 150 |
| 157 // Track the start time so we can reduce the timeout as data is read. | 151 // Track the start time so we can reduce the timeout as data is read. |
| 158 TimeTicks start_time = TimeTicks::Now(); | 152 TimeTicks start_time = TimeTicks::Now(); |
| 159 const TimeTicks finish_time = start_time + timeout; | 153 const TimeTicks finish_time = start_time + timeout; |
| 160 | 154 |
| 161 fd_set read_fds; | 155 struct pollfd pollfd; |
| 162 size_t bytes_read_total; | 156 pollfd.fd = handle_; |
| 163 for (bytes_read_total = 0; | 157 pollfd.events = POLLIN; |
| 164 bytes_read_total < length && timeout.InMicroseconds() > 0; | 158 pollfd.revents = 0; |
| 165 timeout = finish_time - base::TimeTicks::Now()) { | |
| 166 FD_ZERO(&read_fds); | |
| 167 FD_SET(handle_, &read_fds); | |
| 168 | 159 |
| 169 // Wait for data to become available. | 160 size_t bytes_read_total = 0; |
| 170 struct timeval timeout_struct = | 161 while (bytes_read_total < length) { |
| 171 { 0, static_cast<suseconds_t>(timeout.InMicroseconds()) }; | 162 const TimeDelta this_timeout = finish_time - TimeTicks::Now(); |
| 172 const int select_result = | 163 const int timeout_ms = |
| 173 select(handle_ + 1, &read_fds, NULL, NULL, &timeout_struct); | 164 static_cast<int>(this_timeout.InMillisecondsRoundedUp()); |
| 165 if (timeout_ms <= 0) |
| 166 break; |
| 167 const int poll_result = poll(&pollfd, 1, timeout_ms); |
| 174 // Handle EINTR manually since we need to update the timeout value. | 168 // Handle EINTR manually since we need to update the timeout value. |
| 175 if (select_result == -1 && errno == EINTR) | 169 if (poll_result == -1 && errno == EINTR) |
| 176 continue; | 170 continue; |
| 177 if (select_result <= 0) | 171 // Return if other type of error or a timeout. |
| 172 if (poll_result <= 0) |
| 178 return bytes_read_total; | 173 return bytes_read_total; |
| 179 | 174 |
| 180 // select() only tells us that data is ready for reading, not how much. We | 175 // poll() only tells us that data is ready for reading, not how much. We |
| 181 // must Peek() for the amount ready for reading to avoid blocking. | 176 // must Peek() for the amount ready for reading to avoid blocking. |
| 182 DCHECK(FD_ISSET(handle_, &read_fds)); | 177 // At hang up (POLLHUP), the write end has been closed and there might still |
| 178 // be data to be read. |
| 179 // No special handling is needed for error (POLLERR); we can let any of the |
| 180 // following operations fail and handle it there. |
| 181 DCHECK(pollfd.revents & (POLLIN | POLLHUP | POLLERR)) << pollfd.revents; |
| 183 const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total); | 182 const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total); |
| 184 | 183 |
| 185 // There may be zero bytes to read if the socket at the other end closed. | 184 // There may be zero bytes to read if the socket at the other end closed. |
| 186 if (!bytes_to_read) | 185 if (!bytes_to_read) |
| 187 return bytes_read_total; | 186 return bytes_read_total; |
| 188 | 187 |
| 189 const size_t bytes_received = | 188 const size_t bytes_received = |
| 190 Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read); | 189 Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read); |
| 191 bytes_read_total += bytes_received; | 190 bytes_read_total += bytes_received; |
| 192 if (bytes_received != bytes_to_read) | 191 if (bytes_received != bytes_to_read) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 return len; | 244 return len; |
| 246 } | 245 } |
| 247 | 246 |
| 248 // static | 247 // static |
| 249 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, | 248 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, |
| 250 CancelableSyncSocket* socket_b) { | 249 CancelableSyncSocket* socket_b) { |
| 251 return SyncSocket::CreatePair(socket_a, socket_b); | 250 return SyncSocket::CreatePair(socket_a, socket_b); |
| 252 } | 251 } |
| 253 | 252 |
| 254 } // namespace base | 253 } // namespace base |
| OLD | NEW |