• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_EXT_BASE_UNIX_SOCKET_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_UNIX_SOCKET_H_
19 
20 #include <stdint.h>
21 #include <sys/types.h>
22 
23 #include <memory>
24 #include <string>
25 
26 #include "perfetto/base/logging.h"
27 #include "perfetto/ext/base/scoped_file.h"
28 #include "perfetto/ext/base/utils.h"
29 #include "perfetto/ext/base/weak_ptr.h"
30 
31 struct msghdr;
32 
33 namespace perfetto {
34 namespace base {
35 
36 class TaskRunner;
37 
38 // Use arbitrarily high values to avoid that some code accidentally ends up
39 // assuming that these enum values match the sysroot's SOCK_xxx defines rather
40 // than using GetSockType() / GetSockFamily().
41 enum class SockType { kStream = 100, kDgram, kSeqPacket };
42 enum class SockFamily { kUnix = 200, kInet };
43 
44 // UnixSocketRaw is a basic wrapper around UNIX sockets. It exposes wrapper
45 // methods that take care of most common pitfalls (e.g., marking fd as
46 // O_CLOEXEC, avoiding SIGPIPE, properly handling partial writes). It is used as
47 // a building block for the more sophisticated UnixSocket class.
48 class UnixSocketRaw {
49  public:
50   // Creates a new unconnected unix socket.
51   static UnixSocketRaw CreateMayFail(SockFamily family, SockType type);
52 
53   // Crates a pair of connected sockets.
54   static std::pair<UnixSocketRaw, UnixSocketRaw> CreatePair(SockFamily,
55                                                             SockType);
56 
57   // Creates an uninitialized unix socket.
58   UnixSocketRaw();
59 
60   // Creates a unix socket adopting an existing file descriptor. This is
61   // typically used to inherit fds from init via environment variables.
62   UnixSocketRaw(ScopedFile, SockFamily, SockType);
63 
64   ~UnixSocketRaw() = default;
65   UnixSocketRaw(UnixSocketRaw&&) noexcept = default;
66   UnixSocketRaw& operator=(UnixSocketRaw&&) = default;
67 
68   bool Bind(const std::string& socket_name);
69   bool Listen();
70   bool Connect(const std::string& socket_name);
71   bool SetTxTimeout(uint32_t timeout_ms);
72   bool SetRxTimeout(uint32_t timeout_ms);
73   void Shutdown();
74   void SetBlocking(bool);
75   bool IsBlocking() const;
76   void RetainOnExec();
type()77   SockType type() const { return type_; }
family()78   SockFamily family() const { return family_; }
fd()79   int fd() const { return *fd_; }
80   explicit operator bool() const { return !!fd_; }
81 
ReleaseFd()82   ScopedFile ReleaseFd() { return std::move(fd_); }
83 
84   ssize_t Send(const void* msg,
85                size_t len,
86                const int* send_fds = nullptr,
87                size_t num_fds = 0);
88 
89   // Re-enter sendmsg until all the data has been sent or an error occurs.
90   // TODO(fmayer): Figure out how to do timeouts here for heapprofd.
91   ssize_t SendMsgAll(struct msghdr* msg);
92 
93   ssize_t Receive(void* msg,
94                   size_t len,
95                   ScopedFile* fd_vec = nullptr,
96                   size_t max_files = 0);
97 
98   // Exposed for testing only.
99   // Update msghdr so subsequent sendmsg will send data that remains after n
100   // bytes have already been sent.
101   static void ShiftMsgHdr(size_t n, struct msghdr* msg);
102 
103  private:
104   UnixSocketRaw(SockFamily, SockType);
105 
106   UnixSocketRaw(const UnixSocketRaw&) = delete;
107   UnixSocketRaw& operator=(const UnixSocketRaw&) = delete;
108 
109   ScopedFile fd_;
110   SockFamily family_ = SockFamily::kUnix;
111   SockType type_ = SockType::kStream;
112 };
113 
114 // A non-blocking UNIX domain socket. Allows also to transfer file descriptors.
115 // None of the methods in this class are blocking.
116 // The main design goal is making strong guarantees on the EventListener
117 // callbacks, in order to avoid ending in some undefined state.
118 // In case of any error it will aggressively just shut down the socket and
119 // notify the failure with OnConnect(false) or OnDisconnect() depending on the
120 // state of the socket (see below).
121 // EventListener callbacks stop happening as soon as the instance is destroyed.
122 //
123 // Lifecycle of a client socket:
124 //
125 //                           Connect()
126 //                               |
127 //            +------------------+------------------+
128 //            | (success)                           | (failure or Shutdown())
129 //            V                                     V
130 //     OnConnect(true)                         OnConnect(false)
131 //            |
132 //            V
133 //    OnDataAvailable()
134 //            |
135 //            V
136 //     OnDisconnect()  (failure or shutdown)
137 //
138 //
139 // Lifecycle of a server socket:
140 //
141 //                          Listen()  --> returns false in case of errors.
142 //                             |
143 //                             V
144 //              OnNewIncomingConnection(new_socket)
145 //
146 //          (|new_socket| inherits the same EventListener)
147 //                             |
148 //                             V
149 //                     OnDataAvailable()
150 //                             | (failure or Shutdown())
151 //                             V
152 //                       OnDisconnect()
153 class UnixSocket {
154  public:
155   class EventListener {
156    public:
157     virtual ~EventListener();
158 
159     // After Listen().
160     virtual void OnNewIncomingConnection(
161         UnixSocket* self,
162         std::unique_ptr<UnixSocket> new_connection);
163 
164     // After Connect(), whether successful or not.
165     virtual void OnConnect(UnixSocket* self, bool connected);
166 
167     // After a successful Connect() or OnNewIncomingConnection(). Either the
168     // other endpoint did disconnect or some other error happened.
169     virtual void OnDisconnect(UnixSocket* self);
170 
171     // Whenever there is data available to Receive(). Note that spurious FD
172     // watch events are possible, so it is possible that Receive() soon after
173     // OnDataAvailable() returns 0 (just ignore those).
174     virtual void OnDataAvailable(UnixSocket* self);
175   };
176 
177   enum class State {
178     kDisconnected = 0,  // Failed connection, peer disconnection or Shutdown().
179     kConnecting,  // Soon after Connect(), before it either succeeds or fails.
180     kConnected,   // After a successful Connect().
181     kListening    // After Listen(), until Shutdown().
182   };
183 
184   // Creates a socket and starts listening. If SockFamily::kUnix and
185   // |socket_name| starts with a '@', an abstract UNIX dmoain socket will be
186   // created instead of a filesystem-linked UNIX socket (Linux/Android only).
187   // If SockFamily::kInet, |socket_name| is host:port (e.g., "1.2.3.4:8000").
188   // Returns always an instance. In case of failure (e.g., another socket
189   // with the same name is  already listening) the returned socket will have
190   // is_listening() == false and last_error() will contain the failure reason.
191   static std::unique_ptr<UnixSocket> Listen(const std::string& socket_name,
192                                             EventListener*,
193                                             TaskRunner*,
194                                             SockFamily,
195                                             SockType);
196 
197   // Attaches to a pre-existing socket. The socket must have been created in
198   // SOCK_STREAM mode and the caller must have called bind() on it.
199   static std::unique_ptr<UnixSocket> Listen(ScopedFile,
200                                             EventListener*,
201                                             TaskRunner*,
202                                             SockFamily,
203                                             SockType);
204 
205   // Creates a Unix domain socket and connects to the listening endpoint.
206   // Returns always an instance. EventListener::OnConnect(bool success) will
207   // be called always, whether the connection succeeded or not.
208   static std::unique_ptr<UnixSocket> Connect(const std::string& socket_name,
209                                              EventListener*,
210                                              TaskRunner*,
211                                              SockFamily,
212                                              SockType);
213 
214   // Constructs a UnixSocket using the given connected socket.
215   static std::unique_ptr<UnixSocket> AdoptConnected(ScopedFile,
216                                                     EventListener*,
217                                                     TaskRunner*,
218                                                     SockFamily,
219                                                     SockType);
220 
221   UnixSocket(const UnixSocket&) = delete;
222   UnixSocket& operator=(const UnixSocket&) = delete;
223   // Cannot be easily moved because of tasks from the FileDescriptorWatch.
224   UnixSocket(UnixSocket&&) = delete;
225   UnixSocket& operator=(UnixSocket&&) = delete;
226 
227   // This class gives the hard guarantee that no callback is called on the
228   // passed EventListener immediately after the object has been destroyed.
229   // Any queued callback will be silently dropped.
230   ~UnixSocket();
231 
232   // Shuts down the current connection, if any. If the socket was Listen()-ing,
233   // stops listening. The socket goes back to kNotInitialized state, so it can
234   // be reused with Listen() or Connect().
235   void Shutdown(bool notify);
236 
237   // Returns true is the message was queued, false if there was no space in the
238   // output buffer, in which case the client should retry or give up.
239   // If any other error happens the socket will be shutdown and
240   // EventListener::OnDisconnect() will be called.
241   // If the socket is not connected, Send() will just return false.
242   // Does not append a null string terminator to msg in any case.
243   bool Send(const void* msg, size_t len, const int* send_fds, size_t num_fds);
244 
245   inline bool Send(const void* msg, size_t len, int send_fd = -1) {
246     if (send_fd != -1)
247       return Send(msg, len, &send_fd, 1);
248     return Send(msg, len, nullptr, 0);
249   }
250 
Send(const std::string & msg)251   inline bool Send(const std::string& msg) {
252     return Send(msg.c_str(), msg.size() + 1, -1);
253   }
254 
255   // Returns the number of bytes (<= |len|) written in |msg| or 0 if there
256   // is no data in the buffer to read or an error occurs (in which case a
257   // EventListener::OnDisconnect() will follow).
258   // If the ScopedFile pointer is not null and a FD is received, it moves the
259   // received FD into that. If a FD is received but the ScopedFile pointer is
260   // null, the FD will be automatically closed.
261   size_t Receive(void* msg, size_t len, ScopedFile*, size_t max_files = 1);
262 
Receive(void * msg,size_t len)263   inline size_t Receive(void* msg, size_t len) {
264     return Receive(msg, len, nullptr, 0);
265   }
266 
267   // Only for tests. This is slower than Receive() as it requires a heap
268   // allocation and a copy for the std::string. Guarantees that the returned
269   // string is null terminated even if the underlying message sent by the peer
270   // is not.
271   std::string ReceiveString(size_t max_length = 1024);
272 
is_connected()273   bool is_connected() const { return state_ == State::kConnected; }
is_listening()274   bool is_listening() const { return state_ == State::kListening; }
fd()275   int fd() const { return sock_raw_.fd(); }
last_error()276   int last_error() const { return last_error_; }
277 
278   // User ID of the peer, as returned by the kernel. If the client disconnects
279   // and the socket goes into the kDisconnected state, it retains the uid of
280   // the last peer.
peer_uid()281   uid_t peer_uid() const {
282     PERFETTO_DCHECK(!is_listening() && peer_uid_ != kInvalidUid);
283     ignore_result(kInvalidPid);  // Silence warnings in amalgamated builds.
284     return peer_uid_;
285   }
286 
287 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
288     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
289   // Process ID of the peer, as returned by the kernel. If the client
290   // disconnects and the socket goes into the kDisconnected state, it
291   // retains the pid of the last peer.
292   //
293   // This is only available on Linux / Android.
peer_pid()294   pid_t peer_pid() const {
295     PERFETTO_DCHECK(!is_listening() && peer_pid_ != kInvalidPid);
296     return peer_pid_;
297   }
298 #endif
299 
300   // This makes the UnixSocket unusable.
301   UnixSocketRaw ReleaseSocket();
302 
303  private:
304   UnixSocket(EventListener*, TaskRunner*, SockFamily, SockType);
305   UnixSocket(EventListener*,
306              TaskRunner*,
307              ScopedFile,
308              State,
309              SockFamily,
310              SockType);
311 
312   // Called once by the corresponding public static factory methods.
313   void DoConnect(const std::string& socket_name);
314   void ReadPeerCredentials();
315 
316   void OnEvent();
317   void NotifyConnectionState(bool success);
318 
319   UnixSocketRaw sock_raw_;
320   State state_ = State::kDisconnected;
321   int last_error_ = 0;
322   uid_t peer_uid_ = kInvalidUid;
323 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
324     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
325   pid_t peer_pid_ = kInvalidPid;
326 #endif
327   EventListener* const event_listener_;
328   TaskRunner* const task_runner_;
329   WeakPtrFactory<UnixSocket> weak_ptr_factory_;  // Keep last.
330 };
331 
332 }  // namespace base
333 }  // namespace perfetto
334 
335 #endif  // INCLUDE_PERFETTO_EXT_BASE_UNIX_SOCKET_H_
336