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_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 len = std::min(len, write_buffer_->capacity() - write_buffer_used_); | |
| 167 | |
| 168 int to_copy = len; | |
| 169 while (to_copy > 0) { | |
| 170 // Determine where to write. | |
| 171 int write_offset = write_buffer_->offset() + write_buffer_used_; | |
| 172 if (write_offset >= write_buffer_->capacity()) | |
| 173 write_offset -= write_buffer_->capacity(); | |
|
Ryan Sleevi
2016/10/18 01:30:17
This approach makes me *super* nervous from a secu
davidben
2016/10/18 20:49:11
Every way to write this involves different subtle
| |
| 174 CHECK_LE(0, write_offset); | |
| 175 CHECK_LT(write_offset, write_buffer_->capacity()); | |
| 176 | |
| 177 // Determine how many bytes may be written. | |
| 178 int chunk = (write_offset < write_buffer_->offset()) | |
| 179 ? write_buffer_->offset() - write_offset | |
| 180 : write_buffer_->capacity() - write_offset; | |
| 181 chunk = std::min(chunk, to_copy); | |
| 182 | |
| 183 memcpy(write_buffer_->StartOfBuffer() + write_offset, in, chunk); | |
| 184 in += chunk; | |
| 185 to_copy -= chunk; | |
| 186 write_buffer_used_ += chunk; | |
| 187 } | |
| 188 | |
| 189 // Schedule a socket Write() if necessary. (The ring buffer may previously | |
| 190 // have been empty.) | |
| 191 SocketWrite(); | |
| 192 | |
| 193 // If a read-interrupting write error was synchronously discovered, | |
| 194 // asynchronously notify OnReadReady. See https://crbug.com/249848. Avoid | |
| 195 // reentrancy by deferring it to a later event loop iteration. | |
| 196 if (write_error_ != OK && write_error_ != ERR_IO_PENDING && | |
| 197 read_result_ == ERR_IO_PENDING) { | |
| 198 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 199 FROM_HERE, base::Bind(&SocketBIOAdapter::CallOnReadReady, | |
| 200 weak_factory_.GetWeakPtr())); | |
| 201 } | |
| 202 | |
| 203 return len; | |
| 204 } | |
| 205 | |
| 206 void SocketBIOAdapter::SocketWrite() { | |
| 207 while (write_error_ == OK && write_buffer_used_ > 0) { | |
| 208 int write_size = | |
| 209 std::min(write_buffer_used_, write_buffer_->RemainingCapacity()); | |
| 210 int result = | |
| 211 socket_->Write(write_buffer_.get(), write_size, write_callback_); | |
| 212 if (result == ERR_IO_PENDING) { | |
| 213 write_error_ = ERR_IO_PENDING; | |
| 214 return; | |
| 215 } | |
| 216 | |
| 217 HandleSocketWriteResult(result); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 void SocketBIOAdapter::HandleSocketWriteResult(int result) { | |
| 222 DCHECK_NE(ERR_IO_PENDING, result); | |
| 223 | |
| 224 if (result < 0) { | |
| 225 write_error_ = result; | |
| 226 | |
| 227 // The write buffer is no longer needed. | |
| 228 write_buffer_ = nullptr; | |
| 229 write_buffer_used_ = 0; | |
| 230 return; | |
| 231 } | |
| 232 | |
| 233 // Advance the ring buffer. | |
| 234 write_buffer_->set_offset(write_buffer_->offset() + result); | |
| 235 write_buffer_used_ -= result; | |
| 236 if (write_buffer_->RemainingCapacity() == 0) | |
| 237 write_buffer_->set_offset(0); | |
| 238 write_error_ = OK; | |
| 239 | |
| 240 // Release the write buffer if empty. | |
| 241 if (write_buffer_used_ == 0) | |
| 242 write_buffer_ = nullptr; | |
| 243 } | |
| 244 | |
| 245 void SocketBIOAdapter::OnSocketWriteComplete(int result) { | |
| 246 DCHECK_EQ(ERR_IO_PENDING, write_error_); | |
| 247 | |
| 248 bool was_full = write_buffer_used_ == write_buffer_->capacity(); | |
| 249 | |
| 250 HandleSocketWriteResult(result); | |
| 251 SocketWrite(); | |
| 252 | |
| 253 // If transitioning from being unable to accept data to being able to, signal | |
| 254 // OnWriteReady. | |
| 255 if (was_full) { | |
| 256 base::WeakPtr<SocketBIOAdapter> guard(weak_factory_.GetWeakPtr()); | |
| 257 delegate_->OnWriteReady(); | |
| 258 // OnWriteReady may delete the adapter. | |
| 259 if (!guard) | |
| 260 return; | |
| 261 } | |
| 262 | |
| 263 // Write errors are fed back into BIO_read once the read buffer is empty. If | |
| 264 // BIO_read is currently blocked, signal early that a read result is ready. | |
| 265 if (result < 0 && read_result_ == ERR_IO_PENDING) | |
| 266 delegate_->OnReadReady(); | |
| 267 } | |
| 268 | |
| 269 void SocketBIOAdapter::CallOnReadReady() { | |
| 270 if (read_result_ == ERR_IO_PENDING) | |
| 271 delegate_->OnReadReady(); | |
| 272 } | |
| 273 | |
| 274 SocketBIOAdapter* SocketBIOAdapter::GetAdapter(BIO* bio) { | |
| 275 DCHECK_EQ(&kBIOMethod, bio->method); | |
| 276 SocketBIOAdapter* adapter = reinterpret_cast<SocketBIOAdapter*>(bio->ptr); | |
| 277 if (adapter) | |
| 278 DCHECK_EQ(bio, adapter->bio()); | |
| 279 return adapter; | |
| 280 } | |
| 281 | |
| 282 int SocketBIOAdapter::BIOWriteWrapper(BIO* bio, const char* in, int len) { | |
| 283 BIO_clear_retry_flags(bio); | |
| 284 | |
| 285 SocketBIOAdapter* adapter = GetAdapter(bio); | |
| 286 if (!adapter) { | |
| 287 OpenSSLPutNetError(FROM_HERE, ERR_UNEXPECTED); | |
| 288 return -1; | |
| 289 } | |
| 290 | |
| 291 return adapter->BIOWrite(in, len); | |
| 292 } | |
| 293 | |
| 294 int SocketBIOAdapter::BIOReadWrapper(BIO* bio, char* out, int len) { | |
| 295 BIO_clear_retry_flags(bio); | |
| 296 | |
| 297 SocketBIOAdapter* adapter = GetAdapter(bio); | |
| 298 if (!adapter) { | |
| 299 OpenSSLPutNetError(FROM_HERE, ERR_UNEXPECTED); | |
| 300 return -1; | |
| 301 } | |
| 302 | |
| 303 return adapter->BIORead(out, len); | |
| 304 } | |
| 305 | |
| 306 long SocketBIOAdapter::BIOCtrlWrapper(BIO* bio, | |
| 307 int cmd, | |
| 308 long larg, | |
| 309 void* parg) { | |
| 310 switch (cmd) { | |
| 311 case BIO_CTRL_FLUSH: | |
| 312 // The SSL stack requires BIOs handle BIO_flush. | |
| 313 return 1; | |
| 314 } | |
| 315 | |
| 316 NOTIMPLEMENTED(); | |
| 317 return 0; | |
| 318 } | |
| 319 | |
| 320 const BIO_METHOD SocketBIOAdapter::kBIOMethod = { | |
| 321 0, // type (unused) | |
| 322 nullptr, // name (unused) | |
| 323 SocketBIOAdapter::BIOWriteWrapper, | |
| 324 SocketBIOAdapter::BIOReadWrapper, | |
| 325 nullptr, // puts | |
| 326 nullptr, // gets | |
| 327 SocketBIOAdapter::BIOCtrlWrapper, | |
| 328 nullptr, // create | |
| 329 nullptr, // destroy | |
| 330 nullptr, // callback_ctrl | |
| 331 }; | |
| 332 | |
| 333 } // namespace net | |
| OLD | NEW |