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