/** @addtogroup MCD_MCDIMPL_DAEMON_SRV * @{ * @file * * Connection data. * * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "Connection.h" //#define LOG_VERBOSE #include "log.h" //------------------------------------------------------------------------------ Connection::Connection(void) { connectionData = NULL; // Set invalid socketDescriptor socketDescriptor = -1; } //------------------------------------------------------------------------------ Connection::Connection(int socketDescriptor, sockaddr_un *remote) { assert(NULL != remote); assert(-1 != socketDescriptor); this->socketDescriptor = socketDescriptor; this->remote = *remote; connectionData = NULL; } //------------------------------------------------------------------------------ Connection::~Connection(void) { LOG_V(" closing Connection..."); if (socketDescriptor != -1) close(socketDescriptor); LOG_I(" Socket connection closed."); } //------------------------------------------------------------------------------ bool Connection::connect(const char *dest) { int32_t len; assert(NULL != dest); LOG_I(" Connecting to %s socket", dest); remote.sun_family = AF_UNIX; strncpy(remote.sun_path, dest, sizeof(remote.sun_path) - 1); if ((socketDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { LOG_ERRNO("Can't open stream socket."); return false; } len = strlen(remote.sun_path) + sizeof(remote.sun_family); // The Daemon socket is in the Abstract Domain(LINUX ONLY!) remote.sun_path[0] = 0; if (::connect(socketDescriptor, (struct sockaddr *) &remote, len) < 0) { LOG_ERRNO("connect()"); return false; } return true; } //------------------------------------------------------------------------------ size_t Connection::readData(void *buffer, uint32_t len) { return readData(buffer, len, -1); } //------------------------------------------------------------------------------ size_t Connection::readData(void *buffer, uint32_t len, int32_t timeout) { size_t ret = 0; struct timeval tv; struct timeval *ptv = NULL; fd_set readfds; assert(NULL != buffer); assert(socketDescriptor != -1); if (timeout >= 0) { // Calculate timeout value tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; ptv = &tv; } FD_ZERO(&readfds); FD_SET(socketDescriptor, &readfds); ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv); // check for read error if ((int)ret == -1) { LOG_ERRNO("select"); return -1; } // Handle case of no descriptor ready if (0 == ret) { LOG_W(" Timeout during select() / No more notifications."); return -2; } // one or more descriptors are ready // finally check if fd has been selected -> must socketDescriptor if (!FD_ISSET(socketDescriptor, &readfds)) { LOG_ERRNO("no fd is set, select"); return ret; } ret = recv(socketDescriptor, buffer, len, MSG_DONTWAIT); if (ret == 0) { LOG_V(" readData(): peer orderly closed connection."); } return ret; } //------------------------------------------------------------------------------ size_t Connection::writeData(void *buffer, uint32_t len) { size_t ret; assert(NULL != buffer); assert(-1 != socketDescriptor); ret = send(socketDescriptor, buffer, len, 0); if (ret != len) { LOG_ERRNO("could not send all data, because send"); LOG_E("ret = %d", ret); ret = -1; } return ret; } //------------------------------------------------------------------------------ int Connection::waitData(int32_t timeout) { size_t ret; struct timeval tv; struct timeval *ptv = NULL; fd_set readfds; assert(socketDescriptor != -1); if (timeout >= 0) { // Calculate timeout value tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; ptv = &tv; } FD_ZERO(&readfds); FD_SET(socketDescriptor, &readfds); ret = select(socketDescriptor + 1, &readfds, NULL, NULL, ptv); // check for read error if ((int)ret == -1) { LOG_ERRNO("select"); return ret; } else if (ret == 0) { LOG_E("select() timed out"); return -1; } return 0; } /** @} */