1f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard/* 2b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * Copyright (c) 2011-2014, Intel Corporation 3b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * All rights reserved. 4b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 5b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * Redistribution and use in source and binary forms, with or without modification, 6b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * are permitted provided that the following conditions are met: 7b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 8b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 1. Redistributions of source code must retain the above copyright notice, this 9b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * list of conditions and the following disclaimer. 10b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 11b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 2. Redistributions in binary form must reproduce the above copyright notice, 12b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * this list of conditions and the following disclaimer in the documentation and/or 13b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * other materials provided with the distribution. 14b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 15b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 3. Neither the name of the copyright holder nor the names of its contributors 16b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * may be used to endorse or promote products derived from this software without 17b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * specific prior written permission. 18b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * 19b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2968a912857707864bbaaff9808717813105072a6ePatrick Benavoli */ 3068a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include "Socket.h" 3168a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/types.h> 3268a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/socket.h> 3368a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <unistd.h> 3468a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <assert.h> 3568a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <netdb.h> 3668a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <strings.h> 37f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard#include <errno.h> 3868a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <fcntl.h> 3968a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <netinet/in.h> 403e783c2172a05bf5557086301442e7b56aba78a2David Wagner#include <netinet/tcp.h> 4168a912857707864bbaaff9808717813105072a6ePatrick Benavoli#include <sys/time.h> 42a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi#include <signal.h> 4368a912857707864bbaaff9808717813105072a6ePatrick Benavoli 44a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel TriviCSocket::CSocket() : _iSockFd(socket(AF_INET, SOCK_STREAM, 0)), mSendFlag(0) 4568a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 4668a912857707864bbaaff9808717813105072a6ePatrick Benavoli assert(_iSockFd != -1); 473e783c2172a05bf5557086301442e7b56aba78a2David Wagner 483e783c2172a05bf5557086301442e7b56aba78a2David Wagner int iNoDelay = 1; 493e783c2172a05bf5557086301442e7b56aba78a2David Wagner // (see man 7 tcp) 503e783c2172a05bf5557086301442e7b56aba78a2David Wagner // Setting TCP_NODELAY allows us sending commands and responses as soon as 513e783c2172a05bf5557086301442e7b56aba78a2David Wagner // they are ready to be sent, instead of waiting for more data on the 523e783c2172a05bf5557086301442e7b56aba78a2David Wagner // socket. 533e783c2172a05bf5557086301442e7b56aba78a2David Wagner setsockopt(_iSockFd, IPPROTO_TCP, TCP_NODELAY, (char *)&iNoDelay, sizeof(iNoDelay)); 54a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi 55a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // Disable sigpipe reception on send 56a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi# if not defined(SIGPIPE) 57a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // Pipe signal does not exist, there no sigpipe to ignore on send 58a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi# elif defined(SO_NOSIGPIPE) 59a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi const int set = 1; 60a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi setsockopt(_iSockFd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set)); 61a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi# elif defined(MSG_NOSIGNAL) 62a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // Use flag NOSIGNAL on send call 63a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi mSendFlag = MSG_NOSIGNAL; 64a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi# else 65a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi# error Can not disable SIGPIPE 66a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi# endif 6768a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 6868a912857707864bbaaff9808717813105072a6ePatrick Benavoli 6968a912857707864bbaaff9808717813105072a6ePatrick BenavoliCSocket::CSocket(int iSockId) : _iSockFd(iSockId) 7068a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 7168a912857707864bbaaff9808717813105072a6ePatrick Benavoli assert(_iSockFd != -1); 7268a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 7368a912857707864bbaaff9808717813105072a6ePatrick Benavoli 7468a912857707864bbaaff9808717813105072a6ePatrick BenavoliCSocket::~CSocket() 7568a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 76a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // fd might be invalide if send had an error. 77a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // valgrind displays a warning if closing an invalid fd. 78a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi if (_iSockFd != -1) { 79a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi close(_iSockFd); 80a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi } 8168a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 8268a912857707864bbaaff9808717813105072a6ePatrick Benavoli 8368a912857707864bbaaff9808717813105072a6ePatrick Benavoli// Socket address init 8468a912857707864bbaaff9808717813105072a6ePatrick Benavolivoid CSocket::initSockAddrIn(struct sockaddr_in* pSockAddrIn, uint32_t uiInAddr, uint16_t uiPort) const 8568a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 8668a912857707864bbaaff9808717813105072a6ePatrick Benavoli // Fill server address 8768a912857707864bbaaff9808717813105072a6ePatrick Benavoli pSockAddrIn->sin_family = AF_INET; 8868a912857707864bbaaff9808717813105072a6ePatrick Benavoli pSockAddrIn->sin_port = htons(uiPort); 8968a912857707864bbaaff9808717813105072a6ePatrick Benavoli pSockAddrIn->sin_addr.s_addr = uiInAddr; 9068a912857707864bbaaff9808717813105072a6ePatrick Benavoli bzero(&pSockAddrIn->sin_zero, sizeof(pSockAddrIn->sin_zero)); 9168a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 9268a912857707864bbaaff9808717813105072a6ePatrick Benavoli 9368a912857707864bbaaff9808717813105072a6ePatrick Benavoli// Non blocking state 9468a912857707864bbaaff9808717813105072a6ePatrick Benavolivoid CSocket::setNonBlocking(bool bNonBlocking) 9568a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 9668a912857707864bbaaff9808717813105072a6ePatrick Benavoli int iFlags = fcntl(_iSockFd, F_GETFL, 0); 9768a912857707864bbaaff9808717813105072a6ePatrick Benavoli 9868a912857707864bbaaff9808717813105072a6ePatrick Benavoli assert(iFlags != -1); 9968a912857707864bbaaff9808717813105072a6ePatrick Benavoli 10068a912857707864bbaaff9808717813105072a6ePatrick Benavoli if (bNonBlocking) { 10168a912857707864bbaaff9808717813105072a6ePatrick Benavoli 10268a912857707864bbaaff9808717813105072a6ePatrick Benavoli iFlags |= O_NONBLOCK; 10368a912857707864bbaaff9808717813105072a6ePatrick Benavoli } else { 10468a912857707864bbaaff9808717813105072a6ePatrick Benavoli 10568a912857707864bbaaff9808717813105072a6ePatrick Benavoli iFlags &= ~O_NONBLOCK; 10668a912857707864bbaaff9808717813105072a6ePatrick Benavoli } 10768a912857707864bbaaff9808717813105072a6ePatrick Benavoli fcntl(_iSockFd, F_SETFL, iFlags); 10868a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 10968a912857707864bbaaff9808717813105072a6ePatrick Benavoli 11068a912857707864bbaaff9808717813105072a6ePatrick Benavoli// Communication timeout 11168a912857707864bbaaff9808717813105072a6ePatrick Benavolivoid CSocket::setTimeout(uint32_t uiMilliseconds) 11268a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 11368a912857707864bbaaff9808717813105072a6ePatrick Benavoli struct timeval tv; 11468a912857707864bbaaff9808717813105072a6ePatrick Benavoli tv.tv_sec = uiMilliseconds / 1000; 11568a912857707864bbaaff9808717813105072a6ePatrick Benavoli tv.tv_usec = (uiMilliseconds % 1000) * 1000; 11668a912857707864bbaaff9808717813105072a6ePatrick Benavoli 11768a912857707864bbaaff9808717813105072a6ePatrick Benavoli setsockopt(_iSockFd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 11868a912857707864bbaaff9808717813105072a6ePatrick Benavoli setsockopt(_iSockFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 11968a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 12068a912857707864bbaaff9808717813105072a6ePatrick Benavoli 12168a912857707864bbaaff9808717813105072a6ePatrick Benavoli// Read 12268a912857707864bbaaff9808717813105072a6ePatrick Benavolibool CSocket::read(void* pvData, uint32_t uiSize) 12368a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 12468a912857707864bbaaff9808717813105072a6ePatrick Benavoli uint32_t uiOffset = 0; 12568a912857707864bbaaff9808717813105072a6ePatrick Benavoli uint8_t* pucData = (uint8_t*)pvData; 12668a912857707864bbaaff9808717813105072a6ePatrick Benavoli 12768a912857707864bbaaff9808717813105072a6ePatrick Benavoli while (uiSize) { 12868a912857707864bbaaff9808717813105072a6ePatrick Benavoli 129a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi int32_t iAccessedSize = ::recv(_iSockFd, &pucData[uiOffset], uiSize, 0); 13068a912857707864bbaaff9808717813105072a6ePatrick Benavoli 131f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard switch (iAccessedSize) { 132f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard case 0: 1333dd67addc686e490ac4b710250d1d5fca4ca0729Kevin Rocard // recv return value is 0 when the peer has performed an orderly shutdown. 134ef8d727ca0eb346af951d15d84ba6f2b9564adf5Kevin Rocard _disconnected = true; 135ef8d727ca0eb346af951d15d84ba6f2b9564adf5Kevin Rocard errno = ECONNRESET; // Warn the client that the client disconnected. 13668a912857707864bbaaff9808717813105072a6ePatrick Benavoli return false; 137f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard 138f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard case -1: 139f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard // errno == EINTR => The recv system call was interrupted, try again 140f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard if (errno != EINTR) { 141f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard return false; 142f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard } 143f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard break; 144f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard 145f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard default: 146f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard uiSize -= iAccessedSize; 147f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard uiOffset += iAccessedSize; 14868a912857707864bbaaff9808717813105072a6ePatrick Benavoli } 14968a912857707864bbaaff9808717813105072a6ePatrick Benavoli } 15068a912857707864bbaaff9808717813105072a6ePatrick Benavoli return true; 15168a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 15268a912857707864bbaaff9808717813105072a6ePatrick Benavoli 15368a912857707864bbaaff9808717813105072a6ePatrick Benavoli// Write 15468a912857707864bbaaff9808717813105072a6ePatrick Benavolibool CSocket::write(const void* pvData, uint32_t uiSize) 15568a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 15668a912857707864bbaaff9808717813105072a6ePatrick Benavoli uint32_t uiOffset = 0; 15768a912857707864bbaaff9808717813105072a6ePatrick Benavoli const uint8_t* pucData = (const uint8_t*)pvData; 15868a912857707864bbaaff9808717813105072a6ePatrick Benavoli 15968a912857707864bbaaff9808717813105072a6ePatrick Benavoli while (uiSize) { 16068a912857707864bbaaff9808717813105072a6ePatrick Benavoli 161a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi int32_t iAccessedSize = ::send(_iSockFd, &pucData[uiOffset], uiSize, mSendFlag); 16268a912857707864bbaaff9808717813105072a6ePatrick Benavoli 1633dd67addc686e490ac4b710250d1d5fca4ca0729Kevin Rocard if (iAccessedSize == -1) { 164a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi if (errno == EINTR) { 165a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // The send system call was interrupted, try again 166a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi continue; 167f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard } 168a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi 169a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi // An error occured, forget this socket 170a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi _disconnected = true; 171a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi close(_iSockFd); 172a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi _iSockFd = -1; // Avoid writing again on the same socket 173a9be2d378b7ad84e679a48efa81f42fb54f85d9aJean-Michel Trivi return false; 174f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard } else { 175f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard uiSize -= iAccessedSize; 176f976f3749c6639915a646a88049fe523e3d5f051Kevin Rocard uiOffset += iAccessedSize; 17768a912857707864bbaaff9808717813105072a6ePatrick Benavoli } 17868a912857707864bbaaff9808717813105072a6ePatrick Benavoli } 17968a912857707864bbaaff9808717813105072a6ePatrick Benavoli return true; 18068a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 18168a912857707864bbaaff9808717813105072a6ePatrick Benavoli 18268a912857707864bbaaff9808717813105072a6ePatrick Benavoli// Fd 18368a912857707864bbaaff9808717813105072a6ePatrick Benavoliint CSocket::getFd() const 18468a912857707864bbaaff9808717813105072a6ePatrick Benavoli{ 18568a912857707864bbaaff9808717813105072a6ePatrick Benavoli return _iSockFd; 18668a912857707864bbaaff9808717813105072a6ePatrick Benavoli} 187ef8d727ca0eb346af951d15d84ba6f2b9564adf5Kevin Rocard 188ef8d727ca0eb346af951d15d84ba6f2b9564adf5Kevin Rocardbool CSocket::hasPeerDisconnected() { 189ef8d727ca0eb346af951d15d84ba6f2b9564adf5Kevin Rocard return _disconnected; 190ef8d727ca0eb346af951d15d84ba6f2b9564adf5Kevin Rocard} 191