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

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

Issue 2411033003: Drop buffers in idle SSLClientSockets (and SSLServerSockets). (Closed)
Patch Set: rsleevi comments 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
« no previous file with comments | « net/socket/socket_bio_adapter.h ('k') | net/socket/socket_bio_adapter_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
(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_capacity,
25 int write_buffer_capacity,
26 Delegate* delegate)
27 : socket_(socket),
28 read_buffer_capacity_(read_buffer_capacity),
29 read_offset_(0),
30 read_result_(0),
31 write_buffer_capacity_(write_buffer_capacity),
32 write_buffer_used_(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 requested, intentionally read to the full buffer size. The SSL
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_capacity_);
80 int result = socket_->Read(read_buffer_.get(), read_buffer_capacity_,
81 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 CHECK_LT(read_offset_, read_result_);
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_) {
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 that higher
121 // levels 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_used_ == 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_used_);
156 write_buffer_ = new GrowableIOBuffer;
157 write_buffer_->SetCapacity(write_buffer_capacity_);
158 }
159
160 // If the ring buffer is full, inform the caller to try again later.
161 if (write_buffer_used_ == write_buffer_->capacity()) {
162 BIO_set_retry_write(bio());
163 return -1;
164 }
165
166 int bytes_copied = 0;
167
168 // If there is space after the offset, fill it.
169 if (write_buffer_used_ < write_buffer_->RemainingCapacity()) {
170 int chunk =
171 std::min(write_buffer_->RemainingCapacity() - write_buffer_used_, len);
172 memcpy(write_buffer_->data() + write_buffer_used_, in, chunk);
173 in += chunk;
174 len -= chunk;
175 bytes_copied += chunk;
176 write_buffer_used_ += chunk;
177 }
178
179 // If there is still space for remaining data, try to wrap around.
180 if (len > 0 && write_buffer_used_ < write_buffer_->capacity()) {
181 // If there were any room after the offset, the previous branch would have
182 // filled it.
183 CHECK_LE(write_buffer_->RemainingCapacity(), write_buffer_used_);
184 int write_offset = write_buffer_used_ - write_buffer_->RemainingCapacity();
185 int chunk = std::min(len, write_buffer_->capacity() - write_buffer_used_);
186 memcpy(write_buffer_->StartOfBuffer() + write_offset, in, chunk);
187 in += chunk;
188 len -= chunk;
189 bytes_copied += chunk;
190 write_buffer_used_ += chunk;
191 }
192
193 // Either the buffer is now full or there is no more input.
194 DCHECK(len == 0 || write_buffer_used_ == write_buffer_->capacity());
195
196 // Schedule a socket Write() if necessary. (The ring buffer may previously
197 // have been empty.)
198 SocketWrite();
199
200 // If a read-interrupting write error was synchronously discovered,
201 // asynchronously notify OnReadReady. See https://crbug.com/249848. Avoid
202 // reentrancy by deferring it to a later event loop iteration.
203 if (write_error_ != OK && write_error_ != ERR_IO_PENDING &&
204 read_result_ == ERR_IO_PENDING) {
205 base::ThreadTaskRunnerHandle::Get()->PostTask(
206 FROM_HERE, base::Bind(&SocketBIOAdapter::CallOnReadReady,
207 weak_factory_.GetWeakPtr()));
208 }
209
210 return bytes_copied;
211 }
212
213 void SocketBIOAdapter::SocketWrite() {
214 while (write_error_ == OK && write_buffer_used_ > 0) {
215 int write_size =
216 std::min(write_buffer_used_, write_buffer_->RemainingCapacity());
217 int result =
218 socket_->Write(write_buffer_.get(), write_size, write_callback_);
219 if (result == ERR_IO_PENDING) {
220 write_error_ = ERR_IO_PENDING;
221 return;
222 }
223
224 HandleSocketWriteResult(result);
225 }
226 }
227
228 void SocketBIOAdapter::HandleSocketWriteResult(int result) {
229 DCHECK_NE(ERR_IO_PENDING, result);
230
231 if (result < 0) {
232 write_error_ = result;
233
234 // The write buffer is no longer needed.
235 write_buffer_ = nullptr;
236 write_buffer_used_ = 0;
237 return;
238 }
239
240 // Advance the ring buffer.
241 write_buffer_->set_offset(write_buffer_->offset() + result);
242 write_buffer_used_ -= result;
243 if (write_buffer_->RemainingCapacity() == 0)
244 write_buffer_->set_offset(0);
245 write_error_ = OK;
246
247 // Release the write buffer if empty.
248 if (write_buffer_used_ == 0)
249 write_buffer_ = nullptr;
250 }
251
252 void SocketBIOAdapter::OnSocketWriteComplete(int result) {
253 DCHECK_EQ(ERR_IO_PENDING, write_error_);
254
255 bool was_full = write_buffer_used_ == write_buffer_->capacity();
256
257 HandleSocketWriteResult(result);
258 SocketWrite();
259
260 // If transitioning from being unable to accept data to being able to, signal
261 // OnWriteReady.
262 if (was_full) {
263 base::WeakPtr<SocketBIOAdapter> guard(weak_factory_.GetWeakPtr());
264 delegate_->OnWriteReady();
265 // OnWriteReady may delete the adapter.
266 if (!guard)
267 return;
268 }
269
270 // Write errors are fed back into BIO_read once the read buffer is empty. If
271 // BIO_read is currently blocked, signal early that a read result is ready.
272 if (result < 0 && read_result_ == ERR_IO_PENDING)
273 delegate_->OnReadReady();
274 }
275
276 void SocketBIOAdapter::CallOnReadReady() {
277 if (read_result_ == ERR_IO_PENDING)
278 delegate_->OnReadReady();
279 }
280
281 SocketBIOAdapter* SocketBIOAdapter::GetAdapter(BIO* bio) {
282 DCHECK_EQ(&kBIOMethod, bio->method);
283 SocketBIOAdapter* adapter = reinterpret_cast<SocketBIOAdapter*>(bio->ptr);
284 if (adapter)
285 DCHECK_EQ(bio, adapter->bio());
286 return adapter;
287 }
288
289 int SocketBIOAdapter::BIOWriteWrapper(BIO* bio, const char* in, int len) {
290 BIO_clear_retry_flags(bio);
291
292 SocketBIOAdapter* adapter = GetAdapter(bio);
293 if (!adapter) {
294 OpenSSLPutNetError(FROM_HERE, ERR_UNEXPECTED);
295 return -1;
296 }
297
298 return adapter->BIOWrite(in, len);
299 }
300
301 int SocketBIOAdapter::BIOReadWrapper(BIO* bio, char* out, int len) {
302 BIO_clear_retry_flags(bio);
303
304 SocketBIOAdapter* adapter = GetAdapter(bio);
305 if (!adapter) {
306 OpenSSLPutNetError(FROM_HERE, ERR_UNEXPECTED);
307 return -1;
308 }
309
310 return adapter->BIORead(out, len);
311 }
312
313 long SocketBIOAdapter::BIOCtrlWrapper(BIO* bio,
314 int cmd,
315 long larg,
316 void* parg) {
317 switch (cmd) {
318 case BIO_CTRL_FLUSH:
319 // The SSL stack requires BIOs handle BIO_flush.
320 return 1;
321 }
322
323 NOTIMPLEMENTED();
324 return 0;
325 }
326
327 const BIO_METHOD SocketBIOAdapter::kBIOMethod = {
328 0, // type (unused)
329 nullptr, // name (unused)
330 SocketBIOAdapter::BIOWriteWrapper,
331 SocketBIOAdapter::BIOReadWrapper,
332 nullptr, // puts
333 nullptr, // gets
334 SocketBIOAdapter::BIOCtrlWrapper,
335 nullptr, // create
336 nullptr, // destroy
337 nullptr, // callback_ctrl
338 };
339
340 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/socket_bio_adapter.h ('k') | net/socket/socket_bio_adapter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698