|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef NET_SOCKET_SOCKET_BIO_ADAPTER_H_ | 
|  | #define NET_SOCKET_SOCKET_BIO_ADAPTER_H_ | 
|  |  | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "net/base/completion_repeating_callback.h" | 
|  | #include "net/base/net_export.h" | 
|  | #include "third_party/boringssl/src/include/openssl/base.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | class GrowableIOBuffer; | 
|  | class IOBuffer; | 
|  | class StreamSocket; | 
|  |  | 
|  | // An adapter to convert between StreamSocket and OpenSSL BIO I/O models. | 
|  | // | 
|  | // BIO exposes a UNIX-like interface where BIO_read and BIO_write may either | 
|  | // succeed synchronously or be retried (with no memory between calls). | 
|  | // StreamSocket exposes an asynchronous interface where an asynchronous | 
|  | // operation continues running and completes with a callback. | 
|  | // | 
|  | // For reading, SocketBIOAdapter maintains a buffer to pass to | 
|  | // StreamSocket::Read. Once that Read completes, BIO_read synchronously drains | 
|  | // the buffer and signals BIO_should_read once empty. | 
|  | // | 
|  | // For writing, SocketBIOAdapter maintains a ring buffer of data to be written | 
|  | // to the StreamSocket. BIO_write synchronously copies data into the buffer or | 
|  | // signals BIO_should_write if the buffer is full. The ring buffer is drained | 
|  | // asynchronously into the socket. Note this means write errors are reported at | 
|  | // a later BIO_write. | 
|  | // | 
|  | // To work around this delay, write errors are also surfaced out of | 
|  | // BIO_read. Otherwise a failure in the final BIO_write of an application may go | 
|  | // unnoticed. If this occurs, OnReadReady will be signaled as if it were a read | 
|  | // error. See https://crbug.com/249848. | 
|  | class NET_EXPORT_PRIVATE SocketBIOAdapter { | 
|  | public: | 
|  | // A delegate interface for when the sockets are ready. BIO assumes external | 
|  | // knowledge of when to retry operations (such as a select() loop for UNIX), | 
|  | // which is signaled out of StreamSocket's callbacks here. | 
|  | // | 
|  | // Callers should implement these methods and, when signaled, retry the | 
|  | // BIO_read or BIO_write. This usually is done by retrying a higher-level | 
|  | // operation, such as SSL_read or SSL_write. | 
|  | // | 
|  | // Callers may assume that OnReadReady and OnWriteReady will only be called | 
|  | // from a PostTask or StreamSocket callback. | 
|  | class Delegate { | 
|  | public: | 
|  | // Called when the BIO is ready to handle BIO_read, after having previously | 
|  | // been blocked. | 
|  | virtual void OnReadReady() = 0; | 
|  |  | 
|  | // Called when the BIO is ready to handle BIO_write, after having previously | 
|  | // been blocked. | 
|  | virtual void OnWriteReady() = 0; | 
|  |  | 
|  | protected: | 
|  | virtual ~Delegate() {} | 
|  | }; | 
|  |  | 
|  | // Creates a new SocketBIOAdapter for the specified socket. |socket| and | 
|  | // |delegate| must remain valid for the lifetime of the SocketBIOAdapter. | 
|  | SocketBIOAdapter(StreamSocket* socket, | 
|  | int read_buffer_capacity, | 
|  | int write_buffer_capacity, | 
|  | Delegate* delegate); | 
|  | ~SocketBIOAdapter(); | 
|  |  | 
|  | BIO* bio() { return bio_.get(); } | 
|  |  | 
|  | // Returns true if any data has been read from the underlying StreamSocket, | 
|  | // but not yet consumed by the BIO. | 
|  | bool HasPendingReadData(); | 
|  |  | 
|  | // Returns the allocation size estimate in bytes. | 
|  | size_t GetAllocationSize() const; | 
|  |  | 
|  | private: | 
|  | int BIORead(char* out, int len); | 
|  | void HandleSocketReadResult(int result); | 
|  | void OnSocketReadComplete(int result); | 
|  | void OnSocketReadIfReadyComplete(int result); | 
|  |  | 
|  | int BIOWrite(const char* in, int len); | 
|  | void SocketWrite(); | 
|  | void HandleSocketWriteResult(int result); | 
|  | void OnSocketWriteComplete(int result); | 
|  | void CallOnReadReady(); | 
|  |  | 
|  | static SocketBIOAdapter* GetAdapter(BIO* bio); | 
|  | static int BIOReadWrapper(BIO* bio, char* out, int len); | 
|  | static int BIOWriteWrapper(BIO* bio, const char* in, int len); | 
|  | static long BIOCtrlWrapper(BIO* bio, int cmd, long larg, void* parg); | 
|  |  | 
|  | static const BIO_METHOD kBIOMethod; | 
|  |  | 
|  | bssl::UniquePtr<BIO> bio_; | 
|  |  | 
|  | // The pointer is non-owning so this class may be used with both | 
|  | // ClientSocketHandles and raw StreamSockets. | 
|  | StreamSocket* socket_; | 
|  |  | 
|  | CompletionRepeatingCallback read_callback_; | 
|  | CompletionRepeatingCallback write_callback_; | 
|  |  | 
|  | // The capacity of the read buffer. | 
|  | int read_buffer_capacity_; | 
|  | // A buffer containing data from the most recent socket Read(). The buffer is | 
|  | // deallocated when unused. | 
|  | scoped_refptr<IOBuffer> read_buffer_; | 
|  | // The number of bytes of read_buffer_ consumed. | 
|  | int read_offset_; | 
|  | // The result of the most recent socket Read(). If ERR_IO_PENDING, there is a | 
|  | // socket Read() in progress. If another error, Read() has failed. Otherwise, | 
|  | // it is the number of bytes in the buffer (zero if empty). | 
|  | int read_result_; | 
|  |  | 
|  | // The capacity of the write buffer. | 
|  | int write_buffer_capacity_; | 
|  | // A ring buffer of data to be written to the transport. The offset of the | 
|  | // buffer is the start of the ring buffer and is advanced on successful | 
|  | // Write(). The buffer is deallocated when unused. | 
|  | scoped_refptr<GrowableIOBuffer> write_buffer_; | 
|  | // The number of bytes of data in write_buffer_. | 
|  | int write_buffer_used_; | 
|  | // The most recent socket Write() error. If ERR_IO_PENDING, there is a socket | 
|  | // Write() in progress. If OK, there is no socket Write() in progress and none | 
|  | // have failed. | 
|  | int write_error_; | 
|  |  | 
|  | Delegate* delegate_; | 
|  |  | 
|  | base::WeakPtrFactory<SocketBIOAdapter> weak_factory_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SocketBIOAdapter); | 
|  | }; | 
|  |  | 
|  | }  // namespace net | 
|  |  | 
|  | #endif  // NET_SOCKET_SOCKET_BIO_ADAPTER_H_ |