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