Home | History | Annotate | Download | only in Common
      1 /** @addtogroup MCD_MCDIMPL_DAEMON_SRV
      2  * @{
      3  * @file
      4  *
      5  * Connection data.
      6  *
      7  * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of the author may not be used to endorse or promote
     18  *    products derived from this software without specific prior
     19  *    written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     27  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include <assert.h>
     36 #include <cstring>
     37 #include <errno.h>
     38 #include <stdio.h>
     39 #include <sys/socket.h>
     40 #include <linux/netlink.h>
     41 
     42 #include "NetlinkConnection.h"
     43 
     44 #include "log.h"
     45 
     46 
     47 uint64_t hashConnection(
     48     pid_t pid,
     49     uint32_t seq
     50 )
     51 {
     52     return (((uint64_t)seq) << 32) | (uint64_t)pid;
     53 }
     54 
     55 
     56 //------------------------------------------------------------------------------
     57 NetlinkConnection::NetlinkConnection(
     58     void
     59 ) : Connection(),
     60     dataLeft(0),
     61     manager(NULL)
     62 {
     63     detached = false;
     64     dataMsg = NULL;
     65     dataStart = NULL;
     66     dataLen = 0;
     67 
     68 
     69     selfPid = getpid();
     70     peerPid = 0;
     71     sequenceMagic = 0;
     72     hash = hashConnection(peerPid, sequenceMagic);
     73 }
     74 
     75 
     76 //------------------------------------------------------------------------------
     77 NetlinkConnection::NetlinkConnection(
     78     NetlinkConnectionManager    *manager,
     79     int                         socketDescriptor,
     80     uint32_t                    pid,
     81     uint32_t                    seq
     82 ): Connection(),
     83     dataLeft(0),
     84     manager(manager)
     85 {
     86     detached = false;
     87     dataMsg = NULL;
     88     dataStart = NULL;
     89     dataLen = 0;
     90 
     91     this->socketDescriptor = socketDescriptor;
     92     selfPid = getpid();
     93     peerPid = pid;
     94     sequenceMagic = seq;
     95     hash = hashConnection(pid, seq);
     96 }
     97 
     98 
     99 //------------------------------------------------------------------------------
    100 NetlinkConnection::~NetlinkConnection(
    101     void
    102 )
    103 {
    104     LOG_I("%s: destroy connection for PID 0x%X", __FUNCTION__, peerPid);
    105     socketDescriptor = -1;
    106     free(dataMsg);
    107 
    108     if (manager) {
    109         manager->removeConnection(hash);
    110     }
    111 }
    112 
    113 
    114 //------------------------------------------------------------------------------
    115 bool NetlinkConnection::connect(
    116     const char *dest
    117 )
    118 {
    119     struct sockaddr_nl addr;
    120     bool ret = false;
    121 
    122     assert(NULL != dest);
    123 
    124     LOG_I("%s: Connecting to SEQ 0x%X", __FUNCTION__, MC_DAEMON_PID);
    125     do {
    126         if ((socketDescriptor = socket(PF_NETLINK, SOCK_DGRAM, MC_DAEMON_NETLINK)) < 0) {
    127             LOG_E("%s: Can't open netlink socket - errno: %d(%s)",
    128                   __FUNCTION__, errno, strerror(errno));
    129             break;
    130         }
    131         memset(&addr, 0, sizeof(addr));
    132         addr.nl_family = AF_NETLINK;
    133         addr.nl_pid = selfPid;  /* self pid */
    134         addr.nl_groups = 0;  /* not in mcast groups */
    135 
    136         if (bind(socketDescriptor, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    137             LOG_E("%s: bind() failed - errno: %d(%s)", __FUNCTION__, errno, strerror(errno));
    138             close(socketDescriptor);
    139 
    140             // Set invalid socketDescriptor
    141             socketDescriptor = -1;
    142             break;
    143         }
    144         ret = true;
    145 
    146 
    147     } while (false);
    148 
    149     return ret;
    150 }
    151 
    152 
    153 //------------------------------------------------------------------------------
    154 void NetlinkConnection::handleMessage(
    155     struct nlmsghdr *nlh
    156 )
    157 {
    158     dataMutex.lock();
    159     /* Takeover the buffer */
    160     dataMsg = nlh;
    161     dataLen = NLMSG_PAYLOAD(dataMsg, 0);
    162     dataStart = static_cast<uint8_t *>(NLMSG_DATA(dataMsg));
    163     dataMutex.unlock();
    164     dataLeft.signal();
    165 }
    166 
    167 //------------------------------------------------------------------------------
    168 size_t NetlinkConnection::readData(
    169     void *buffer,
    170     uint32_t len
    171 )
    172 {
    173     return readData(buffer, len, -1);
    174 }
    175 
    176 
    177 //------------------------------------------------------------------------------
    178 size_t NetlinkConnection::readData(
    179     void      *buffer,
    180     uint32_t  len,
    181     int32_t   timeout
    182 )
    183 {
    184     size_t ret = -1;
    185     assert(NULL != buffer);
    186 
    187     if (!dataLeft.wait(timeout)) {
    188         return -2;
    189     }
    190     dataMutex.lock();
    191     // No data left?? Could we get this far?
    192     if (dataLen <= 0) {
    193         dataMutex.unlock();
    194         return -2;
    195     }
    196 
    197     //LOG_I("%s: reading connection data %u, connection data left %u",
    198     //      __FUNCTION__, len, dataLen);
    199 
    200     assert(dataStart != NULL);
    201 
    202     // trying to read more than the left data
    203     if (len > dataLen) {
    204         ret = dataLen;
    205         memcpy(buffer, dataStart, dataLen);
    206         dataLen = 0;
    207     } else {
    208         ret = len;
    209         memcpy(buffer, dataStart, len);
    210         dataLen -= len;
    211         dataStart += len;
    212     }
    213 
    214     if (dataLen == 0) {
    215         dataStart = NULL;
    216         free(dataMsg);
    217         dataMsg = NULL;
    218     } else {
    219         // Still some data left
    220         dataLeft.signal();
    221     }
    222     dataMutex.unlock();
    223 
    224     //LOG_I("%s: read %u", __FUNCTION__, ret);
    225     return ret;
    226 }
    227 
    228 //------------------------------------------------------------------------------
    229 size_t NetlinkConnection::writeData(
    230     void *buffer,
    231     uint32_t len
    232 )
    233 {
    234     size_t ret;
    235     struct sockaddr_nl dest_addr;
    236     struct nlmsghdr *nlh = NULL;
    237     struct iovec iov;
    238     struct msghdr msg;
    239 
    240     assert(NULL != buffer);
    241     assert(-1 != socketDescriptor);
    242 
    243     //LOG_I("%s: send data %u to PID %u", __FUNCTION__, len, sequenceMagic);
    244 
    245     memset(&dest_addr, 0, sizeof(dest_addr));
    246     dest_addr.nl_family = AF_NETLINK;
    247     dest_addr.nl_pid = peerPid;
    248     dest_addr.nl_groups = 0; /* unicast */
    249 
    250     nlh = (struct nlmsghdr *)malloc(
    251               NLMSG_SPACE(len));
    252     /* Fill the netlink message header */
    253     nlh->nlmsg_len = NLMSG_SPACE(len);
    254     nlh->nlmsg_pid = selfPid;
    255     nlh->nlmsg_flags = NLM_F_REQUEST;
    256     nlh->nlmsg_seq = sequenceMagic;
    257 
    258     /* Fill in the netlink message payload */
    259     memcpy(NLMSG_DATA(nlh), buffer, len);
    260 
    261     iov.iov_base = (void *)nlh;
    262     iov.iov_len = nlh->nlmsg_len;
    263     msg.msg_name = (void *)&dest_addr;
    264     msg.msg_namelen = sizeof(dest_addr);
    265     msg.msg_iov = &iov;
    266     msg.msg_iovlen = 1;
    267     msg.msg_control = NULL;
    268     msg.msg_controllen = 0;
    269 
    270     ret = sendmsg(socketDescriptor, &msg, 0);
    271     if (ret != NLMSG_SPACE(len)) {
    272         LOG_E( "%s: could no send all data, ret=%d, errno: %d(%s)",
    273                __FUNCTION__, ret, errno, strerror(errno));
    274         ret = -1;
    275     } else {
    276         /* The whole message sent also includes the header, so make sure to
    277          * return only the number of payload data sent, not everything */
    278         ret = len;
    279     }
    280 
    281     free(nlh);
    282 
    283     return ret;
    284 }
    285 
    286 /** @} */
    287