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 /** @} */ 274