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