Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |