This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,171 @@
#include "IConnection.h"
#include "IConnectionClient.h"
#include "IConnection.inl"
#include <cstring>
#include <iostream>
#include <fcntl.h>
#include <cerrno>
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <unistd.h>
#elif defined TARGET_OS_Windows
#include <cerrno>
#include <WS2tcpip.h>
#else
#endif
namespace Socket {
class CConnectionClient final : public TConnection<IConnectionClient>
{
public:
bool connect(const char* sServerName, const size_t serverPort, const size_t timeOut) override
{
if (!open()) { return false; }
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
long value;
// Sets non blocking
if((value = ::fcntl(m_socket, F_GETFL, nullptr)) < 0)
{
close();
return false;
}
value|=O_NONBLOCK;
if(::fcntl(m_socket, F_SETFL, value)<0)
{
close();
return false;
}
// Looks up host name
struct hostent* serverHostEntry = gethostbyname(sServerName);
if(!serverHostEntry)
{
close();
return false;
}
#elif defined TARGET_OS_Windows
// Sets non blocking
unsigned long mode = 1;
ioctlsocket(m_socket, FIONBIO, &mode);
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
PADDRINFOA addr;
if (getaddrinfo(sServerName, nullptr, &hints, &addr) != 0)
{
close();
return false;
}
const auto sockaddrIPV4 = reinterpret_cast<sockaddr_in*>(addr->ai_addr);
#endif
// Connects
struct sockaddr_in serverAddress;
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(static_cast<unsigned short>(serverPort));
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
serverAddress.sin_addr=*((struct in_addr*)serverHostEntry->h_addr);
#elif defined TARGET_OS_Windows
serverAddress.sin_addr = sockaddrIPV4->sin_addr;
freeaddrinfo(addr);
#endif
errno = 0;
if (::connect(m_socket, reinterpret_cast<struct sockaddr*>(&serverAddress), sizeof(struct sockaddr_in)) < 0)
{
bool inProgress;
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
inProgress = (errno==EINPROGRESS);
#elif defined TARGET_OS_Windows
inProgress = (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK);
#else
inProgress = false;
#endif
if (inProgress)
{
const int t = (timeOut == 0xffffffff) ? 125 : int(timeOut);
// Performs time out
struct timeval timeVal;
timeVal.tv_sec = (t / 1000);
timeVal.tv_usec = ((t - timeVal.tv_sec * 1000) * 1000);
fd_set writeFileDesc;
FD_ZERO(&writeFileDesc);
FD_SET(m_socket, &writeFileDesc);
if (select(int(m_socket + 1), nullptr, &writeFileDesc, nullptr, &timeVal) < 0)
{
close();
return false;
}
if (!FD_ISSET_PROXY(int(m_socket), &writeFileDesc))
{
close();
return false;
}
// Checks error status
int option = 0;
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
socklen_t length = sizeof(option);
::getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (void*)(&option), &length);
#elif defined TARGET_OS_Windows
int length = sizeof(option);
getsockopt(m_socket, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&option), &length);
#endif
if (option != 0)
{
close();
return false;
}
}
else
{
close();
return false;
}
}
#if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
// Sets back to blocking
if((value=::fcntl(m_socket, F_GETFL, nullptr))<0)
{
close();
return false;
}
value&=~O_NONBLOCK;
if(::fcntl(m_socket, F_SETFL, value)<0)
{
close();
return false;
}
#elif defined TARGET_OS_Windows
// Sets back to blocking
mode = 0;
ioctlsocket(m_socket, FIONBIO, &mode);
#endif
return true;
}
};
IConnectionClient* createConnectionClient() { return new CConnectionClient(); }
} // namespace Socket