import old mobicore
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos7580.git] / mobicore / daemon / Daemon / Server / NetlinkServer.cpp
CommitLineData
15e8442f
JA
1/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
2 * @{
3 * @file
4 *
5 * Connection server.
6 *
7 * Handles incoming socket connections from clients using the MobiCore driver.
8 */
9/*
10 * Copyright (c) 2013 TRUSTONIC LIMITED
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * 3. Neither the name of the TRUSTONIC LIMITED nor the names of its
24 * contributors may be used to endorse or promote products derived from
25 * this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
34 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
36 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
37 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39#include "public/NetlinkServer.h"
40#include <unistd.h>
41#include <string.h>
42#include <errno.h>
43#include <linux/netlink.h>
44
45#include <stdlib.h>
46#include "NetlinkConnection.h"
47#include <signal.h>
48
49#define LOG_TAG "McDaemon"
50#include "log.h"
51
52//------------------------------------------------------------------------------
53NetlinkServer::NetlinkServer(
54 ConnectionHandler *connectionHandler
55): Server(connectionHandler, "dummy")
56{
57}
58
59
60//------------------------------------------------------------------------------
61void NetlinkServer::run(
62)
63{
64 do {
65 LOG_I("NetlinkServer: Starting to listen on netlink bus");
66
67 // Open a socket
68 serverSock = socket(PF_NETLINK, SOCK_DGRAM, MC_DAEMON_NETLINK);
69 if (serverSock < 0) {
70 LOG_ERRNO("Opening socket");
71 break;
72 }
73
74 // Fill in address structure and bind to socket
75 struct sockaddr_nl src_addr;
76 struct nlmsghdr *nlh = NULL;
77 struct iovec iov;
78 struct msghdr msg;
79 uint32_t len;
80
81 memset(&src_addr, 0, sizeof(src_addr));
82 src_addr.nl_family = AF_NETLINK;
83 src_addr.nl_pid = MC_DAEMON_PID; /* daemon pid */
84 src_addr.nl_groups = 0; /* not in mcast groups */
85 if (::bind(serverSock, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
86 LOG_ERRNO("Binding to server socket failed, because bind");
87 close(serverSock);
88 serverSock = -1;
89 break;
90 }
91
92 // Start reading the socket
93 LOG_I("\n********* successfully initialized *********\n");
94
95 for (;;) {
96 // This buffer will be taken over by the connection it was routed to
97 nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
98 if (nlh == NULL) {
99 LOG_E("Allocation failure");
100 break;
101 }
102 memset(&msg, 0, sizeof(msg));
103 iov.iov_base = (void *)nlh;
104 iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
105 msg.msg_iov = &iov;
106 msg.msg_iovlen = 1;
107 msg.msg_name = &src_addr;
108 msg.msg_namelen = sizeof(src_addr);
109
110 memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
111
112 // Read the incoming message and route it to the connection based
113 // on the incoming PID
114 if ((int) (len = recvmsg(serverSock, &msg, 0)) < 0) {
115 LOG_ERRNO("recvmsg");
116 break;
117 }
118
119 if (NLMSG_OK(nlh, len)) {
120 handleMessage(nlh);
121 } else {
122 break;
123 }
124 }
125 close(serverSock);
126 serverSock = -1;
127 } while (false);
128
129 LOG_W("Could not open netlink socket. KernelAPI disabled");
130}
131
132//------------------------------------------------------------------------------
133void NetlinkServer::handleMessage(
134 struct nlmsghdr *nlh
135)
136{
137 uint32_t seq = nlh->nlmsg_seq;
138 uint32_t pid = nlh->nlmsg_pid;
139 //LOG_I("%s: Handling NQ message for pid %u seq %u...", __FUNCTION__, pid, seq);
140 uint64_t hash = hashConnection(pid, seq);
141 /* First cleanup the connection list */
142 cleanupConnections();
143
144 NetlinkConnection *connection = findConnection(hash);
145 // This is a message from a new client
146 if (connection == NULL) {
147 //LOG_I("%s: Cound't find the connection, creating a new one", __FUNCTION__);
148 connection = new NetlinkConnection(this, serverSock, pid, seq);
149 // Add the new connection
150 insertConnection(hash, connection);
151 }
152
153 connection->handleMessage(nlh);
154
155 // Only handle connections which have not been detached
156 if (connection->detached == false) {
157 if (!connectionHandler->handleConnection(connection)) {
158 LOG_I("%s: No command processed.", __FUNCTION__);
159 connection->socketDescriptor = -1;
160 //Inform the driver
161 connectionHandler->dropConnection(connection);
162
163 // Remove connection from list
164 removeConnection(hash);
165 connection->socketDescriptor = -1;
166 delete connection;
167 }
168 // If connection data is set to NULL then device close has been called
169 // so we must remove all connections associated with this hash
170 else if (connection->connectionData == NULL &&
171 connection->detached == false) {
172 delete connection;
173 }
174 }
175}
176
177
178//------------------------------------------------------------------------------
179void NetlinkServer::detachConnection(
180 Connection *connection
181)
182{
183 connection->detached = true;
184}
185
186
187//------------------------------------------------------------------------------
188NetlinkServer::~NetlinkServer(
189 void
190)
191{
192 connectionMap_t::iterator i;
193 // Shut down the server socket
194 if(serverSock != -1) {
195 close(serverSock);
196 serverSock = -1;
197 }
198
199 // Destroy all client connections
200 for (i = peerConnections.begin(); i != peerConnections.end(); i++) {
201 if (i->second->detached == false) {
202 delete i->second;
203 }
204 }
205 peerConnections.clear();
206}
207
208
209//------------------------------------------------------------------------------
210NetlinkConnection *NetlinkServer::findConnection(
211 uint64_t hash
212)
213{
214 connectionMap_t::iterator i = peerConnections.find(hash);
215 if (i != peerConnections.end()) {
216 return i->second;
217 }
218
219 return NULL;
220}
221
222
223//------------------------------------------------------------------------------
224void NetlinkServer::insertConnection(
225 uint64_t hash,
226 NetlinkConnection *connection
227)
228{
229 peerConnections[hash] = connection;
230}
231
232/* This is called from multiple threads! */
233//------------------------------------------------------------------------------
234void NetlinkServer::removeConnection(
235 uint64_t hash
236)
237{
238 connectionMap_t::iterator i = peerConnections.find(hash);
239 if (i != peerConnections.end()) {
240 peerConnections.erase(i);
241 }
242}
243
244//------------------------------------------------------------------------------
245void NetlinkServer::cleanupConnections(
246 void
247)
248{
249 connectionMap_t::reverse_iterator i;
250 pid_t pid;
251 NetlinkConnection *connection = NULL;
252 // Destroy all client connections
253 for (i = peerConnections.rbegin(); i != peerConnections.rend(); ++i) {
254 connection = i->second;
255 // Only 16 bits are for the actual PID, the rest is session magic
256 pid = connection->peerPid & 0xFFFF;
257 //LOG_I("%s: checking PID %u", __FUNCTION__, pid);
258 // Check if the peer pid is still alive
259 if (pid == 0) {
260 continue;
261 }
262 if (kill(pid, 0)) {
263 bool detached = connection->detached;
264 LOG_I("%s: PID %u has died, cleaning up session 0x%X",
265 __FUNCTION__, pid, connection->peerPid);
266
267 connection->socketDescriptor = -1;
268 //Inform the driver
269 connectionHandler->dropConnection(connection);
270
271 // We aren't handling this connection anymore no matter what
272 removeConnection(connection->hash);
273
274 // Remove connection from list only if detached, the detached
275 // connections are managed by the device
276 if (detached == false) {
277 delete connection;
278 }
279 if (peerConnections.size() == 0) {
280 break;
281 }
282 i = peerConnections.rbegin();
283 }
284 }
285}
286
287/** @} */