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

Side by Side Diff: net/socket/socket_bio_adapter.cc

Issue 2411033003: Drop buffers in idle SSLClientSockets (and SSLServerSockets). (Closed)
Patch Set: typo Created 4 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
OLDNEW
(Empty)
1 // Copyright 2016 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 "net/socket/socket_bio_adapter.h"
6
7 #include <openssl/bio.h>
8 #include <string.h>
9
10 #include <algorithm>
11
12 #include "base/bind.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/socket/stream_socket.h"
19 #include "net/ssl/openssl_ssl_util.h"
20
21 namespace net {
22
23 SocketBIOAdapter::SocketBIOAdapter(StreamSocket* socket,
24 int read_buffer_size,
25 int write_buffer_size,
26 Delegate* delegate)
27 : socket_(socket),
28 read_buffer_size_(read_buffer_size),
29 read_offset_(0),
30 read_result_(0),
31 write_buffer_size_(write_buffer_size),
32 write_buffer_data_size_(0),
33 write_error_(OK),
34 delegate_(delegate),
35 weak_factory_(this) {
36 bio_.reset(BIO_new(&kBIOMethod));
37 bio_->ptr = this;
38 bio_->init = 1;
39
40 read_callback_ = base::Bind(&SocketBIOAdapter::OnSocketReadComplete,
41 weak_factory_.GetWeakPtr());
42 write_callback_ = base::Bind(&SocketBIOAdapter::OnSocketWriteComplete,
43 weak_factory_.GetWeakPtr());
44 }
45
46 SocketBIOAdapter::~SocketBIOAdapter() {
47 // BIOs are reference-counted and may outlive the adapter. Clear the pointer
48 // so future operations fail.
49 bio_->ptr = nullptr;
50 }
51
52 bool SocketBIOAdapter::HasPendingReadData() {
53 return read_result_ > 0;
54 }
55
56 int SocketBIOAdapter::BIORead(char* out, int len) {
57 if (len <= 0)
58 return len;
59
60 // If there is no result available synchronously, report any Write() errors
61 // that were observed. Otherwise the application may have encountered a socket
62 // error while writing that would otherwise not be reported until the
63 // application attempted to write again - which it may never do. See
64 // https://crbug.com/249848.
65 if (write_error_ != OK && write_error_ != ERR_IO_PENDING &&
66 (read_result_ == 0 || read_result_ == ERR_IO_PENDING)) {
67 OpenSSLPutNetError(FROM_HERE, write_error_);
68 return -1;
69 }
70
71 if (read_result_ == 0) {
72 // Instantiate the read buffer and read from the socket. Although only |len|
73 // bytes were received, intentionally read to the full buffer size. The SSL
Ryan Sleevi 2016/10/12 23:30:27 s/received/requested/ ?
davidben 2016/10/13 23:40:13 Done.
74 // layer reads the record header and body in separate reads to avoid
75 // overreading, but issuing one is more efficient. SSL sockets are not
76 // reused after shutdown for non-SSL traffic, so overreading is fine.
77 DCHECK(!read_buffer_);
78 DCHECK_EQ(0, read_offset_);
79 read_buffer_ = new IOBuffer(read_buffer_size_);
80 int result =
81 socket_->Read(read_buffer_.get(), read_buffer_size_, read_callback_);
82 if (result == ERR_IO_PENDING) {
83 read_result_ = ERR_IO_PENDING;
84 } else {
85 HandleSocketReadResult(result);
86 }
87 }
88
89 // There is a pending Read(). Inform the caller to retry when it completes.
90 if (read_result_ == ERR_IO_PENDING) {
91 BIO_set_retry_read(bio());
92 return -1;
93 }
94
95 // If the last Read() failed, report the error.
96 if (read_result_ < 0) {
97 OpenSSLPutNetError(FROM_HERE, read_result_);
98 return -1;
99 }
100
101 // Report the result of the last Read() if non-empty.
102 DCHECK_LT(read_offset_, read_result_);
Ryan Sleevi 2016/10/12 23:30:27 CHECK_LT ?
davidben 2016/10/13 23:40:13 Done.
103 len = std::min(len, read_result_ - read_offset_);
104 memcpy(out, read_buffer_->data() + read_offset_, len);
105 read_offset_ += len;
106
107 // Release the buffer when empty.
108 if (read_offset_ >= read_result_) {
Ryan Sleevi 2016/10/12 23:30:27 Should read_offset_ ever be >? Seems like that wou
davidben 2016/10/13 23:40:13 The (D)CHECK_LT above would impy it can't be. Swit
109 read_buffer_ = nullptr;
110 read_offset_ = 0;
111 read_result_ = 0;
112 }
113
114 return len;
115 }
116
117 void SocketBIOAdapter::HandleSocketReadResult(int result) {
118 DCHECK_NE(ERR_IO_PENDING, result);
119
120 // If an EOF, canonicalize to ERR_CONNECTION_CLOSED here so higher levels
Ryan Sleevi 2016/10/12 23:30:27 s/here so/here, so that/
davidben 2016/10/13 23:40:13 Done.
121 // don't report success.
122 if (result == 0)
123 result = ERR_CONNECTION_CLOSED;
124
125 read_result_ = result;
126
127 // The read buffer is no longer needed.
128 if (read_result_ <= 0)
129 read_buffer_ = nullptr;
130 }
131
132 void SocketBIOAdapter::OnSocketReadComplete(int result) {
133 DCHECK_EQ(ERR_IO_PENDING, read_result_);
134
135 HandleSocketReadResult(result);
136 delegate_->OnReadReady();
137 }
138
139 int SocketBIOAdapter::BIOWrite(const char* in, int len) {
140 if (len <= 0)
141 return len;
142
143 // If the write buffer is not empty, there must be a pending Write() to flush
144 // it.
145 DCHECK(write_buffer_data_size_ == 0 || write_error_ == ERR_IO_PENDING);
146
147 // If a previous Write() failed, report the error.
148 if (write_error_ != OK && write_error_ != ERR_IO_PENDING) {
149 OpenSSLPutNetError(FROM_HERE, write_error_);
150 return -1;
151 }
152
153 // Instantiate the write buffer if needed.
154 if (!write_buffer_) {
155 DCHECK_EQ(0, write_buffer_data_size_);
156 write_buffer_ = new GrowableIOBuffer;
157 write_buffer_->SetCapacity(write_buffer_size_);
158 }
159
160 // If the ring buffer is full, inform the caller to try again later.
161 if (write_buffer_data_size_ == write_buffer_->capacity()) {
162 BIO_set_retry_write(bio());
163 return -1;
164 }
165
166 // Copy data into the ring buffer. First fill the space in front of the
167 // starting offset.
168 int bytes_copied = 0;
169 if (write_buffer_data_size_ < write_buffer_->RemainingCapacity()) {
Ryan Sleevi 2016/10/12 23:30:27 Naming wise, it was hard to tell the distinction b
davidben 2016/10/13 23:40:13 Yeah. I switched it to size => capacity and data_s
170 int todo = std::min(
Ryan Sleevi 2016/10/12 23:30:27 tocopy?
171 len, write_buffer_->RemainingCapacity() - write_buffer_data_size_);
172 memcpy(write_buffer_->data() + write_buffer_data_size_, in, todo);
173 in += todo;
174 len -= todo;
175 write_buffer_data_size_ += todo;
176 bytes_copied += todo;
177 }
178
179 // If there is space and more data, fill the space before the starting offset.
Ryan Sleevi 2016/10/12 23:30:27 What's the difference between "front of the starti
Ryan Sleevi 2016/10/12 23:30:27 What variable represents "starting offset" ?
180 if (len > 0 && write_buffer_data_size_ < write_buffer_->capacity()) {
181 DCHECK_GE(write_buffer_data_size_, write_buffer_->RemainingCapacity());
davidben 2016/10/13 23:40:13 So it turns out all this code was totally wrong an
182 int todo =
183 std::min(len, write_buffer_->capacity() - write_buffer_data_size_);
184 memcpy(write_buffer_->StartOfBuffer(), in, todo);
185 in += todo;
186 len -= todo;
187 write_buffer_data_size_ += todo;
188 bytes_copied += todo;
189 }
190
191 // Schedule a socket Write() if necessary. (The ring buffer may previously
192 // have been empty.)
193 SocketWrite();
194
195 // If a read-interrupting write error was synchronously discovered,
196 // asynchronously notify OnReadReady. See https://crbug.com/249848. Avoid
197 // reentrancy by deferring it to a later event loop iteration.
198 if (write_error_ != OK && write_error_ != ERR_IO_PENDING &&
199 read_result_ == ERR_IO_PENDING) {
200 base::ThreadTaskRunnerHandle::Get()->PostTask(
201 FROM_HERE, base::Bind(&SocketBIOAdapter::CallOnReadReady,
202 weak_factory_.GetWeakPtr()));
203 }
204
205 return bytes_copied;
206 }
207
208 void SocketBIOAdapter::SocketWrite() {
209 while (write_error_ == OK && write_buffer_data_size_ > 0) {
210 int write_size =
211 std::min(write_buffer_data_size_, write_buffer_->RemainingCapacity());
212 int result =
213 socket_->Write(write_buffer_.get(), write_size, write_callback_);
214 if (result == ERR_IO_PENDING) {
215 write_error_ = ERR_IO_PENDING;
216 return;
217 }
218
219 HandleSocketWriteResult(result);
220 }
221 }
222
223 void SocketBIOAdapter::HandleSocketWriteResult(int result) {
224 DCHECK_NE(ERR_IO_PENDING, result);
225
226 if (result < 0) {
227 write_error_ = result;
228
229 // The write buffer is no longer needed.
230 write_buffer_ = nullptr;
231 write_buffer_data_size_ = 0;
232 return;
233 }
234
235 // Advance the ring buffer.
236 write_buffer_->set_offset(write_buffer_->offset() + result);
237 write_buffer_data_size_ -= result;
238 if (write_buffer_->RemainingCapacity() == 0)
239 write_buffer_->set_offset(0);
240 write_error_ = OK;
241
242 // Release the write buffer if empty.
243 if (write_buffer_data_size_ == 0)
244 write_buffer_ = nullptr;
245 }
246
247 void SocketBIOAdapter::OnSocketWriteComplete(int result) {
248 DCHECK_EQ(ERR_IO_PENDING, write_error_);
249
250 bool was_full = write_buffer_data_size_ == write_buffer_->capacity();
251
252 HandleSocketWriteResult(result);
253 SocketWrite();
254
255 // If transitioning from being unable to accept data to being able to, signal
256 // OnWriteReady.
257 if (was_full) {
258 base::WeakPtr<SocketBIOAdapter> guard(weak_factory_.GetWeakPtr());
259 delegate_->OnWriteReady();
260 // OnWriteReady may delete the adapter.
261 if (!guard)
262 return;
263 }
264
265 // Write errors are fed back into BIO_read once the read buffer is empty. If
266 // BIO_read is currently blocked, signal early that a read result is ready.
267 if (result < 0 && read_result_ == ERR_IO_PENDING)
268 delegate_->OnReadReady();
269 }
270
271 void SocketBIOAdapter::CallOnReadReady() {
272 if (read_result_ == ERR_IO_PENDING)
273 delegate_->OnReadReady();
274 }
275
276 SocketBIOAdapter* SocketBIOAdapter::GetAdapter(BIO* bio) {
277 DCHECK_EQ(&kBIOMethod, bio->method);
278 SocketBIOAdapter* adapter = reinterpret_cast<SocketBIOAdapter*>(bio->ptr);
279 if (adapter)
280 DCHECK_EQ(bio, adapter->bio());
281 return adapter;
282 }
283
284 int SocketBIOAdapter::BIOWriteWrapper(BIO* bio, const char* in, int len) {
285 BIO_clear_retry_flags(bio);
286
287 SocketBIOAdapter* adapter = GetAdapter(bio);
288 if (!adapter) {
289 OpenSSLPutNetError(FROM_HERE, ERR_UNEXPECTED);
290 return -1;
291 }
292
293 return adapter->BIOWrite(in, len);
294 }
295
296 int SocketBIOAdapter::BIOReadWrapper(BIO* bio, char* out, int len) {
297 BIO_clear_retry_flags(bio);
298
299 SocketBIOAdapter* adapter = GetAdapter(bio);
300 if (!adapter) {
301 OpenSSLPutNetError(FROM_HERE, ERR_UNEXPECTED);
302 return -1;
303 }
304
305 return adapter->BIORead(out, len);
306 }
307
308 long SocketBIOAdapter::BIOCtrlWrapper(BIO* bio,
309 int cmd,
310 long larg,
311 void* parg) {
312 switch (cmd) {
313 case BIO_CTRL_FLUSH:
314 // The SSL stack requires BIOs handle BIO_flush.
315 return 1;
316 }
317
318 NOTIMPLEMENTED();
319 return 0;
320 }
321
322 const BIO_METHOD SocketBIOAdapter::kBIOMethod = {
323 0, // type (unused)
324 nullptr, // name (unused)
325 SocketBIOAdapter::BIOWriteWrapper,
326 SocketBIOAdapter::BIOReadWrapper,
327 nullptr, // puts
328 nullptr, // gets
329 SocketBIOAdapter::BIOCtrlWrapper,
330 nullptr, // create
331 nullptr, // destroy
332 nullptr, // callback_ctrl
333 };
334
335 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698