xref: /aosp_15_r20/external/cronet/net/base/file_stream_context.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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 // This file defines FileStream::Context class.
6 // The general design of FileStream is as follows: file_stream.h defines
7 // FileStream class which basically is just an "wrapper" not containing any
8 // specific implementation details. It re-routes all its method calls to
9 // the instance of FileStream::Context (FileStream holds a scoped_ptr to
10 // FileStream::Context instance). Context was extracted into a different class
11 // to be able to do and finish all async operations even when FileStream
12 // instance is deleted. So FileStream's destructor can schedule file
13 // closing to be done by Context in WorkerPool (or the TaskRunner passed to
14 // constructor) and then just return (releasing Context pointer from
15 // scoped_ptr) without waiting for actual closing to complete.
16 // Implementation of FileStream::Context is divided in two parts: some methods
17 // and members are platform-independent and some depend on the platform. This
18 // header file contains the complete definition of Context class including all
19 // platform-dependent parts (because of that it has a lot of #if-#else
20 // branching). Implementations of all platform-independent methods are
21 // located in file_stream_context.cc, and all platform-dependent methods are
22 // in file_stream_context_{win,posix}.cc. This separation provides better
23 // readability of Context's code. And we tried to make as much Context code
24 // platform-independent as possible. So file_stream_context_{win,posix}.cc are
25 // much smaller than file_stream_context.cc now.
26 
27 #ifndef NET_BASE_FILE_STREAM_CONTEXT_H_
28 #define NET_BASE_FILE_STREAM_CONTEXT_H_
29 
30 #include <stdint.h>
31 
32 #include "base/files/file.h"
33 #include "base/logging.h"
34 #include "base/memory/weak_ptr.h"
35 #include "base/message_loop/message_pump_for_io.h"
36 #include "base/task/single_thread_task_runner.h"
37 #include "base/task/task_runner.h"
38 #include "build/build_config.h"
39 #include "net/base/completion_once_callback.h"
40 #include "net/base/file_stream.h"
41 
42 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
43 #include <errno.h>
44 #endif
45 
46 namespace base {
47 class FilePath;
48 }
49 
50 namespace net {
51 
52 class IOBuffer;
53 
54 #if BUILDFLAG(IS_WIN)
55 class FileStream::Context : public base::MessagePumpForIO::IOHandler {
56 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
57 class FileStream::Context {
58 #endif
59 
60  public:
61   ////////////////////////////////////////////////////////////////////////////
62   // Platform-dependent methods implemented in
63   // file_stream_context_{win,posix}.cc.
64   ////////////////////////////////////////////////////////////////////////////
65 
66   explicit Context(scoped_refptr<base::TaskRunner> task_runner);
67   Context(base::File file, scoped_refptr<base::TaskRunner> task_runner);
68   Context(const Context&) = delete;
69   Context& operator=(const Context&) = delete;
70 #if BUILDFLAG(IS_WIN)
71   ~Context() override;
72 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
73   ~Context();
74 #endif
75 
76   int Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback);
77 
78   int Write(IOBuffer* buf, int buf_len, CompletionOnceCallback callback);
79 
async_in_progress()80   bool async_in_progress() const { return async_in_progress_; }
81 
82   ////////////////////////////////////////////////////////////////////////////
83   // Platform-independent methods implemented in file_stream_context.cc.
84   ////////////////////////////////////////////////////////////////////////////
85 
86   // Destroys the context. It can be deleted in the method or deletion can be
87   // deferred if some asynchronous operation is now in progress or if file is
88   // not closed yet.
89   void Orphan();
90 
91   void Open(const base::FilePath& path,
92             int open_flags,
93             CompletionOnceCallback callback);
94 
95   void Close(CompletionOnceCallback callback);
96 
97   // Seeks |offset| bytes from the start of the file.
98   void Seek(int64_t offset, Int64CompletionOnceCallback callback);
99 
100   void GetFileInfo(base::File::Info* file_info,
101                    CompletionOnceCallback callback);
102 
103   void Flush(CompletionOnceCallback callback);
104 
105   bool IsOpen() const;
106 
107  private:
108   struct IOResult {
109     IOResult();
110     IOResult(int64_t result, logging::SystemErrorCode os_error);
111     static IOResult FromOSError(logging::SystemErrorCode os_error);
112 
113     int64_t result;
114     logging::SystemErrorCode os_error;  // Set only when result < 0.
115   };
116 
117   struct OpenResult {
118    public:
119     OpenResult();
120     OpenResult(base::File file, IOResult error_code);
121     OpenResult(OpenResult&& other);
122     OpenResult& operator=(OpenResult&& other);
123     OpenResult(const OpenResult&) = delete;
124     OpenResult& operator=(const OpenResult&) = delete;
125 
126     base::File file;
127     IOResult error_code;
128   };
129 
130   ////////////////////////////////////////////////////////////////////////////
131   // Platform-independent methods implemented in file_stream_context.cc.
132   ////////////////////////////////////////////////////////////////////////////
133 
134   OpenResult OpenFileImpl(const base::FilePath& path, int open_flags);
135 
136   IOResult GetFileInfoImpl(base::File::Info* file_info);
137 
138   IOResult CloseFileImpl();
139 
140   IOResult FlushFileImpl();
141 
142   void OnOpenCompleted(CompletionOnceCallback callback, OpenResult open_result);
143 
144   void CloseAndDelete();
145 
146   Int64CompletionOnceCallback IntToInt64(CompletionOnceCallback callback);
147 
148   // Called when Open() or Seek() completes. |result| contains the result or a
149   // network error code.
150   void OnAsyncCompleted(Int64CompletionOnceCallback callback,
151                         const IOResult& result);
152 
153   ////////////////////////////////////////////////////////////////////////////
154   // Platform-dependent methods implemented in
155   // file_stream_context_{win,posix}.cc.
156   ////////////////////////////////////////////////////////////////////////////
157 
158   // Adjusts the position from where the data is read.
159   IOResult SeekFileImpl(int64_t offset);
160 
161   void OnFileOpened();
162 
163 #if BUILDFLAG(IS_WIN)
164   void IOCompletionIsPending(CompletionOnceCallback callback, IOBuffer* buf);
165 
166   // Implementation of MessagePumpForIO::IOHandler.
167   void OnIOCompleted(base::MessagePumpForIO::IOContext* context,
168                      DWORD bytes_read,
169                      DWORD error) override;
170 
171   // Invokes the user callback.
172   void InvokeUserCallback();
173 
174   // Deletes an orphaned context.
175   void DeleteOrphanedContext();
176 
177   // The ReadFile call on Windows can execute synchronously at times.
178   // http://support.microsoft.com/kb/156932. This ends up blocking the calling
179   // thread which is undesirable. To avoid this we execute the ReadFile call
180   // on a worker thread.
181   // The |context| parameter is a pointer to the current Context instance. It
182   // is safe to pass this as is to the pool as the Context instance should
183   // remain valid until the pending Read operation completes.
184   // The |file| parameter is the handle to the file being read.
185   // The |buf| parameter is the buffer where we want the ReadFile to read the
186   // data into.
187   // The |buf_len| parameter contains the number of bytes to be read.
188   // The |overlapped| parameter is a pointer to the OVERLAPPED structure being
189   // used.
190   // The |origin_thread_task_runner| is a task runner instance used to post
191   // tasks back to the originating thread.
192   static void ReadAsync(
193       FileStream::Context* context,
194       HANDLE file,
195       scoped_refptr<IOBuffer> buf,
196       int buf_len,
197       OVERLAPPED* overlapped,
198       scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner);
199 
200   // This callback executes on the main calling thread. It informs the caller
201   // about the result of the ReadFile call.
202   // The |read_file_ret| parameter contains the return value of the ReadFile
203   // call.
204   // The |bytes_read| contains the number of bytes read from the file, if
205   // ReadFile succeeds.
206   // The |os_error| parameter contains the value of the last error returned by
207   // the ReadFile API.
208   void ReadAsyncResult(BOOL read_file_ret, DWORD bytes_read, DWORD os_error);
209 
210 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
211   // ReadFileImpl() is a simple wrapper around read() that handles EINTR
212   // signals and calls RecordAndMapError() to map errno to net error codes.
213   IOResult ReadFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
214 
215   // WriteFileImpl() is a simple wrapper around write() that handles EINTR
216   // signals and calls MapSystemError() to map errno to net error codes.
217   // It tries to write to completion.
218   IOResult WriteFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
219 #endif  // BUILDFLAG(IS_WIN)
220 
221   base::File file_;
222   bool async_in_progress_ = false;
223 
224   bool orphaned_ = false;
225   const scoped_refptr<base::TaskRunner> task_runner_;
226 
227 #if BUILDFLAG(IS_WIN)
228   base::MessagePumpForIO::IOContext io_context_;
229   CompletionOnceCallback callback_;
230   scoped_refptr<IOBuffer> in_flight_buf_;
231   // This flag is set to true when we receive a Read request which is queued to
232   // the thread pool.
233   bool async_read_initiated_ = false;
234   // This flag is set to true when we receive a notification ReadAsyncResult()
235   // on the calling thread which indicates that the asynchronous Read
236   // operation is complete.
237   bool async_read_completed_ = false;
238   // This flag is set to true when we receive an IO completion notification for
239   // an asynchronously initiated Read operation. OnIOComplete().
240   bool io_complete_for_read_received_ = false;
241   // Tracks the result of the IO completion operation. Set in OnIOComplete.
242   int result_ = 0;
243 #endif
244 };
245 
246 }  // namespace net
247 
248 #endif  // NET_BASE_FILE_STREAM_CONTEXT_H_
249