blob: b36d32fc804addbf2d3bfc5a959388b436438f93 [file] [log] [blame]
/*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <assert.h>
#include <netdb.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/time.h>
CSocket::CSocket() : _iSockFd(socket(AF_INET, SOCK_STREAM, 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));
}
CSocket::CSocket(int iSockId) : _iSockFd(iSockId)
{
assert(_iSockFd != -1);
}
CSocket::~CSocket()
{
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, MSG_NOSIGNAL);
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, MSG_NOSIGNAL);
if (iAccessedSize == -1) {
if (errno == ECONNRESET) {
// Peer has disconnected
_disconnected = true;
}
// errno == EINTR => The send system call was interrupted, try again
if (errno != EINTR) {
return false;
}
} else {
uiSize -= iAccessedSize;
uiOffset += iAccessedSize;
}
}
return true;
}
// Fd
int CSocket::getFd() const
{
return _iSockFd;
}
bool CSocket::hasPeerDisconnected() {
return _disconnected;
}