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