xref: /aosp_15_r20/external/cronet/net/socket/socket_bio_adapter.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_SOCKET_SOCKET_BIO_ADAPTER_H_
6 #define NET_SOCKET_SOCKET_BIO_ADAPTER_H_
7 
8 #include "base/memory/raw_ptr.h"
9 #include "base/memory/scoped_refptr.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/sequence_checker.h"
12 #include "net/base/completion_repeating_callback.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/net_export.h"
15 #include "third_party/boringssl/src/include/openssl/base.h"
16 
17 namespace net {
18 
19 class GrowableIOBuffer;
20 class IOBuffer;
21 class StreamSocket;
22 
23 // An adapter to convert between StreamSocket and OpenSSL BIO I/O models.
24 //
25 // BIO exposes a UNIX-like interface where BIO_read and BIO_write may either
26 // succeed synchronously or be retried (with no memory between calls).
27 // StreamSocket exposes an asynchronous interface where an asynchronous
28 // operation continues running and completes with a callback.
29 //
30 // For reading, SocketBIOAdapter maintains a buffer to pass to
31 // StreamSocket::Read. Once that Read completes, BIO_read synchronously drains
32 // the buffer and signals BIO_should_read once empty.
33 //
34 // For writing, SocketBIOAdapter maintains a ring buffer of data to be written
35 // to the StreamSocket. BIO_write synchronously copies data into the buffer or
36 // signals BIO_should_write if the buffer is full. The ring buffer is drained
37 // asynchronously into the socket. Note this means write errors are reported at
38 // a later BIO_write.
39 //
40 // To work around this delay, write errors are also surfaced out of
41 // BIO_read. Otherwise a failure in the final BIO_write of an application may go
42 // unnoticed. If this occurs, OnReadReady will be signaled as if it were a read
43 // error. See https://crbug.com/249848.
44 class NET_EXPORT_PRIVATE SocketBIOAdapter {
45  public:
46   // A delegate interface for when the sockets are ready. BIO assumes external
47   // knowledge of when to retry operations (such as a select() loop for UNIX),
48   // which is signaled out of StreamSocket's callbacks here.
49   //
50   // Callers should implement these methods and, when signaled, retry the
51   // BIO_read or BIO_write. This usually is done by retrying a higher-level
52   // operation, such as SSL_read or SSL_write.
53   //
54   // Callers may assume that OnReadReady and OnWriteReady will only be called
55   // from a PostTask or StreamSocket callback.
56   class Delegate {
57    public:
58     // Called when the BIO is ready to handle BIO_read, after having previously
59     // been blocked.
60     virtual void OnReadReady() = 0;
61 
62     // Called when the BIO is ready to handle BIO_write, after having previously
63     // been blocked.
64     virtual void OnWriteReady() = 0;
65 
66    protected:
67     virtual ~Delegate() = default;
68   };
69 
70   // Creates a new SocketBIOAdapter for the specified socket. |socket| and
71   // |delegate| must remain valid for the lifetime of the SocketBIOAdapter.
72   SocketBIOAdapter(StreamSocket* socket,
73                    int read_buffer_capacity,
74                    int write_buffer_capacity,
75                    Delegate* delegate);
76 
77   SocketBIOAdapter(const SocketBIOAdapter&) = delete;
78   SocketBIOAdapter& operator=(const SocketBIOAdapter&) = delete;
79 
80   ~SocketBIOAdapter();
81 
bio()82   BIO* bio() { return bio_.get(); }
83 
84   // Returns true if any data has been read from the underlying StreamSocket,
85   // but not yet consumed by the BIO.
86   bool HasPendingReadData();
87 
88   // Returns the allocation size estimate in bytes.
89   size_t GetAllocationSize() const;
90 
91  private:
92   int BIORead(char* out, int len);
93   void HandleSocketReadResult(int result);
94   void OnSocketReadComplete(int result);
95   void OnSocketReadIfReadyComplete(int result);
96 
97   int BIOWrite(const char* in, int len);
98   void SocketWrite();
99   void HandleSocketWriteResult(int result);
100   void OnSocketWriteComplete(int result);
101   void CallOnReadReady();
102 
103   static SocketBIOAdapter* GetAdapter(BIO* bio);
104   static int BIOReadWrapper(BIO* bio, char* out, int len);
105   static int BIOWriteWrapper(BIO* bio, const char* in, int len);
106   static long BIOCtrlWrapper(BIO* bio, int cmd, long larg, void* parg);
107 
108   static const BIO_METHOD* BIOMethod();
109 
110   bssl::UniquePtr<BIO> bio_;
111 
112   // The pointer is non-owning so this class may be used with both
113   // ClientSocketHandles and raw StreamSockets.
114   raw_ptr<StreamSocket> socket_;
115 
116   CompletionRepeatingCallback read_callback_;
117   CompletionRepeatingCallback write_callback_;
118 
119   // The capacity of the read buffer.
120   int read_buffer_capacity_;
121   // A buffer containing data from the most recent socket Read(). The buffer is
122   // deallocated when unused.
123   scoped_refptr<IOBuffer> read_buffer_;
124   // The number of bytes of read_buffer_ consumed.
125   int read_offset_ = 0;
126   // The result of the most recent socket Read(). If ERR_IO_PENDING, there is a
127   // socket Read() in progress. If another error, Read() has failed. Otherwise,
128   // it is the number of bytes in the buffer (zero if empty).
129   int read_result_ = 0;
130 
131   // The capacity of the write buffer.
132   int write_buffer_capacity_;
133   // A ring buffer of data to be written to the transport. The offset of the
134   // buffer is the start of the ring buffer and is advanced on successful
135   // Write(). The buffer is deallocated when unused.
136   scoped_refptr<GrowableIOBuffer> write_buffer_;
137   // The number of bytes of data in write_buffer_.
138   int write_buffer_used_ = 0;
139   // The most recent socket Write() error. If ERR_IO_PENDING, there is a socket
140   // Write() in progress. If OK, there is no socket Write() in progress and none
141   // have failed.
142   int write_error_ = OK;
143 
144   raw_ptr<Delegate> delegate_;
145 
146   SEQUENCE_CHECKER(sequence_checker_);
147   base::WeakPtrFactory<SocketBIOAdapter> weak_factory_{this};
148 };
149 
150 }  // namespace net
151 
152 #endif  // NET_SOCKET_SOCKET_BIO_ADAPTER_H_
153