1 /** @addtogroup MCD_MCDIMPL_DAEMON_SRV
7 * Handles incoming socket connections from clients using the MobiCore driver.
9 * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
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.
35 #include "public/NetlinkServer.h"
39 #include <linux/netlink.h>
42 #include "NetlinkConnection.h"
45 #define LOG_TAG "McDaemon"
48 //------------------------------------------------------------------------------
49 NetlinkServer::NetlinkServer(
50 ConnectionHandler
*connectionHandler
51 ): Server(connectionHandler
, "dummy")
56 //------------------------------------------------------------------------------
57 void NetlinkServer::run(
61 LOG_I("NetlinkServer: Starting to listen on netlink bus");
64 serverSock
= socket(PF_NETLINK
, SOCK_DGRAM
, MC_DAEMON_NETLINK
);
66 LOG_ERRNO("Opening socket");
70 // Fill in address structure and bind to socket
71 struct sockaddr_nl src_addr
;
72 struct nlmsghdr
*nlh
= NULL
;
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");
87 // Start reading the socket
88 LOG_I("\n********* successfully initialized *********\n");
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
);
98 msg
.msg_name
= &src_addr
;
99 msg
.msg_namelen
= sizeof(src_addr
);
101 memset(nlh
, 0, NLMSG_SPACE(MAX_PAYLOAD
));
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");
110 if (NLMSG_OK(nlh
, len
)) {
118 LOG_ERRNO("Exiting NetlinkServer! Because it");
121 //------------------------------------------------------------------------------
122 void NetlinkServer::handleMessage(
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();
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
);
142 connection
->handleMessage(nlh
);
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;
150 connectionHandler
->dropConnection(connection
);
152 // Remove connection from list
153 removeConnection(hash
);
154 connection
->socketDescriptor
= -1;
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) {
167 //------------------------------------------------------------------------------
168 void NetlinkServer::detachConnection(
169 Connection
*connection
172 connection
->detached
= true;
176 //------------------------------------------------------------------------------
177 NetlinkServer::~NetlinkServer(
181 connectionMap_t::iterator i
;
182 // Shut down the server socket
185 // Destroy all client connections
186 for (i
= peerConnections
.begin(); i
!= peerConnections
.end(); i
++) {
187 if (i
->second
->detached
== false) {
191 peerConnections
.clear();
195 //------------------------------------------------------------------------------
196 NetlinkConnection
*NetlinkServer::findConnection(
200 connectionMap_t::iterator i
= peerConnections
.find(hash
);
201 if (i
!= peerConnections
.end()) {
209 //------------------------------------------------------------------------------
210 void NetlinkServer::insertConnection(
212 NetlinkConnection
*connection
215 peerConnections
[hash
] = connection
;
218 /* This is called from multiple threads! */
219 //------------------------------------------------------------------------------
220 void NetlinkServer::removeConnection(
224 connectionMap_t::iterator i
= peerConnections
.find(hash
);
225 if (i
!= peerConnections
.end()) {
226 peerConnections
.erase(i
);
230 //------------------------------------------------------------------------------
231 void NetlinkServer::cleanupConnections(
235 connectionMap_t::reverse_iterator i
;
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
249 bool detached
= connection
->detached
;
250 LOG_I("%s: PID %u has died, cleaning up session 0x%X",
251 __FUNCTION__
, pid
, connection
->peerPid
);
253 connection
->socketDescriptor
= -1;
255 connectionHandler
->dropConnection(connection
);
257 // We aren't handling this connection anymore no matter what
258 removeConnection(connection
->hash
);
260 // Remove connection from list only if detached, the detached
261 // connections are managed by the device
262 if (detached
== false) {
265 if (peerConnections
.size() == 0) {
268 i
= peerConnections
.rbegin();