1 /*
2 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "Socket.h"
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include <netdb.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <netinet/in.h>
40 #include <netinet/tcp.h>
41 #include <sys/time.h>
42 #include <signal.h>
43
CSocket()44 CSocket::CSocket() : _iSockFd(socket(AF_INET, SOCK_STREAM, 0)), mSendFlag(0)
45 {
46 assert(_iSockFd != -1);
47
48 int iNoDelay = 1;
49 // (see man 7 tcp)
50 // Setting TCP_NODELAY allows us sending commands and responses as soon as
51 // they are ready to be sent, instead of waiting for more data on the
52 // socket.
53 setsockopt(_iSockFd, IPPROTO_TCP, TCP_NODELAY, (char *)&iNoDelay, sizeof(iNoDelay));
54
55 // Disable sigpipe reception on send
56 # if not defined(SIGPIPE)
57 // Pipe signal does not exist, there no sigpipe to ignore on send
58 # elif defined(SO_NOSIGPIPE)
59 const int set = 1;
60 setsockopt(_iSockFd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set));
61 # elif defined(MSG_NOSIGNAL)
62 // Use flag NOSIGNAL on send call
63 mSendFlag = MSG_NOSIGNAL;
64 # else
65 # error Can not disable SIGPIPE
66 # endif
67 }
68
CSocket(int iSockId)69 CSocket::CSocket(int iSockId) : _iSockFd(iSockId)
70 {
71 assert(_iSockFd != -1);
72 }
73
~CSocket()74 CSocket::~CSocket()
75 {
76 // fd might be invalide if send had an error.
77 // valgrind displays a warning if closing an invalid fd.
78 if (_iSockFd != -1) {
79 close(_iSockFd);
80 }
81 }
82
83 // Socket address init
initSockAddrIn(struct sockaddr_in * pSockAddrIn,uint32_t uiInAddr,uint16_t uiPort) const84 void CSocket::initSockAddrIn(struct sockaddr_in* pSockAddrIn, uint32_t uiInAddr, uint16_t uiPort) const
85 {
86 // Fill server address
87 pSockAddrIn->sin_family = AF_INET;
88 pSockAddrIn->sin_port = htons(uiPort);
89 pSockAddrIn->sin_addr.s_addr = uiInAddr;
90 bzero(&pSockAddrIn->sin_zero, sizeof(pSockAddrIn->sin_zero));
91 }
92
93 // Non blocking state
setNonBlocking(bool bNonBlocking)94 void CSocket::setNonBlocking(bool bNonBlocking)
95 {
96 int iFlags = fcntl(_iSockFd, F_GETFL, 0);
97
98 assert(iFlags != -1);
99
100 if (bNonBlocking) {
101
102 iFlags |= O_NONBLOCK;
103 } else {
104
105 iFlags &= ~O_NONBLOCK;
106 }
107 fcntl(_iSockFd, F_SETFL, iFlags);
108 }
109
110 // Communication timeout
setTimeout(uint32_t uiMilliseconds)111 void CSocket::setTimeout(uint32_t uiMilliseconds)
112 {
113 struct timeval tv;
114 tv.tv_sec = uiMilliseconds / 1000;
115 tv.tv_usec = (uiMilliseconds % 1000) * 1000;
116
117 setsockopt(_iSockFd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
118 setsockopt(_iSockFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
119 }
120
121 // Read
read(void * pvData,uint32_t uiSize)122 bool CSocket::read(void* pvData, uint32_t uiSize)
123 {
124 uint32_t uiOffset = 0;
125 uint8_t* pucData = (uint8_t*)pvData;
126
127 while (uiSize) {
128
129 int32_t iAccessedSize = ::recv(_iSockFd, &pucData[uiOffset], uiSize, 0);
130
131 switch (iAccessedSize) {
132 case 0:
133 // recv return value is 0 when the peer has performed an orderly shutdown.
134 _disconnected = true;
135 errno = ECONNRESET; // Warn the client that the client disconnected.
136 return false;
137
138 case -1:
139 // errno == EINTR => The recv system call was interrupted, try again
140 if (errno != EINTR) {
141 return false;
142 }
143 break;
144
145 default:
146 uiSize -= iAccessedSize;
147 uiOffset += iAccessedSize;
148 }
149 }
150 return true;
151 }
152
153 // Write
write(const void * pvData,uint32_t uiSize)154 bool CSocket::write(const void* pvData, uint32_t uiSize)
155 {
156 uint32_t uiOffset = 0;
157 const uint8_t* pucData = (const uint8_t*)pvData;
158
159 while (uiSize) {
160
161 int32_t iAccessedSize = ::send(_iSockFd, &pucData[uiOffset], uiSize, mSendFlag);
162
163 if (iAccessedSize == -1) {
164 if (errno == EINTR) {
165 // The send system call was interrupted, try again
166 continue;
167 }
168
169 // An error occured, forget this socket
170 _disconnected = true;
171 close(_iSockFd);
172 _iSockFd = -1; // Avoid writing again on the same socket
173 return false;
174 } else {
175 uiSize -= iAccessedSize;
176 uiOffset += iAccessedSize;
177 }
178 }
179 return true;
180 }
181
182 // Fd
getFd() const183 int CSocket::getFd() const
184 {
185 return _iSockFd;
186 }
187
hasPeerDisconnected()188 bool CSocket::hasPeerDisconnected() {
189 return _disconnected;
190 }
191