19 #define _WINSOCK_DEPRECATED_NO_WARNINGS
23 #pragma comment(lib, "WS2_32.LIB")
27 #define INVALID_SOCKET (-1)
28 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <netinet/tcp.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
54 WORD wVersionRequested;
57 wVersionRequested = MAKEWORD(2, 0);
59 if (WSAStartup(wVersionRequested, &wsaData))
62 m_hSock = INVALID_SOCKET;
76 catch (
const std::exception& e)
78 std::cerr <<
"[~CClientTCPSocket] Exception:\n"
94 if (m_hSock != INVALID_SOCKET)
98 m_hSock = INVALID_SOCKET;
104 shutdown(m_hSock, SHUT_RDWR);
119 return readAsync(Buffer, Count);
131 return writeAsync(Buffer, Count);
138 Write(str.c_str(), str.size());
145 const std::string& remotePartAddress,
unsigned short remotePartTCPPort,
146 unsigned int timeout_ms)
151 if (m_hSock != INVALID_SOCKET) close();
154 if (INVALID_SOCKET == (m_hSock = socket(AF_INET, SOCK_STREAM, 0)))
156 "Error creating new client socket:\n%s",
157 getLastErrorStr().c_str()));
159 struct sockaddr_in otherAddress;
161 otherAddress.sin_family = AF_INET;
162 otherAddress.sin_port = htons(remotePartTCPPort);
165 std::string solved_IP;
167 remotePartAddress, solved_IP, DNS_LOOKUP_TIMEOUT_MS))
169 "DNS lookup failed for '%s'", remotePartAddress.c_str());
172 otherAddress.sin_addr.s_addr = inet_addr(solved_IP.c_str());
173 if (INADDR_NONE == otherAddress.sin_addr.s_addr)
175 "Invalid IP address provided: %s", solved_IP.c_str());
179 unsigned long non_block_mode = 1;
180 if (ioctlsocket(m_hSock, FIONBIO, &non_block_mode))
181 THROW_EXCEPTION(
"Error entering non-blocking mode with ioctlsocket();");
183 int oldflags = fcntl(m_hSock, F_GETFL, 0);
184 if (oldflags == -1)
THROW_EXCEPTION(
"Error retrieving fcntl();of socket.");
185 oldflags |= O_NONBLOCK;
186 if (-1 == fcntl(m_hSock, F_SETFL, oldflags))
192 m_hSock, (
struct sockaddr*)&otherAddress,
sizeof(otherAddress));
194 int er = WSAGetLastError();
195 if (r < 0 && er != WSAEINPROGRESS && er != WSAEWOULDBLOCK)
198 if (r < 0 && er != EINPROGRESS)
201 "Error connecting to %s:%hu. Error: %s [%d]",
202 remotePartAddress.c_str(), remotePartTCPPort, strerror(er), er));
205 timeval timer = {0, 0};
206 fd_set ss_write, ss_errors;
209 FD_SET(m_hSock, &ss_write);
210 FD_SET(m_hSock, &ss_errors);
212 timer.tv_sec = timeout_ms / 1000;
213 timer.tv_usec = 1000 * (timeout_ms % 1000);
215 int sel_ret = select(
220 timeout_ms == 0 ?
nullptr : &timer);
224 "Timeout connecting to '%s:%hu':\n%s", remotePartAddress.c_str(),
225 remotePartTCPPort, getLastErrorStr().c_str()));
228 "Error connecting to '%s:%hu':\n%s", remotePartAddress.c_str(),
229 remotePartTCPPort, getLastErrorStr().c_str()));
234 int lon =
sizeof(int);
235 getsockopt(m_hSock, SOL_SOCKET, SO_ERROR, (
char*)(&valopt), &
lon);
238 getsockopt(m_hSock, SOL_SOCKET, SO_ERROR, (
void*)(&valopt), &
lon);
244 "Error connecting to %s:%hu. Error: %i.", remotePartAddress.c_str(),
245 remotePartTCPPort, valopt));
249 "Error connecting to %s:%hu. Error: %s.", remotePartAddress.c_str(),
250 remotePartTCPPort, strerror(valopt)));
257 if (ioctlsocket(m_hSock, FIONBIO, &non_block_mode))
260 oldflags &= ~O_NONBLOCK;
261 if (-1 == fcntl(m_hSock, F_SETFL, oldflags))
266 m_remotePartIP = remotePartAddress;
279 void* Buffer,
const size_t Count,
const int timeoutStart_ms,
280 const int timeoutBetween_ms)
284 if (m_hSock == INVALID_SOCKET)
return 0;
286 size_t remainToRead, alreadyRead = 0;
288 bool timeoutExpired =
false;
290 struct timeval timeoutSelect = {0, 0};
291 struct timeval* ptrTimeout;
296 FD_SET(m_hSock, &sockArr);
299 while (alreadyRead < Count && !timeoutExpired)
302 int curTimeout = alreadyRead == 0 ? timeoutStart_ms : timeoutBetween_ms;
305 ptrTimeout =
nullptr;
308 timeoutSelect.tv_sec = curTimeout / 1000;
309 timeoutSelect.tv_usec = 1000 * (curTimeout % 1000);
310 ptrTimeout = &timeoutSelect;
314 int selRet = ::select(
321 if (selRet == INVALID_SOCKET)
323 "Error reading from socket: %s", getLastErrorStr().c_str());
328 timeoutExpired =
true;
333 remainToRead = Count - alreadyRead;
337 m_hSock, ((
char*)Buffer) + alreadyRead, (
int)remainToRead, 0);
339 if (readNow != INVALID_SOCKET)
342 alreadyRead += readNow;
351 if (readNow == 0 && remainToRead != 0)
355 timeoutExpired =
true;
370 const void* Buffer,
const size_t Count,
const int timeout_ms)
374 if (m_hSock == INVALID_SOCKET)
return 0;
376 size_t remainToWrite, alreadyWritten = 0;
378 bool timeoutExpired =
false;
380 struct timeval timeoutSelect = {0, 0};
381 struct timeval* ptrTimeout;
386 FD_SET(m_hSock, &sockArr);
391 ptrTimeout =
nullptr;
395 timeoutSelect.tv_sec = timeout_ms / 1000;
396 timeoutSelect.tv_usec = 1000 * (timeout_ms % 1000);
397 ptrTimeout = &timeoutSelect;
401 while (alreadyWritten < Count && !timeoutExpired)
404 int selRet = ::select(
411 if (selRet == INVALID_SOCKET)
413 "Error writing to socket: %s", getLastErrorStr().c_str());
418 timeoutExpired =
true;
425 remainToWrite = Count - alreadyWritten;
429 m_hSock, ((
char*)Buffer) + alreadyWritten, (
int)remainToWrite,
432 if (writtenNow != INVALID_SOCKET)
435 alreadyWritten += writtenNow;
441 return alreadyWritten;
451 if (m_hSock == INVALID_SOCKET)
return 0;
452 unsigned long ret = 0;
455 ioctlsocket(m_hSock, FIONREAD, &ret)
457 ioctl(m_hSock, FIONREAD, &ret)
472 int length =
sizeof(newValue);
475 m_hSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&newValue, length);
485 int length =
sizeof(value);
487 unsigned int length =
sizeof(value);
490 getsockopt(m_hSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&value, &length);
503 const unsigned int length =
sizeof(newValue);
505 return setsockopt(m_hSock, SOL_SOCKET, SO_SNDBUF, (
char*)&newValue, length);
515 int length =
sizeof(value);
517 unsigned int length =
sizeof(value);
519 getsockopt(m_hSock, SOL_SOCKET, SO_SNDBUF, (
char*)&value, &length);
530 [[maybe_unused]] int64_t off, [[maybe_unused]] CStream::TSeekOrigin org)