Chromium Code Reviews| Index: base/sync_socket_posix.cc |
| diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc |
| index 257916df3357a21962a4f6b9fe7561a09c286d50..fa72624df90f0890db608c61ed36ef7845ec3228 100644 |
| --- a/base/sync_socket_posix.cc |
| +++ b/base/sync_socket_posix.cc |
| @@ -19,7 +19,6 @@ |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| - |
| namespace base { |
| namespace { |
| @@ -93,6 +92,7 @@ bool SyncSocket::Close() { |
| } |
| size_t SyncSocket::Send(const void* buffer, size_t length) { |
| + DCHECK_GT(length, 0u); |
| DCHECK_LE(length, kMaxMessageLength); |
| const char* charbuffer = static_cast<const char*>(buffer); |
| int len = file_util::WriteFileDescriptor(handle_, charbuffer, length); |
| @@ -101,6 +101,7 @@ size_t SyncSocket::Send(const void* buffer, size_t length) { |
| } |
| size_t SyncSocket::Receive(void* buffer, size_t length) { |
| + DCHECK_GT(length, 0u); |
| DCHECK_LE(length, kMaxMessageLength); |
| char* charbuffer = static_cast<char*>(buffer); |
| if (file_util::ReadFromFD(handle_, charbuffer, length)) |
| @@ -108,13 +109,58 @@ size_t SyncSocket::Receive(void* buffer, size_t length) { |
| return 0; |
| } |
| +size_t SyncSocket::ReceiveWithTimeout(void* buffer, |
| + size_t length, |
| + TimeDelta timeout) { |
| + DCHECK_GT(length, 0u); |
| + DCHECK_LE(length, kMaxMessageLength); |
| + |
| + // Only timeouts greater than zero and less than one second are allowed. |
| + DCHECK_GT(timeout.InMicroseconds(), 0); |
| + DCHECK(timeout.InMicroseconds() < Time::kMicrosecondsPerSecond); |
| + |
| + // Track the start time so we can reduce the timeout as data is read. |
| + TimeTicks start_time = base::TimeTicks::Now(); |
|
DaleCurtis
2013/09/25 22:48:25
Is this worth doing? TimeTicks::Now() has a resolu
|
| + |
| + fd_set rfds; |
| + size_t bytes_remaining = length; |
| + do { |
| + FD_ZERO(&rfds); |
| + FD_SET(handle_, &rfds); |
| + |
| + // Wait for data to become available. |
| + struct timeval timeout_struct = { 0, timeout.InMicroseconds() }; |
| + const int select_result = HANDLE_EINTR( |
| + select(handle_ + 1, &rfds, NULL, NULL, &timeout_struct)); |
| + if (select_result <= 0) |
| + return length - bytes_remaining; |
| + |
| + // select() only tells us that data is ready for reading, not how much. We |
| + // must Peek() for the amount ready for reading to avoid blocking. |
| + DCHECK(FD_ISSET(handle_, &rfds)); |
| + const size_t bytes_to_read = std::min(Peek(), length); |
| + const size_t bytes_received = Receive(buffer, bytes_to_read); |
| + if (bytes_received != bytes_to_read) |
| + return length - bytes_remaining; |
| + |
| + // Since TimeTicks::Now() is expensive, only bother updating the tracking |
| + // variables if we have more work to do. |
| + if (bytes_remaining -= bytes_received) { |
| + buffer = static_cast<uint8_t*>(buffer) + bytes_received; |
| + timeout -= base::TimeTicks::Now() - start_time; |
| + } |
| + } while (bytes_remaining > 0 && timeout > base::TimeDelta()); |
| + return length; |
| +} |
| + |
| size_t SyncSocket::Peek() { |
| int number_chars; |
| if (-1 == ioctl(handle_, FIONREAD, &number_chars)) { |
| // If there is an error in ioctl, signal that the channel would block. |
| return 0; |
| } |
| - return (size_t) number_chars; |
| + DCHECK_GE(number_chars, 0); |
| + return number_chars; |
| } |
| CancelableSyncSocket::CancelableSyncSocket() {} |