Both fr::TcpSocket and fr::SSLSocket can have timeouts specified when connecting. This works by putting the socket into non-blocking mode, making a connect, and then selecting on the socket for the requested timeout. If the select times out then we've failed to connect, if it didn't time out then we've connected.
128 lines
2.9 KiB
C++
128 lines
2.9 KiB
C++
//
|
|
// Created by fred on 06/12/16.
|
|
//
|
|
|
|
#ifndef FRNETLIB_NETWORKENCODING_H
|
|
#define FRNETLIB_NETWORKENCODING_H
|
|
|
|
#include <cstring>
|
|
#include <cstdint>
|
|
#include <atomic>
|
|
#include <exception>
|
|
#include <stdexcept>
|
|
#include <csignal>
|
|
|
|
//Windows and UNIX require some different headers.
|
|
//We also need some compatibility defines for cross platform support.
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
#include <ws2tcpip.h>
|
|
#define SOL_TCP SOL_SOCKET
|
|
#define SHUT_RDWR SD_BOTH
|
|
#define UNUSED_VAR
|
|
#else
|
|
|
|
#define UNUSED_VAR __attribute__ ((unused))
|
|
#define closesocket(x) close(x)
|
|
#define INVALID_SOCKET 0
|
|
#define SOCKET_ERROR (-1)
|
|
|
|
#include <netdb.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/tcp.h>
|
|
#endif
|
|
|
|
|
|
#undef htonll
|
|
#undef ntohll
|
|
#undef htonf
|
|
#undef ntohf
|
|
#undef htond
|
|
#undef ntohd
|
|
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
|
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
|
|
|
|
inline float htonf(float val)
|
|
{
|
|
uint32_t ret;
|
|
memcpy(&ret, &val, sizeof(ret));
|
|
ret = htonl(ret);
|
|
memcpy(&val, &ret, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
inline float ntohf(float val)
|
|
{
|
|
uint32_t ret;
|
|
memcpy(&ret, &val, sizeof(ret));
|
|
ret = ntohl(ret);
|
|
memcpy(&val, &ret, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
inline double htond(double val)
|
|
{
|
|
uint64_t ret;
|
|
memcpy(&ret, &val, sizeof(ret));
|
|
ret = htonll(ret);
|
|
memcpy(&val, &ret, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
inline double ntohd(double val)
|
|
{
|
|
uint64_t ret;
|
|
memcpy(&ret, &val, sizeof(ret));
|
|
ret = ntohll(ret);
|
|
memcpy(&val, &ret, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
inline bool set_unix_socket_blocking(int32_t socket_descriptor, bool is_blocking_already, bool should_block)
|
|
{
|
|
//Don't update it if we're already in that mode
|
|
if(should_block == is_blocking_already)
|
|
return true;
|
|
|
|
//Different API calls needed for both windows and unix
|
|
#ifdef WIN32
|
|
u_long non_blocking = should_block ? 0 : 1;
|
|
int ret = ioctlsocket(socket_descriptor, FIONBIO, &non_blocking);
|
|
if(ret != 0)
|
|
return false;
|
|
#else
|
|
int flags = fcntl(socket_descriptor, F_GETFL, 0);
|
|
if(flags < 0)
|
|
return false;
|
|
flags = fcntl(socket_descriptor, F_SETFL, is_blocking_already ? flags ^ O_NONBLOCK : flags ^= O_NONBLOCK);
|
|
if(flags < 0)
|
|
return false;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
static UNUSED_VAR void init_wsa()
|
|
{
|
|
#ifdef _WIN32
|
|
static WSADATA wsaData = WSAData();
|
|
static std::atomic<uint32_t> instance_count{0};
|
|
if(instance_count++ == 0)
|
|
{
|
|
int wsa_result = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
if(wsa_result != 0)
|
|
{
|
|
throw std::runtime_error("Failed to initialise WSA: " + std::to_string(wsa_result));
|
|
}
|
|
}
|
|
#else
|
|
signal(SIGPIPE, SIG_IGN);
|
|
#endif
|
|
}
|
|
|
|
|
|
#endif //FRNETLIB_NETWORKENCODING_H
|