1 // Copyright 2020 The Chromium 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
5 #ifndef UI_GFX_X_XPROTO_TYPES_H_
6 #define UI_GFX_X_XPROTO_TYPES_H_
7
8 #include <cstdint>
9 #include <memory>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/component_export.h"
14 #include "base/files/scoped_file.h"
15 #include "base/memory/free_deleter.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/memory/scoped_refptr.h"
18 #include "base/optional.h"
19 #include "ui/gfx/x/error.h"
20
21 namespace x11 {
22
23 class Connection;
24
25 constexpr uint8_t kSendEventMask = 0x80;
26
27 namespace detail {
28
29 template <typename T>
VerifyAlignment(T * t,size_t offset)30 void VerifyAlignment(T* t, size_t offset) {
31 // On the wire, X11 types are always aligned to their size. This is a sanity
32 // check to ensure padding etc are working properly.
33 if (sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8)
34 DCHECK_EQ(offset % sizeof(*t), 0UL);
35 }
36
37 } // namespace detail
38
39 // Wraps data read from the connection.
COMPONENT_EXPORT(X11)40 struct COMPONENT_EXPORT(X11) ReadBuffer {
41 explicit ReadBuffer(scoped_refptr<base::RefCountedMemory> data);
42
43 ReadBuffer(const ReadBuffer&) = delete;
44 ReadBuffer(ReadBuffer&&);
45
46 ~ReadBuffer();
47
48 scoped_refptr<base::RefCountedMemory> ReadAndAdvance(size_t length);
49
50 int TakeFd();
51
52 scoped_refptr<base::RefCountedMemory> data;
53 size_t offset = 0;
54 const int* fds = nullptr;
55 };
56
57 // Wraps data to write to the connection.
COMPONENT_EXPORT(X11)58 class COMPONENT_EXPORT(X11) WriteBuffer {
59 public:
60 WriteBuffer();
61
62 WriteBuffer(const WriteBuffer&) = delete;
63 WriteBuffer(WriteBuffer&&);
64
65 ~WriteBuffer();
66
67 void AppendBuffer(scoped_refptr<base::RefCountedMemory> buffer, size_t size);
68
69 std::vector<scoped_refptr<base::RefCountedMemory>>& GetBuffers();
70
71 size_t offset() const { return offset_; }
72
73 std::vector<int>& fds() { return fds_; }
74
75 template <typename T>
76 void Write(const T* t) {
77 static_assert(std::is_trivially_copyable<T>::value, "");
78 detail::VerifyAlignment(t, offset_);
79 const uint8_t* start = reinterpret_cast<const uint8_t*>(t);
80 std::copy(start, start + sizeof(*t), std::back_inserter(current_buffer_));
81 offset_ += sizeof(*t);
82 }
83
84 private:
85 void AppendCurrentBuffer();
86
87 std::vector<scoped_refptr<base::RefCountedMemory>> buffers_;
88 std::vector<uint8_t> current_buffer_;
89 size_t offset_ = 0;
90 std::vector<int> fds_;
91 };
92
93 namespace detail {
94
95 template <typename Reply>
96 std::unique_ptr<Reply> ReadReply(ReadBuffer* buffer);
97
98 } // namespace detail
99
100 template <class Reply>
101 class Future;
102
103 template <typename T>
104 T Read(ReadBuffer* buf);
105
106 template <typename T>
107 WriteBuffer Write(const T& t);
108
109 template <typename T>
110 void ReadEvent(T* event, ReadBuffer* buf);
111
112 template <typename Reply>
113 struct Response {
114 operator bool() const { return reply.get(); }
115 const Reply* operator->() const { return reply.get(); }
116 Reply* operator->() { return reply.get(); }
117
118 std::unique_ptr<Reply> reply;
119 std::unique_ptr<Error> error;
120
121 private:
122 friend class Future<Reply>;
123
ResponseResponse124 Response(std::unique_ptr<Reply> reply, std::unique_ptr<Error> error)
125 : reply(std::move(reply)), error(std::move(error)) {}
126 };
127
128 template <>
129 struct Response<void> {
130 std::unique_ptr<Error> error;
131
132 private:
133 friend class Future<void>;
134
135 explicit Response(std::unique_ptr<Error> error) : error(std::move(error)) {}
136 };
137
138 class COMPONENT_EXPORT(X11) FutureBase {
139 public:
140 using RawReply = scoped_refptr<base::RefCountedMemory>;
141 using RawError = scoped_refptr<base::RefCountedMemory>;
142 using ResponseCallback =
143 base::OnceCallback<void(RawReply reply, RawError error)>;
144
145 FutureBase(const FutureBase&) = delete;
146 FutureBase& operator=(const FutureBase&) = delete;
147
148 protected:
149 FutureBase(Connection* connection,
150 base::Optional<unsigned int> sequence,
151 const char* request_name);
152 ~FutureBase();
153
154 FutureBase(FutureBase&& future);
155 FutureBase& operator=(FutureBase&& future);
156
157 void SyncImpl(RawError* raw_error, RawReply* raw_reply);
158 void SyncImpl(RawError* raw_error);
159
160 void OnResponseImpl(ResponseCallback callback);
161
162 x11::Connection* connection() { return connection_; }
163
164 static std::unique_ptr<Error> ParseErrorImpl(x11::Connection* connection,
165 RawError raw_error);
166
167 private:
168 void Reset();
169
170 Connection* connection_ = nullptr;
171 base::Optional<unsigned int> sequence_;
172 const char* request_name_ = nullptr;
173 };
174
175 // An x11::Future wraps an asynchronous response from the X11 server. The
176 // response may be waited-for with Sync(), or asynchronously handled by
177 // installing a response handler using OnResponse().
178 template <typename Reply>
179 class Future : public FutureBase {
180 public:
181 using Callback = base::OnceCallback<void(Response<Reply> response)>;
182
183 Future() : FutureBase(nullptr, base::nullopt, nullptr) {}
184
185 // Blocks until we receive the response from the server. Returns the response.
186 Response<Reply> Sync() {
187 RawError raw_error;
188 RawReply raw_reply;
189 SyncImpl(&raw_error, &raw_reply);
190
191 std::unique_ptr<Reply> reply;
192 if (raw_reply) {
193 auto buf = ReadBuffer(raw_reply);
194 reply = detail::ReadReply<Reply>(&buf);
195 }
196
197 std::unique_ptr<Error> error = ParseErrorImpl(connection(), raw_error);
198
199 return {std::move(reply), std::move(error)};
200 }
201
202 // Installs |callback| to be run when the response is received.
203 void OnResponse(Callback callback) {
204 // This intermediate callback handles the conversion from |raw_reply| to a
205 // real Reply object before feeding the result to |callback|. This means
206 // |callback| must be bound as the first argument of the intermediate
207 // function.
208 auto wrapper = [](x11::Connection* connection, Callback callback,
209 RawReply raw_reply, RawError raw_error) {
210 std::unique_ptr<Reply> reply;
211 if (raw_reply) {
212 ReadBuffer buf(raw_reply);
213 reply = detail::ReadReply<Reply>(&buf);
214 }
215 std::unique_ptr<Error> error = ParseErrorImpl(connection, raw_error);
216 std::move(callback).Run({std::move(reply), std::move(error)});
217 };
218 OnResponseImpl(base::BindOnce(wrapper, connection(), std::move(callback)));
219 }
220
221 void IgnoreError() {
222 OnResponse(base::BindOnce([](Response<Reply>) {}));
223 }
224
225 private:
226 template <typename R>
227 friend Future<R> SendRequest(Connection*, WriteBuffer*, bool, const char*);
228
229 Future(Connection* connection,
230 base::Optional<unsigned int> sequence,
231 const char* request_name)
232 : FutureBase(connection, sequence, request_name) {}
233 };
234
235 // Sync() specialization for requests that don't generate replies. The returned
236 // response will only contain an error if there was one.
237 template <>
238 inline Response<void> Future<void>::Sync() {
239 RawError raw_error;
240 SyncImpl(&raw_error);
241 return Response<void>{ParseErrorImpl(connection(), raw_error)};
242 }
243
244 // OnResponse() specialization for requests that don't generate replies. The
245 // response argument to |callback| will only contain an error if there was one.
246 template <>
247 inline void Future<void>::OnResponse(Callback callback) {
248 // See Future<Reply>::OnResponse() for an explanation of why
249 // this wrapper is necessary.
250 auto wrapper = [](x11::Connection* connection, Callback callback,
251 RawReply reply, RawError error) {
252 DCHECK(!reply);
253 std::move(callback).Run(Response<void>{ParseErrorImpl(connection, error)});
254 };
255 OnResponseImpl(base::BindOnce(wrapper, connection(), std::move(callback)));
256 }
257
258 template <>
259 inline void Future<void>::IgnoreError() {
260 OnResponse(base::BindOnce([](Response<void>) {}));
261 }
262
263 } // namespace x11
264
265 #endif // UI_GFX_X_XPROTO_TYPES_H_
266