Home | History | Annotate | Download | only in Server
      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