• 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 SRC_IPC_UNIX_SOCKET_H_
18 #define SRC_IPC_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/base/scoped_file.h"
28 #include "perfetto/base/weak_ptr.h"
29 #include "perfetto/ipc/basic_types.h"
30 
31 namespace perfetto {
32 
33 namespace base {
34 class TaskRunner;
35 }  // namespace base.
36 
37 namespace ipc {
38 
39 // A non-blocking UNIX domain socket in SOCK_STREAM mode. Allows also to
40 // transfer file descriptors. None of the methods in this class are blocking.
41 // The main design goal is API simplicity and strong guarantees on the
42 // EventListener callbacks, in order to avoid ending in some undefined state.
43 // In case of any error it will aggressively just shut down the socket and
44 // notify the failure with OnConnect(false) or OnDisconnect() depending on the
45 // state of the socket (see below).
46 // EventListener callbacks stop happening as soon as the instance is destroyed.
47 //
48 // Lifecycle of a client socket:
49 //
50 //                           Connect()
51 //                               |
52 //            +------------------+------------------+
53 //            | (success)                           | (failure or Shutdown())
54 //            V                                     V
55 //     OnConnect(true)                         OnConnect(false)
56 //            |
57 //            V
58 //    OnDataAvailable()
59 //            |
60 //            V
61 //     OnDisconnect()  (failure or shutdown)
62 //
63 //
64 // Lifecycle of a server socket:
65 //
66 //                          Listen()  --> returns false in case of errors.
67 //                             |
68 //                             V
69 //              OnNewIncomingConnection(new_socket)
70 //
71 //          (|new_socket| inherits the same EventListener)
72 //                             |
73 //                             V
74 //                     OnDataAvailable()
75 //                             | (failure or Shutdown())
76 //                             V
77 //                       OnDisconnect()
78 class UnixSocket {
79  public:
80   class EventListener {
81    public:
82     virtual ~EventListener();
83 
84     // After Listen().
85     virtual void OnNewIncomingConnection(
86         UnixSocket* self,
87         std::unique_ptr<UnixSocket> new_connection);
88 
89     // After Connect(), whether successful or not.
90     virtual void OnConnect(UnixSocket* self, bool connected);
91 
92     // After a successful Connect() or OnNewIncomingConnection(). Either the
93     // other endpoint did disconnect or some other error happened.
94     virtual void OnDisconnect(UnixSocket* self);
95 
96     // Whenever there is data available to Receive(). Note that spurious FD
97     // watch events are possible, so it is possible that Receive() soon after
98     // OnDataAvailable() returns 0 (just ignore those).
99     virtual void OnDataAvailable(UnixSocket* self);
100   };
101 
102   enum class State {
103     kDisconnected = 0,  // Failed connection, peer disconnection or Shutdown().
104     kConnecting,  // Soon after Connect(), before it either succeeds or fails.
105     kConnected,   // After a successful Connect().
106     kListening    // After Listen(), until Shutdown().
107   };
108 
109   enum class BlockingMode { kNonBlocking, kBlocking };
110 
111   // Creates a Unix domain socket and starts listening. If |socket_name|
112   // starts with a '@', an abstract socket will be created (Linux/Android only).
113   // Returns always an instance. In case of failure (e.g., another socket
114   // with the same name is  already listening) the returned socket will have
115   // is_listening() == false and last_error() will contain the failure reason.
116   static std::unique_ptr<UnixSocket> Listen(const std::string& socket_name,
117                                             EventListener*,
118                                             base::TaskRunner*);
119 
120   // Attaches to a pre-existing socket. The socket must have been created in
121   // SOCK_STREAM mode and the caller must have called bind() on it.
122   static std::unique_ptr<UnixSocket> Listen(base::ScopedFile socket_fd,
123                                             EventListener*,
124                                             base::TaskRunner*);
125 
126   // Creates a Unix domain socket and connects to the listening endpoint.
127   // Returns always an instance. EventListener::OnConnect(bool success) will
128   // be called always, whether the connection succeeded or not.
129   static std::unique_ptr<UnixSocket> Connect(const std::string& socket_name,
130                                              EventListener*,
131                                              base::TaskRunner*);
132 
133   // Creates a Unix domain socket and binds it to |socket_name| (see comment
134   // of Listen() above for the format). This file descriptor is suitable to be
135   // passed to Listen(ScopedFile, ...). Returns the file descriptor, or -1 in
136   // case of failure.
137   static base::ScopedFile CreateAndBind(const std::string& socket_name);
138 
139   // This class gives the hard guarantee that no callback is called on the
140   // passed EventListener immediately after the object has been destroyed.
141   // Any queued callback will be silently dropped.
142   ~UnixSocket();
143 
144   // Shuts down the current connection, if any. If the socket was Listen()-ing,
145   // stops listening. The socket goes back to kNotInitialized state, so it can
146   // be reused with Listen() or Connect().
147   void Shutdown(bool notify);
148 
149   // Returns true is the message was queued, false if there was no space in the
150   // output buffer, in which case the client should retry or give up.
151   // If any other error happens the socket will be shutdown and
152   // EventListener::OnDisconnect() will be called.
153   // If the socket is not connected, Send() will just return false.
154   // Does not append a null string terminator to msg in any case.
155   bool Send(const void* msg,
156             size_t len,
157             int send_fd = -1,
158             BlockingMode blocking = BlockingMode::kNonBlocking);
159   bool Send(const std::string& msg);
160 
161   // Returns the number of bytes (<= |len|) written in |msg| or 0 if there
162   // is no data in the buffer to read or an error occurs (in which case a
163   // EventListener::OnDisconnect() will follow).
164   // If the ScopedFile pointer is not null and a FD is received, it moves the
165   // received FD into that. If a FD is received but the ScopedFile pointer is
166   // null, the FD will be automatically closed.
167   size_t Receive(void* msg, size_t len, base::ScopedFile* = nullptr);
168 
169   // Only for tests. This is slower than Receive() as it requires a heap
170   // allocation and a copy for the std::string. Guarantees that the returned
171   // string is null terminated even if the underlying message sent by the peer
172   // is not.
173   std::string ReceiveString(size_t max_length = 1024);
174 
is_connected()175   bool is_connected() const { return state_ == State::kConnected; }
is_listening()176   bool is_listening() const { return state_ == State::kListening; }
fd()177   int fd() const { return fd_.get(); }
last_error()178   int last_error() const { return last_error_; }
179 
180   // User ID of the peer, as returned by the kernel. If the client disconnects
181   // and the socket goes into the kDisconnected state, it retains the uid of
182   // the last peer.
peer_uid()183   uid_t peer_uid() const {
184     PERFETTO_DCHECK(!is_listening() && peer_uid_ != kInvalidUid);
185     return peer_uid_;
186   }
187 
188  private:
189   UnixSocket(EventListener*, base::TaskRunner*);
190   UnixSocket(EventListener*, base::TaskRunner*, base::ScopedFile, State);
191   UnixSocket(const UnixSocket&) = delete;
192   UnixSocket& operator=(const UnixSocket&) = delete;
193 
194   // Called once by the corresponding public static factory methods.
195   void DoConnect(const std::string& socket_name);
196   void ReadPeerCredentials();
197   void SetBlockingIO(bool is_blocking);
198 
199   void OnEvent();
200   void NotifyConnectionState(bool success);
201 
202   base::ScopedFile fd_;
203   State state_ = State::kDisconnected;
204   int last_error_ = 0;
205   uid_t peer_uid_ = kInvalidUid;
206   EventListener* event_listener_;
207   base::TaskRunner* task_runner_;
208   base::WeakPtrFactory<UnixSocket> weak_ptr_factory_;
209 };
210 
211 }  // namespace ipc
212 }  // namespace perfetto
213 
214 #endif  // SRC_IPC_UNIX_SOCKET_H_
215