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