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 <unistd.h> 34#include <assert.h> 35#include <cstring> 36#include <errno.h> 37 38#include "Connection.h" 39 40//#define LOG_VERBOSE 41#include "log.h" 42 43 44//------------------------------------------------------------------------------ 45Connection::Connection(void) 46{ 47 connectionData = NULL; 48 // Set invalid socketDescriptor 49 socketDescriptor = -1; 50} 51 52 53//------------------------------------------------------------------------------ 54Connection::Connection(int socketDescriptor, sockaddr_un *remote) 55{ 56 assert(NULL != remote); 57 assert(-1 != socketDescriptor); 58 59 this->socketDescriptor = socketDescriptor; 60 this->remote = *remote; 61 connectionData = NULL; 62} 63 64 65//------------------------------------------------------------------------------ 66Connection::~Connection(void) 67{ 68 LOG_V(" closing Connection..."); 69 if (socketDescriptor != -1) 70 close(socketDescriptor); 71 LOG_I(" Socket connection closed."); 72} 73 74 75//------------------------------------------------------------------------------ 76bool Connection::connect(const char *dest) 77{ 78 int32_t len; 79 80 assert(NULL != dest); 81 82 LOG_I(" Connecting to %s socket", dest); 83 remote.sun_family = AF_UNIX; 84 strncpy(remote.sun_path, dest, sizeof(remote.sun_path) - 1); 85 if ((socketDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 86 LOG_ERRNO("Can't open stream socket."); 87 return false; 88 } 89 len = strlen(remote.sun_path) + sizeof(remote.sun_family); 90 // The Daemon socket is in the Abstract Domain(LINUX ONLY!) 91 remote.sun_path[0] = 0; 92 if (::connect(socketDescriptor, (struct sockaddr *) &remote, len) < 0) { 93 LOG_ERRNO("connect()"); 94 return false; 95 } 96 return true; 97} 98 99 100//------------------------------------------------------------------------------ 101size_t Connection::readData(void *buffer, uint32_t len) 102{ 103 return readData(buffer, len, -1); 104} 105 106 107//------------------------------------------------------------------------------ 108size_t Connection::readData(void *buffer, uint32_t len, int32_t timeout) 109{ 110 size_t ret = 0; 111 struct timeval tv; 112 struct timeval *ptv = NULL; 113 fd_set readfds; 114 115 assert(NULL != buffer); 116 assert(socketDescriptor != -1); 117 118 if (timeout >= 0) { 119 // Calculate timeout value 120 tv.tv_sec = timeout / 1000; 121 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; 122 ptv = &tv; 123 } 124 125 FD_ZERO(&readfds); 126 FD_SET(socketDescriptor, &readfds); 127 ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv); 128 129 // check for read error 130 if ((int)ret == -1) { 131 LOG_ERRNO("select"); 132 return -1; 133 } 134 135 // Handle case of no descriptor ready 136 if (0 == ret) { 137 LOG_W(" Timeout during select() / No more notifications."); 138 return -2; 139 } 140 141 // one or more descriptors are ready 142 143 // finally check if fd has been selected -> must socketDescriptor 144 if (!FD_ISSET(socketDescriptor, &readfds)) { 145 LOG_ERRNO("no fd is set, select"); 146 return ret; 147 } 148 149 ret = recv(socketDescriptor, buffer, len, MSG_DONTWAIT); 150 if (ret == 0) { 151 LOG_V(" readData(): peer orderly closed connection."); 152 } 153 154 return ret; 155} 156 157 158//------------------------------------------------------------------------------ 159size_t Connection::writeData(void *buffer, uint32_t len) 160{ 161 size_t ret; 162 163 assert(NULL != buffer); 164 assert(-1 != socketDescriptor); 165 166 ret = send(socketDescriptor, buffer, len, 0); 167 if (ret != len) { 168 LOG_ERRNO("could not send all data, because send"); 169 LOG_E("ret = %d", ret); 170 ret = -1; 171 } 172 173 return ret; 174} 175 176 177//------------------------------------------------------------------------------ 178int Connection::waitData(int32_t timeout) 179{ 180 size_t ret; 181 struct timeval tv; 182 struct timeval *ptv = NULL; 183 fd_set readfds; 184 185 assert(socketDescriptor != -1); 186 187 if (timeout >= 0) { 188 // Calculate timeout value 189 tv.tv_sec = timeout / 1000; 190 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; 191 ptv = &tv; 192 } 193 194 FD_ZERO(&readfds); 195 FD_SET(socketDescriptor, &readfds); 196 ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv); 197 198 // check for read error 199 if ((int)ret == -1) { 200 LOG_ERRNO("select"); 201 return ret; 202 } else if (ret == 0) { 203 LOG_E("select() timed out"); 204 return -1; 205 } 206 207 return 0; 208} 209 210/** @} */ 211