2020-11-21 12:52:38 -05:00
|
|
|
/*!
|
|
|
|
* @file xsocket.cpp
|
|
|
|
* Cross platform socket library used for the listener.
|
|
|
|
*/
|
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
// clang-format off
|
2020-09-07 19:58:54 -04:00
|
|
|
#ifdef __linux
|
|
|
|
#include <netinet/tcp.h>
|
2022-06-22 23:37:46 -04:00
|
|
|
#include <sys/socket.h>
|
2020-09-07 19:58:54 -04:00
|
|
|
#include <unistd.h>
|
|
|
|
#elif _WIN32
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <WinSock2.h>
|
|
|
|
#include <WS2tcpip.h>
|
|
|
|
#endif
|
2020-09-08 19:15:14 -04:00
|
|
|
#include <errno.h>
|
2020-09-08 00:01:46 -04:00
|
|
|
#include <stdio.h>
|
2020-09-08 19:15:14 -04:00
|
|
|
#include <string.h>
|
2020-09-08 00:01:46 -04:00
|
|
|
|
2022-05-06 18:19:37 -04:00
|
|
|
#include "third-party/fmt/core.h"
|
2022-10-01 11:58:36 -04:00
|
|
|
#include "common/log/log.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
// clang-format on
|
2022-05-06 18:19:37 -04:00
|
|
|
|
2020-09-08 00:01:46 -04:00
|
|
|
int open_socket(int af, int type, int protocol) {
|
|
|
|
#ifdef __linux
|
|
|
|
return socket(af, type, protocol);
|
|
|
|
#elif _WIN32
|
|
|
|
WSADATA wsaData = {0};
|
|
|
|
int iResult = 0;
|
|
|
|
// Initialize Winsock
|
|
|
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
|
|
if (iResult != 0) {
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::error("WSAStartup failed: {}", iResult);
|
2020-09-08 00:01:46 -04:00
|
|
|
return 1;
|
|
|
|
}
|
2020-09-08 14:12:04 -04:00
|
|
|
return socket(af, type, protocol);
|
2020-09-08 00:01:46 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-06-11 11:32:27 -04:00
|
|
|
int connect_socket(int socket, sockaddr* addr, int nameLen) {
|
|
|
|
int result = connect(socket, addr, nameLen);
|
|
|
|
if (result == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-05-06 18:19:37 -04:00
|
|
|
#ifdef __linux
|
|
|
|
int accept_socket(int socket, sockaddr* addr, socklen_t* addrLen) {
|
|
|
|
return accept(socket, addr, addrLen);
|
|
|
|
}
|
2022-05-21 15:49:01 -04:00
|
|
|
int select_and_accept_socket(int socket, sockaddr* addr, socklen_t* addrLen, int microSeconds) {
|
|
|
|
struct timeval timeout;
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = microSeconds;
|
|
|
|
// Use select so it can timeout, accept on the returned socket if it is correct
|
|
|
|
fd_set read_sockets;
|
|
|
|
FD_ZERO(&read_sockets);
|
|
|
|
FD_SET(socket, &read_sockets);
|
|
|
|
auto activity = select(socket + 1, &read_sockets, NULL, NULL, &timeout);
|
|
|
|
if (activity > 0) {
|
|
|
|
return accept(socket, addr, addrLen);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2022-05-06 18:19:37 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
int accept_socket(int socket, sockaddr* addr, int* addrLen) {
|
|
|
|
WSADATA wsaData = {0};
|
|
|
|
int iResult = 0;
|
|
|
|
// Initialize Winsock
|
|
|
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
|
|
if (iResult != 0) {
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::error("WSAStartup failed: {}", iResult);
|
2022-05-06 18:19:37 -04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return accept(socket, addr, addrLen);
|
|
|
|
}
|
2022-05-21 15:49:01 -04:00
|
|
|
|
|
|
|
int select_and_accept_socket(int socket, sockaddr* addr, int* addrLen, int microSeconds) {
|
|
|
|
WSADATA wsaData = {0};
|
|
|
|
int iResult = 0;
|
|
|
|
// Initialize Winsock
|
|
|
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
|
|
if (iResult != 0) {
|
|
|
|
printf("WSAStartup failed: %d\n", iResult);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
struct timeval timeout;
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = microSeconds;
|
|
|
|
// Use select so it can timeout, accept on the returned socket if it is correct
|
|
|
|
fd_set read_sockets;
|
|
|
|
FD_ZERO(&read_sockets);
|
|
|
|
FD_SET(socket, &read_sockets);
|
|
|
|
auto activity = select(socket + 1, &read_sockets, NULL, NULL, &timeout);
|
|
|
|
if (activity > 0) {
|
|
|
|
return accept(socket, addr, addrLen);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2022-05-06 18:19:37 -04:00
|
|
|
#endif
|
|
|
|
|
2020-09-07 19:58:54 -04:00
|
|
|
void close_socket(int sock) {
|
|
|
|
if (sock < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef __linux
|
|
|
|
close(sock);
|
|
|
|
#elif _WIN32
|
|
|
|
closesocket(sock);
|
2020-09-08 00:01:46 -04:00
|
|
|
WSACleanup();
|
2020-09-07 19:58:54 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-09-08 19:15:14 -04:00
|
|
|
int set_socket_option(int socket, int level, int optname, const void* optval, int optlen) {
|
2020-09-08 20:49:37 -04:00
|
|
|
int ret = setsockopt(socket, level, optname, (const char*)optval, optlen);
|
2020-09-08 19:15:14 -04:00
|
|
|
if (ret < 0) {
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::error("Failed to setsockopt({},{}, {}, _, _) - Error: {}", socket, level, optname,
|
|
|
|
strerror(errno));
|
2020-09-08 19:15:14 -04:00
|
|
|
}
|
|
|
|
#ifdef _WIN32
|
2020-09-08 00:01:46 -04:00
|
|
|
if (ret < 0) {
|
2020-09-08 14:12:04 -04:00
|
|
|
int err = WSAGetLastError();
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::error("WSAGetLastError: {}", err);
|
2020-09-08 14:12:04 -04:00
|
|
|
}
|
2020-09-07 19:58:54 -04:00
|
|
|
#endif
|
2020-09-08 19:15:14 -04:00
|
|
|
return ret;
|
2020-09-07 19:58:54 -04:00
|
|
|
}
|
|
|
|
|
2020-09-08 19:15:14 -04:00
|
|
|
int set_socket_timeout(int socket, long microSeconds) {
|
2020-09-08 14:17:15 -04:00
|
|
|
#ifdef __linux
|
2020-09-08 19:15:14 -04:00
|
|
|
struct timeval timeout = {};
|
2020-09-08 14:17:15 -04:00
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = microSeconds;
|
2020-09-08 19:15:14 -04:00
|
|
|
int ret = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (struct timeval*)&timeout, sizeof(timeout));
|
|
|
|
if (ret < 0) {
|
|
|
|
printf("Failed to setsockopt(%d, %d, %d, _, _) - Error: %s\n", socket, SOL_SOCKET, SO_RCVTIMEO,
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
return ret;
|
2020-09-08 14:17:15 -04:00
|
|
|
#elif _WIN32
|
2020-09-08 20:46:09 -04:00
|
|
|
DWORD timeout = microSeconds / 1000; // milliseconds
|
2020-09-08 19:15:14 -04:00
|
|
|
return set_socket_option(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
2020-09-08 14:17:15 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-09-07 19:58:54 -04:00
|
|
|
int write_to_socket(int socket, const char* buf, int len) {
|
2022-05-06 18:19:37 -04:00
|
|
|
int bytes_wrote = 0;
|
2020-09-07 19:58:54 -04:00
|
|
|
#ifdef __linux
|
2022-06-11 16:52:27 -04:00
|
|
|
bytes_wrote = send(socket, buf, len, MSG_NOSIGNAL);
|
2020-09-07 19:58:54 -04:00
|
|
|
#elif _WIN32
|
2022-05-06 18:19:37 -04:00
|
|
|
bytes_wrote = send(socket, buf, len, 0);
|
2020-09-07 19:58:54 -04:00
|
|
|
#endif
|
2022-05-06 18:19:37 -04:00
|
|
|
if (bytes_wrote < 0) {
|
2022-10-01 11:58:36 -04:00
|
|
|
lg::error("[XSocket:{}] Error writing to socket", socket);
|
2022-05-06 18:19:37 -04:00
|
|
|
}
|
|
|
|
return bytes_wrote;
|
2020-09-07 19:58:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int read_from_socket(int socket, char* buf, int len) {
|
|
|
|
#ifdef __linux
|
|
|
|
return read(socket, buf, len);
|
|
|
|
#elif _WIN32
|
|
|
|
return recv(socket, buf, len, 0);
|
|
|
|
#endif
|
2020-09-08 00:01:46 -04:00
|
|
|
}
|
2020-09-09 20:14:13 -04:00
|
|
|
|
|
|
|
bool socket_timed_out() {
|
|
|
|
#ifdef __linux
|
|
|
|
return errno == EAGAIN;
|
|
|
|
#elif _WIN32
|
|
|
|
auto err = WSAGetLastError();
|
|
|
|
return err == WSAETIMEDOUT;
|
|
|
|
#endif
|
2022-05-06 18:19:37 -04:00
|
|
|
}
|