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