blob: f6810d832a33b326e25b65e239ab2b664b61a30e [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
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"
Primiano Tucci3cbb10a2018-04-10 17:52:40 +010029#include "perfetto/ipc/basic_types.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000030
31namespace perfetto {
32
33namespace base {
34class TaskRunner;
35} // namespace base.
36
37namespace 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()
78class 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
Primiano Tucci7a265b62017-12-07 18:37:31 +0000109 enum class BlockingMode { kNonBlocking, kBlocking };
110
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000111 // 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
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100120 // 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
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000126 // 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
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100133 // 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
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000139 // 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().
Florian Mayer48c139c2018-03-12 14:07:57 +0000147 void Shutdown(bool notify);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000148
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.
Primiano Tucci7a265b62017-12-07 18:37:31 +0000155 bool Send(const void* msg,
156 size_t len,
157 int send_fd = -1,
158 BlockingMode blocking = BlockingMode::kNonBlocking);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000159 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
175 bool is_connected() const { return state_ == State::kConnected; }
176 bool is_listening() const { return state_ == State::kListening; }
177 int fd() const { return fd_.get(); }
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.
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100183 uid_t peer_uid() const {
184 PERFETTO_DCHECK(!is_listening() && peer_uid_ != kInvalidUid);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000185 return peer_uid_;
186 }
187
188 private:
189 UnixSocket(EventListener*, base::TaskRunner*);
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100190 UnixSocket(EventListener*, base::TaskRunner*, base::ScopedFile, State);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000191 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);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000196 void ReadPeerCredentials();
Primiano Tucci7a265b62017-12-07 18:37:31 +0000197 void SetBlockingIO(bool is_blocking);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000198
199 void OnEvent();
200 void NotifyConnectionState(bool success);
201
202 base::ScopedFile fd_;
203 State state_ = State::kDisconnected;
204 int last_error_ = 0;
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100205 uid_t peer_uid_ = kInvalidUid;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000206 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_