blob: 60cc8405575edbf57f718a5c81c6243fc01f7e99 [file] [log] [blame]
Kevin Cernekeed05be172017-06-17 17:40:21 -07001// Copyright (c) 2012 The Chromium OS 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
Garrick Evans3388a032020-03-24 11:25:55 +09005#ifndef PATCHPANEL_DNS_IO_BUFFER_H_
6#define PATCHPANEL_DNS_IO_BUFFER_H_
Kevin Cernekeed05be172017-06-17 17:40:21 -07007
8#include <stddef.h>
9
10#include <memory>
11#include <string>
12
Garrick Evans3388a032020-03-24 11:25:55 +090013#include "patchpanel/dns/net_export.h"
Kevin Cernekeed05be172017-06-17 17:40:21 -070014#include "base/memory/free_deleter.h"
15#include "base/memory/ref_counted.h"
16#include "base/pickle.h"
17
18namespace net {
19
20// IOBuffers are reference counted data buffers used for easier asynchronous
21// IO handling.
22//
23// They are often used as the destination buffers for Read() operations, or as
24// the source buffers for Write() operations.
25//
26// IMPORTANT: Never re-use an IOBuffer after cancelling the IO operation that
27// was using it, since this may lead to memory corruption!
28//
29// -----------------------
30// Ownership of IOBuffers:
31// -----------------------
32//
33// Although IOBuffers are RefCountedThreadSafe, they are not intended to be
34// used as a shared buffer, nor should they be used simultaneously across
35// threads. The fact that they are reference counted is an implementation
36// detail for allowing them to outlive cancellation of asynchronous
37// operations.
38//
39// Instead, think of the underlying |char*| buffer contained by the IOBuffer
40// as having exactly one owner at a time.
41//
42// Whenever you call an asynchronous operation that takes an IOBuffer,
43// ownership is implicitly transferred to the called function, until the
44// operation has completed (at which point it transfers back to the caller).
45//
46// ==> The IOBuffer's data should NOT be manipulated, destroyed, or read
47// until the operation has completed.
48//
49// ==> Cancellation does NOT count as completion. If an operation using
50// an IOBuffer is cancelled, the caller should release their
51// reference to this IOBuffer at the time of cancellation since
52// they can no longer use it.
53//
54// For instance, if you were to call a Read() operation on some class which
55// takes an IOBuffer, and then delete that class (which generally will
56// trigger cancellation), the IOBuffer which had been passed to Read() should
57// never be re-used.
58//
59// This usage contract is assumed by any API which takes an IOBuffer, even
60// though it may not be explicitly mentioned in the function's comments.
61//
62// -----------------------
63// Motivation
64// -----------------------
65//
66// The motivation for transferring ownership during cancellation is
67// to make it easier to work with un-cancellable operations.
68//
69// For instance, let's say under the hood your API called out to the
70// operating system's synchronous ReadFile() function on a worker thread.
71// When cancelling through our asynchronous interface, we have no way of
72// actually aborting the in progress ReadFile(). We must let it keep running,
73// and hence the buffer it was reading into must remain alive. Using
74// reference counting we can add a reference to the IOBuffer and make sure
75// it is not destroyed until after the synchronous operation has completed.
76class NET_EXPORT IOBuffer : public base::RefCountedThreadSafe<IOBuffer> {
77 public:
78 IOBuffer();
79
80 // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
81 explicit IOBuffer(int buffer_size);
82 explicit IOBuffer(size_t buffer_size);
83
84 char* data() const { return data_; }
85
86 protected:
87 friend class base::RefCountedThreadSafe<IOBuffer>;
88
89 // Only allow derived classes to specify data_.
90 // In all other cases, we own data_, and must delete it at destruction time.
91 explicit IOBuffer(char* data);
92
93 virtual ~IOBuffer();
94
95 char* data_;
96};
97
98// This version stores the size of the buffer so that the creator of the object
99// doesn't have to keep track of that value.
100// NOTE: This doesn't mean that we want to stop sending the size as an explicit
101// argument to IO functions. Please keep using IOBuffer* for API declarations.
102class NET_EXPORT IOBufferWithSize : public IOBuffer {
103 public:
104 // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
105 explicit IOBufferWithSize(int size);
106 explicit IOBufferWithSize(size_t size);
107
108 int size() const { return size_; }
109
110 protected:
111 // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
112 IOBufferWithSize(char* data, int size);
113
114 // Purpose of this constructor is to give a subclass access to the base class
115 // constructor IOBuffer(char*) thus allowing subclass to use underlying
116 // memory it does not own.
117 IOBufferWithSize(char* data, size_t size);
118 ~IOBufferWithSize() override;
119
120 int size_;
121};
122
123// This is a read only IOBuffer. The data is stored in a string and
124// the IOBuffer interface does not provide a proper way to modify it.
125class NET_EXPORT StringIOBuffer : public IOBuffer {
126 public:
127 explicit StringIOBuffer(const std::string& s);
128 explicit StringIOBuffer(std::unique_ptr<std::string> s);
129
130 int size() const { return static_cast<int>(string_data_.size()); }
131
132 private:
133 ~StringIOBuffer() override;
134
135 std::string string_data_;
136};
137
138// This version wraps an existing IOBuffer and provides convenient functions
139// to progressively read all the data.
140//
141// DrainableIOBuffer is useful when you have an IOBuffer that contains data
142// to be written progressively, and Write() function takes an IOBuffer rather
143// than char*. DrainableIOBuffer can be used as follows:
144//
145// // payload is the IOBuffer containing the data to be written.
146// buf = new DrainableIOBuffer(payload, payload_size);
147//
148// while (buf->BytesRemaining() > 0) {
149// // Write() takes an IOBuffer. If it takes char*, we could
150// // simply use the regular IOBuffer like payload->data() + offset.
151// int bytes_written = Write(buf, buf->BytesRemaining());
152// buf->DidConsume(bytes_written);
153// }
154//
155class NET_EXPORT DrainableIOBuffer : public IOBuffer {
156 public:
157 // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
158 DrainableIOBuffer(IOBuffer* base, int size);
159 DrainableIOBuffer(IOBuffer* base, size_t size);
160
161 // DidConsume() changes the |data_| pointer so that |data_| always points
162 // to the first unconsumed byte.
163 void DidConsume(int bytes);
164
165 // Returns the number of unconsumed bytes.
166 int BytesRemaining() const;
167
168 // Returns the number of consumed bytes.
169 int BytesConsumed() const;
170
171 // Seeks to an arbitrary point in the buffer. The notion of bytes consumed
172 // and remaining are updated appropriately.
173 void SetOffset(int bytes);
174
175 int size() const { return size_; }
176
177 private:
178 ~DrainableIOBuffer() override;
179
180 scoped_refptr<IOBuffer> base_;
181 int size_;
182 int used_;
183};
184
185// This version provides a resizable buffer and a changeable offset.
186//
187// GrowableIOBuffer is useful when you read data progressively without
188// knowing the total size in advance. GrowableIOBuffer can be used as
189// follows:
190//
191// buf = new GrowableIOBuffer;
192// buf->SetCapacity(1024); // Initial capacity.
193//
194// while (!some_stream->IsEOF()) {
195// // Double the capacity if the remaining capacity is empty.
196// if (buf->RemainingCapacity() == 0)
197// buf->SetCapacity(buf->capacity() * 2);
198// int bytes_read = some_stream->Read(buf, buf->RemainingCapacity());
199// buf->set_offset(buf->offset() + bytes_read);
200// }
201//
202class NET_EXPORT GrowableIOBuffer : public IOBuffer {
203 public:
204 GrowableIOBuffer();
205
206 // realloc memory to the specified capacity.
207 void SetCapacity(int capacity);
208 int capacity() { return capacity_; }
209
210 // |offset| moves the |data_| pointer, allowing "seeking" in the data.
211 void set_offset(int offset);
212 int offset() { return offset_; }
213
214 int RemainingCapacity();
215 char* StartOfBuffer();
216
217 private:
218 ~GrowableIOBuffer() override;
219
220 std::unique_ptr<char, base::FreeDeleter> real_data_;
221 int capacity_;
222 int offset_;
223};
224
225// This versions allows a pickle to be used as the storage for a write-style
226// operation, avoiding an extra data copy.
227class NET_EXPORT PickledIOBuffer : public IOBuffer {
228 public:
229 PickledIOBuffer();
230
231 base::Pickle* pickle() { return &pickle_; }
232
233 // Signals that we are done writing to the pickle and we can use it for a
234 // write-style IO operation.
235 void Done();
236
237 private:
238 ~PickledIOBuffer() override;
239
240 base::Pickle pickle_;
241};
242
243// This class allows the creation of a temporary IOBuffer that doesn't really
244// own the underlying buffer. Please use this class only as a last resort.
245// A good example is the buffer for a synchronous operation, where we can be
246// sure that nobody is keeping an extra reference to this object so the lifetime
247// of the buffer can be completely managed by its intended owner.
248class NET_EXPORT WrappedIOBuffer : public IOBuffer {
249 public:
250 explicit WrappedIOBuffer(const char* data);
251
252 protected:
253 ~WrappedIOBuffer() override;
254};
255
256} // namespace net
257
Garrick Evans3388a032020-03-24 11:25:55 +0900258#endif // PATCHPANEL_DNS_IO_BUFFER_H_