/* * Copyright (c) 2011-2014, Intel Corporation * All rights reserved. * * 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. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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 "Socket.h" #include #include #include #include #include #include #include #include #include #include #include #include CSocket::CSocket() : _iSockFd(socket(AF_INET, SOCK_STREAM, 0)), mSendFlag(0) { assert(_iSockFd != -1); int iNoDelay = 1; // (see man 7 tcp) // Setting TCP_NODELAY allows us sending commands and responses as soon as // they are ready to be sent, instead of waiting for more data on the // socket. setsockopt(_iSockFd, IPPROTO_TCP, TCP_NODELAY, (char *)&iNoDelay, sizeof(iNoDelay)); // Disable sigpipe reception on send # if not defined(SIGPIPE) // Pipe signal does not exist, there no sigpipe to ignore on send # elif defined(SO_NOSIGPIPE) const int set = 1; setsockopt(_iSockFd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set)); # elif defined(MSG_NOSIGNAL) // Use flag NOSIGNAL on send call mSendFlag = MSG_NOSIGNAL; # else # error Can not disable SIGPIPE # endif } CSocket::CSocket(int iSockId) : _iSockFd(iSockId) { assert(_iSockFd != -1); } CSocket::~CSocket() { // fd might be invalide if send had an error. // valgrind displays a warning if closing an invalid fd. if (_iSockFd != -1) { close(_iSockFd); } } // Socket address init void CSocket::initSockAddrIn(struct sockaddr_in* pSockAddrIn, uint32_t uiInAddr, uint16_t uiPort) const { // Fill server address pSockAddrIn->sin_family = AF_INET; pSockAddrIn->sin_port = htons(uiPort); pSockAddrIn->sin_addr.s_addr = uiInAddr; bzero(&pSockAddrIn->sin_zero, sizeof(pSockAddrIn->sin_zero)); } // Non blocking state void CSocket::setNonBlocking(bool bNonBlocking) { int iFlags = fcntl(_iSockFd, F_GETFL, 0); assert(iFlags != -1); if (bNonBlocking) { iFlags |= O_NONBLOCK; } else { iFlags &= ~O_NONBLOCK; } fcntl(_iSockFd, F_SETFL, iFlags); } // Communication timeout void CSocket::setTimeout(uint32_t uiMilliseconds) { struct timeval tv; tv.tv_sec = uiMilliseconds / 1000; tv.tv_usec = (uiMilliseconds % 1000) * 1000; setsockopt(_iSockFd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); setsockopt(_iSockFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); } // Read bool CSocket::read(void* pvData, uint32_t uiSize) { uint32_t uiOffset = 0; uint8_t* pucData = (uint8_t*)pvData; while (uiSize) { int32_t iAccessedSize = ::recv(_iSockFd, &pucData[uiOffset], uiSize, 0); switch (iAccessedSize) { case 0: // recv return value is 0 when the peer has performed an orderly shutdown. _disconnected = true; errno = ECONNRESET; // Warn the client that the client disconnected. return false; case -1: // errno == EINTR => The recv system call was interrupted, try again if (errno != EINTR) { return false; } break; default: uiSize -= iAccessedSize; uiOffset += iAccessedSize; } } return true; } // Write bool CSocket::write(const void* pvData, uint32_t uiSize) { uint32_t uiOffset = 0; const uint8_t* pucData = (const uint8_t*)pvData; while (uiSize) { int32_t iAccessedSize = ::send(_iSockFd, &pucData[uiOffset], uiSize, mSendFlag); if (iAccessedSize == -1) { if (errno == EINTR) { // The send system call was interrupted, try again continue; } // An error occured, forget this socket _disconnected = true; close(_iSockFd); _iSockFd = -1; // Avoid writing again on the same socket return false; } else { uiSize -= iAccessedSize; uiOffset += iAccessedSize; } } return true; } // Fd int CSocket::getFd() const { return _iSockFd; } bool CSocket::hasPeerDisconnected() { return _disconnected; }