19 #define _WINSOCK_DEPRECATED_NO_WARNINGS
23 #pragma comment(lib, "WS2_32.LIB")
27 #define INVALID_SOCKET (-1)
28 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
54 WORD wVersionRequested;
57 wVersionRequested = MAKEWORD(2, 0);
59 if (WSAStartup(wVersionRequested, &wsaData))
62 m_hSock = INVALID_SOCKET;
87 if (m_hSock != INVALID_SOCKET)
91 m_hSock = INVALID_SOCKET;
97 shutdown(m_hSock, SHUT_RDWR);
112 return readAsync(Buffer, Count);
124 return writeAsync(Buffer, Count);
131 Write(str.c_str(), str.size());
138 const std::string& remotePartAddress,
unsigned short remotePartTCPPort,
139 unsigned int timeout_ms)
144 if (m_hSock != INVALID_SOCKET) close();
147 if (INVALID_SOCKET == (m_hSock = socket(AF_INET, SOCK_STREAM, 0)))
150 "Error creating new client socket:\n%s",
151 getLastErrorStr().c_str()));
153 struct sockaddr_in otherAddress;
155 otherAddress.sin_family = AF_INET;
156 otherAddress.sin_port = htons(remotePartTCPPort);
161 remotePartAddress, solved_IP, DNS_LOOKUP_TIMEOUT_MS))
163 "DNS lookup failed for '%s'", remotePartAddress.c_str());
166 otherAddress.sin_addr.s_addr = inet_addr(solved_IP.c_str());
167 if (INADDR_NONE == otherAddress.sin_addr.s_addr)
169 "Invalid IP address provided: %s", solved_IP.c_str());
173 unsigned long non_block_mode = 1;
174 if (ioctlsocket(m_hSock, FIONBIO, &non_block_mode))
175 THROW_EXCEPTION(
"Error entering non-blocking mode with ioctlsocket();");
177 int oldflags = fcntl(m_hSock, F_GETFL, 0);
178 if (oldflags == -1)
THROW_EXCEPTION(
"Error retrieving fcntl();of socket.");
179 oldflags |= O_NONBLOCK;
180 if (-1 == fcntl(m_hSock, F_SETFL, oldflags))
186 m_hSock, (
struct sockaddr*)&otherAddress,
sizeof(otherAddress));
188 int er = WSAGetLastError();
189 if (
r < 0 && er != WSAEINPROGRESS && er != WSAEWOULDBLOCK)
192 if (
r < 0 && er != EINPROGRESS)
196 "Error connecting to %s:%hu. Error: %s [%d]",
197 remotePartAddress.c_str(), remotePartTCPPort, strerror(er),
204 FD_ZERO(&socket_set);
205 FD_SET(m_hSock, &socket_set);
207 timer.tv_sec = timeout_ms / 1000;
208 timer.tv_usec = 1000 * (timeout_ms % 1000);
210 int sel_ret = select(
215 timeout_ms == 0 ?
nullptr : &timer);
220 "Timeout connecting to '%s:%hu':\n%s",
221 remotePartAddress.c_str(), remotePartTCPPort,
222 getLastErrorStr().c_str()));
226 "Error connecting to '%s:%hu':\n%s", remotePartAddress.c_str(),
227 remotePartTCPPort, getLastErrorStr().c_str()));
232 int lon =
sizeof(int);
233 getsockopt(m_hSock, SOL_SOCKET, SO_ERROR, (
char*)(&valopt), &
lon);
236 getsockopt(m_hSock, SOL_SOCKET, SO_ERROR, (
void*)(&valopt), &
lon);
243 "Error connecting to %s:%hu. Error: %i.",
244 remotePartAddress.c_str(), remotePartTCPPort, valopt));
249 "Error connecting to %s:%hu. Error: %s.",
250 remotePartAddress.c_str(), remotePartTCPPort,
258 if (ioctlsocket(m_hSock, FIONBIO, &non_block_mode))
261 oldflags &= ~O_NONBLOCK;
262 if (-1 == fcntl(m_hSock, F_SETFL, oldflags))
267 m_remotePartIP = remotePartAddress;
280 void* Buffer,
const size_t Count,
const int timeoutStart_ms,
281 const int timeoutBetween_ms)
285 if (m_hSock == INVALID_SOCKET)
return 0;
287 size_t remainToRead, alreadyRead = 0;
289 bool timeoutExpired =
false;
291 struct timeval timeoutSelect;
292 struct timeval* ptrTimeout;
297 FD_SET(m_hSock, &sockArr);
300 while (alreadyRead < Count && !timeoutExpired)
303 int curTimeout = alreadyRead == 0 ? timeoutStart_ms : timeoutBetween_ms;
306 ptrTimeout =
nullptr;
309 timeoutSelect.tv_sec = curTimeout / 1000;
310 timeoutSelect.tv_usec = 1000 * (curTimeout % 1000);
311 ptrTimeout = &timeoutSelect;
315 int selRet = ::select(
322 if (selRet == INVALID_SOCKET)
324 "Error reading from socket: %s", getLastErrorStr().c_str());
329 timeoutExpired =
true;
334 remainToRead = Count - alreadyRead;
338 m_hSock, ((
char*)Buffer) + alreadyRead, (
int)remainToRead, 0);
340 if (readNow != INVALID_SOCKET)
343 alreadyRead += readNow;
352 if (readNow == 0 && remainToRead != 0)
356 timeoutExpired =
true;
371 const void* Buffer,
const size_t Count,
const int timeout_ms)
375 if (m_hSock == INVALID_SOCKET)
return 0;
377 size_t remainToWrite, alreadyWritten = 0;
379 bool timeoutExpired =
false;
381 struct timeval timeoutSelect;
382 struct timeval* ptrTimeout;
387 FD_SET(m_hSock, &sockArr);
392 ptrTimeout =
nullptr;
396 timeoutSelect.tv_sec = timeout_ms / 1000;
397 timeoutSelect.tv_usec = 1000 * (timeout_ms % 1000);
398 ptrTimeout = &timeoutSelect;
402 while (alreadyWritten < Count && !timeoutExpired)
405 int selRet = ::select(
412 if (selRet == INVALID_SOCKET)
414 "Error writing to socket: %s", getLastErrorStr().c_str());
419 timeoutExpired =
true;
426 remainToWrite = Count - alreadyWritten;
430 m_hSock, ((
char*)Buffer) + alreadyWritten, (
int)remainToWrite,
433 if (writtenNow != INVALID_SOCKET)
436 alreadyWritten += writtenNow;
442 return alreadyWritten;
452 if (m_hSock == INVALID_SOCKET)
return 0;
453 unsigned long ret = 0;
456 ioctlsocket(m_hSock, FIONREAD, &ret)
458 ioctl(m_hSock, FIONREAD, &ret)
473 int length =
sizeof(newValue);
476 m_hSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&newValue,
length);
491 getsockopt(m_hSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&
value, &
length);
504 const unsigned int length =
sizeof(newValue);
506 return setsockopt(m_hSock, SOL_SOCKET, SO_SNDBUF, (
char*)&newValue,
length);
520 getsockopt(m_hSock, SOL_SOCKET, SO_SNDBUF, (
char*)&
value, &
length);