init
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user