Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: base/sync_socket_posix.cc

Issue 23875019: Add SyncSocket::ReceiveWithTimeout() and SyncSocket unit tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Only read Peek() bytes. Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/sync_socket_nacl.cc ('k') | base/sync_socket_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <limits.h> 8 #include <limits.h>
9 #include <fcntl.h> 9 #include <fcntl.h>
10 #include <stdio.h> 10 #include <stdio.h>
11 #include <sys/ioctl.h> 11 #include <sys/ioctl.h>
12 #include <sys/socket.h> 12 #include <sys/socket.h>
13 #include <sys/types.h> 13 #include <sys/types.h>
14 14
15 #if defined(OS_SOLARIS) 15 #if defined(OS_SOLARIS)
16 #include <sys/filio.h> 16 #include <sys/filio.h>
17 #endif 17 #endif
18 18
19 #include "base/file_util.h" 19 #include "base/file_util.h"
20 #include "base/logging.h" 20 #include "base/logging.h"
21 21
22
23 namespace base { 22 namespace base {
24 23
25 namespace { 24 namespace {
26 // To avoid users sending negative message lengths to Send/Receive 25 // To avoid users sending negative message lengths to Send/Receive
27 // we clamp message lengths, which are size_t, to no more than INT_MAX. 26 // we clamp message lengths, which are size_t, to no more than INT_MAX.
28 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); 27 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
29 28
30 } // namespace 29 } // namespace
31 30
32 const SyncSocket::Handle SyncSocket::kInvalidHandle = -1; 31 const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 return false; 85 return false;
87 } 86 }
88 int retval = HANDLE_EINTR(close(handle_)); 87 int retval = HANDLE_EINTR(close(handle_));
89 if (retval < 0) 88 if (retval < 0)
90 DPLOG(ERROR) << "close"; 89 DPLOG(ERROR) << "close";
91 handle_ = kInvalidHandle; 90 handle_ = kInvalidHandle;
92 return (retval == 0); 91 return (retval == 0);
93 } 92 }
94 93
95 size_t SyncSocket::Send(const void* buffer, size_t length) { 94 size_t SyncSocket::Send(const void* buffer, size_t length) {
95 DCHECK_GT(length, 0u);
96 DCHECK_LE(length, kMaxMessageLength); 96 DCHECK_LE(length, kMaxMessageLength);
97 const char* charbuffer = static_cast<const char*>(buffer); 97 const char* charbuffer = static_cast<const char*>(buffer);
98 int len = file_util::WriteFileDescriptor(handle_, charbuffer, length); 98 int len = file_util::WriteFileDescriptor(handle_, charbuffer, length);
99 99
100 return (len == -1) ? 0 : static_cast<size_t>(len); 100 return (len == -1) ? 0 : static_cast<size_t>(len);
101 } 101 }
102 102
103 size_t SyncSocket::Receive(void* buffer, size_t length) { 103 size_t SyncSocket::Receive(void* buffer, size_t length) {
104 DCHECK_GT(length, 0u);
104 DCHECK_LE(length, kMaxMessageLength); 105 DCHECK_LE(length, kMaxMessageLength);
105 char* charbuffer = static_cast<char*>(buffer); 106 char* charbuffer = static_cast<char*>(buffer);
106 if (file_util::ReadFromFD(handle_, charbuffer, length)) 107 if (file_util::ReadFromFD(handle_, charbuffer, length))
107 return length; 108 return length;
108 return 0; 109 return 0;
109 } 110 }
110 111
112 size_t SyncSocket::ReceiveWithTimeout(void* buffer,
113 size_t length,
114 TimeDelta timeout) {
115 DCHECK_GT(length, 0u);
116 DCHECK_LE(length, kMaxMessageLength);
117
118 // Only timeouts greater than zero and less than one second are allowed.
119 DCHECK_GT(timeout.InMicroseconds(), 0);
120 DCHECK(timeout.InMicroseconds() < Time::kMicrosecondsPerSecond);
121
122 // Track the start time so we can reduce the timeout as data is read.
123 TimeTicks start_time = base::TimeTicks::Now();
DaleCurtis 2013/09/25 22:48:25 Is this worth doing? TimeTicks::Now() has a resolu
124
125 fd_set rfds;
126 size_t bytes_remaining = length;
127 do {
128 FD_ZERO(&rfds);
129 FD_SET(handle_, &rfds);
130
131 // Wait for data to become available.
132 struct timeval timeout_struct = { 0, timeout.InMicroseconds() };
133 const int select_result = HANDLE_EINTR(
134 select(handle_ + 1, &rfds, NULL, NULL, &timeout_struct));
135 if (select_result <= 0)
136 return length - bytes_remaining;
137
138 // select() only tells us that data is ready for reading, not how much. We
139 // must Peek() for the amount ready for reading to avoid blocking.
140 DCHECK(FD_ISSET(handle_, &rfds));
141 const size_t bytes_to_read = std::min(Peek(), length);
142 const size_t bytes_received = Receive(buffer, bytes_to_read);
143 if (bytes_received != bytes_to_read)
144 return length - bytes_remaining;
145
146 // Since TimeTicks::Now() is expensive, only bother updating the tracking
147 // variables if we have more work to do.
148 if (bytes_remaining -= bytes_received) {
149 buffer = static_cast<uint8_t*>(buffer) + bytes_received;
150 timeout -= base::TimeTicks::Now() - start_time;
151 }
152 } while (bytes_remaining > 0 && timeout > base::TimeDelta());
153 return length;
154 }
155
111 size_t SyncSocket::Peek() { 156 size_t SyncSocket::Peek() {
112 int number_chars; 157 int number_chars;
113 if (-1 == ioctl(handle_, FIONREAD, &number_chars)) { 158 if (-1 == ioctl(handle_, FIONREAD, &number_chars)) {
114 // If there is an error in ioctl, signal that the channel would block. 159 // If there is an error in ioctl, signal that the channel would block.
115 return 0; 160 return 0;
116 } 161 }
117 return (size_t) number_chars; 162 DCHECK_GE(number_chars, 0);
163 return number_chars;
118 } 164 }
119 165
120 CancelableSyncSocket::CancelableSyncSocket() {} 166 CancelableSyncSocket::CancelableSyncSocket() {}
121 CancelableSyncSocket::CancelableSyncSocket(Handle handle) 167 CancelableSyncSocket::CancelableSyncSocket(Handle handle)
122 : SyncSocket(handle) { 168 : SyncSocket(handle) {
123 } 169 }
124 170
125 bool CancelableSyncSocket::Shutdown() { 171 bool CancelableSyncSocket::Shutdown() {
126 return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0; 172 return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0;
127 } 173 }
128 174
129 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { 175 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
130 long flags = 0; 176 long flags = 0;
DaleCurtis 2013/09/25 22:48:25 While coding I began to wonder if this is necessar
tommi (sloooow) - chröme 2013/09/29 09:15:54 you mean set the socket to non-blocking inside Cre
DaleCurtis 2013/09/30 18:00:51 Not that I know of or can find. After this lands
131 flags = fcntl(handle_, F_GETFL, NULL); 177 flags = fcntl(handle_, F_GETFL, NULL);
132 if (flags != -1 && (flags & O_NONBLOCK) == 0) { 178 if (flags != -1 && (flags & O_NONBLOCK) == 0) {
133 // Set the socket to non-blocking mode for sending if its original mode 179 // Set the socket to non-blocking mode for sending if its original mode
134 // is blocking. 180 // is blocking.
135 fcntl(handle_, F_SETFL, flags | O_NONBLOCK); 181 fcntl(handle_, F_SETFL, flags | O_NONBLOCK);
136 } 182 }
137 183
138 size_t len = SyncSocket::Send(buffer, length); 184 size_t len = SyncSocket::Send(buffer, length);
139 185
140 if (flags != -1 && (flags & O_NONBLOCK) == 0) { 186 if (flags != -1 && (flags & O_NONBLOCK) == 0) {
141 // Restore the original flags. 187 // Restore the original flags.
142 fcntl(handle_, F_SETFL, flags); 188 fcntl(handle_, F_SETFL, flags);
143 } 189 }
144 190
145 return len; 191 return len;
146 } 192 }
147 193
148 // static 194 // static
149 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, 195 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
150 CancelableSyncSocket* socket_b) { 196 CancelableSyncSocket* socket_b) {
151 return SyncSocket::CreatePair(socket_a, socket_b); 197 return SyncSocket::CreatePair(socket_a, socket_b);
152 } 198 }
153 199
154 } // namespace base 200 } // namespace base
OLDNEW
« no previous file with comments | « base/sync_socket_nacl.cc ('k') | base/sync_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698