1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "DaemonSocket.h"
8 #include "mozilla/ipc/DaemonSocketConsumer.h"
9 #include "mozilla/ipc/DaemonSocketPDU.h"
10 #include "mozilla/UniquePtr.h"
11 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
12
13 #ifdef CHROMIUM_LOG
14 #undef CHROMIUM_LOG
15 #endif
16
17 #if defined(MOZ_WIDGET_GONK)
18 #include <android/log.h>
19 #define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args);
20 #else
21 #include <stdio.h>
22 #define IODEBUG true
23 #define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
24 #endif
25
26 namespace mozilla {
27 namespace ipc {
28
29 //
30 // DaemonSocketIO
31 //
32
33 class DaemonSocketIO final : public ConnectionOrientedSocketIO
34 {
35 public:
36 DaemonSocketIO(MessageLoop* aConsumerLoop,
37 MessageLoop* aIOLoop,
38 int aFd, ConnectionStatus aConnectionStatus,
39 UnixSocketConnector* aConnector,
40 DaemonSocket* aConnection,
41 DaemonSocketIOConsumer* aConsumer);
42
43 ~DaemonSocketIO();
44
45 // Methods for |DataSocketIO|
46 //
47
48 nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer) override;
49 void ConsumeBuffer() override;
50 void DiscardBuffer() override;
51
52 // Methods for |SocketIOBase|
53 //
54
55 SocketBase* GetSocketBase() override;
56
57 bool IsShutdownOnConsumerThread() const override;
58 bool IsShutdownOnIOThread() const override;
59
60 void ShutdownOnConsumerThread() override;
61 void ShutdownOnIOThread() override;
62
63 private:
64 DaemonSocket* mConnection;
65 DaemonSocketIOConsumer* mConsumer;
66 UniquePtr<DaemonSocketPDU> mPDU;
67 bool mShuttingDownOnIOThread;
68 };
69
DaemonSocketIO(MessageLoop * aConsumerLoop,MessageLoop * aIOLoop,int aFd,ConnectionStatus aConnectionStatus,UnixSocketConnector * aConnector,DaemonSocket * aConnection,DaemonSocketIOConsumer * aConsumer)70 DaemonSocketIO::DaemonSocketIO(
71 MessageLoop* aConsumerLoop,
72 MessageLoop* aIOLoop,
73 int aFd,
74 ConnectionStatus aConnectionStatus,
75 UnixSocketConnector* aConnector,
76 DaemonSocket* aConnection,
77 DaemonSocketIOConsumer* aConsumer)
78 : ConnectionOrientedSocketIO(aConsumerLoop,
79 aIOLoop,
80 aFd,
81 aConnectionStatus,
82 aConnector)
83 , mConnection(aConnection)
84 , mConsumer(aConsumer)
85 , mShuttingDownOnIOThread(false)
86 {
87 MOZ_ASSERT(mConnection);
88 MOZ_ASSERT(mConsumer);
89
90 MOZ_COUNT_CTOR_INHERITED(DaemonSocketIO, ConnectionOrientedSocketIO);
91 }
92
~DaemonSocketIO()93 DaemonSocketIO::~DaemonSocketIO()
94 {
95 MOZ_COUNT_DTOR_INHERITED(DaemonSocketIO, ConnectionOrientedSocketIO);
96 }
97
98 // |DataSocketIO|
99
100 nsresult
QueryReceiveBuffer(UnixSocketIOBuffer ** aBuffer)101 DaemonSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
102 {
103 MOZ_ASSERT(aBuffer);
104
105 if (!mPDU) {
106 /* There's only one PDU for receiving. We reuse it every time. */
107 mPDU = MakeUnique<DaemonSocketPDU>(DaemonSocketPDU::PDU_MAX_PAYLOAD_LENGTH);
108 }
109 *aBuffer = mPDU.get();
110
111 return NS_OK;
112 }
113
114 void
ConsumeBuffer()115 DaemonSocketIO::ConsumeBuffer()
116 {
117 MOZ_ASSERT(mConsumer);
118
119 mConsumer->Handle(*mPDU);
120 }
121
122 void
DiscardBuffer()123 DaemonSocketIO::DiscardBuffer()
124 {
125 // Nothing to do.
126 }
127
128 // |SocketIOBase|
129
130 SocketBase*
GetSocketBase()131 DaemonSocketIO::GetSocketBase()
132 {
133 return mConnection;
134 }
135
136 bool
IsShutdownOnConsumerThread() const137 DaemonSocketIO::IsShutdownOnConsumerThread() const
138 {
139 MOZ_ASSERT(IsConsumerThread());
140
141 return mConnection == nullptr;
142 }
143
144 bool
IsShutdownOnIOThread() const145 DaemonSocketIO::IsShutdownOnIOThread() const
146 {
147 return mShuttingDownOnIOThread;
148 }
149
150 void
ShutdownOnConsumerThread()151 DaemonSocketIO::ShutdownOnConsumerThread()
152 {
153 MOZ_ASSERT(IsConsumerThread());
154 MOZ_ASSERT(!IsShutdownOnConsumerThread());
155
156 mConnection = nullptr;
157 }
158
159 void
ShutdownOnIOThread()160 DaemonSocketIO::ShutdownOnIOThread()
161 {
162 MOZ_ASSERT(!IsConsumerThread());
163 MOZ_ASSERT(!mShuttingDownOnIOThread);
164
165 Close(); // will also remove fd from I/O loop
166 mShuttingDownOnIOThread = true;
167 }
168
169 //
170 // DaemonSocket
171 //
172
DaemonSocket(DaemonSocketIOConsumer * aIOConsumer,DaemonSocketConsumer * aConsumer,int aIndex)173 DaemonSocket::DaemonSocket(
174 DaemonSocketIOConsumer* aIOConsumer,
175 DaemonSocketConsumer* aConsumer,
176 int aIndex)
177 : mIO(nullptr)
178 , mIOConsumer(aIOConsumer)
179 , mConsumer(aConsumer)
180 , mIndex(aIndex)
181 {
182 MOZ_ASSERT(mConsumer);
183
184 MOZ_COUNT_CTOR_INHERITED(DaemonSocket, ConnectionOrientedSocket);
185 }
186
~DaemonSocket()187 DaemonSocket::~DaemonSocket()
188 {
189 MOZ_COUNT_DTOR_INHERITED(DaemonSocket, ConnectionOrientedSocket);
190 }
191
192 // |ConnectionOrientedSocket|
193
194 nsresult
PrepareAccept(UnixSocketConnector * aConnector,MessageLoop * aConsumerLoop,MessageLoop * aIOLoop,ConnectionOrientedSocketIO * & aIO)195 DaemonSocket::PrepareAccept(UnixSocketConnector* aConnector,
196 MessageLoop* aConsumerLoop,
197 MessageLoop* aIOLoop,
198 ConnectionOrientedSocketIO*& aIO)
199 {
200 MOZ_ASSERT(!mIO);
201
202 SetConnectionStatus(SOCKET_CONNECTING);
203
204 mIO = new DaemonSocketIO(
205 aConsumerLoop, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
206 aConnector, this, mIOConsumer);
207 aIO = mIO;
208
209 return NS_OK;
210 }
211
212 // |DataSocket|
213
214 void
SendSocketData(UnixSocketIOBuffer * aBuffer)215 DaemonSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
216 {
217 MOZ_ASSERT(mIO);
218 MOZ_ASSERT(mIO->IsConsumerThread());
219
220 mIO->GetIOLoop()->PostTask(
221 MakeAndAddRef<SocketIOSendTask<DaemonSocketIO, UnixSocketIOBuffer>>(
222 mIO, aBuffer));
223 }
224
225 // |SocketBase|
226
227 void
Close()228 DaemonSocket::Close()
229 {
230 if (!mIO) {
231 CHROMIUM_LOG("HAL daemon already disconnected!");
232 return;
233 }
234
235 MOZ_ASSERT(mIO->IsConsumerThread());
236
237 mIO->ShutdownOnConsumerThread();
238 mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
239 mIO = nullptr;
240
241 NotifyDisconnect();
242 }
243
244 void
OnConnectSuccess()245 DaemonSocket::OnConnectSuccess()
246 {
247 mConsumer->OnConnectSuccess(mIndex);
248 }
249
250 void
OnConnectError()251 DaemonSocket::OnConnectError()
252 {
253 mConsumer->OnConnectError(mIndex);
254 }
255
256 void
OnDisconnect()257 DaemonSocket::OnDisconnect()
258 {
259 mConsumer->OnDisconnect(mIndex);
260 }
261
262 }
263 }
264