Files
jak-project/common/cross_sockets/XSocket.cpp
T
Tyler Wilding a0a85eb60a repl: Add a few new quality of life improvements (#2030)
- You can define a `startup.gc` in your user folder, each line will be
executed on startup (deprecates the usefulness of some cli flags)
- You can define a `repl-config.json` file to override REPL settings.
Long-term this is a better approach than a bunch of CLI flags as well
- Via this, you can override the amount of time the repl will attempt to
listen for the target
- At the same time, I think i may have found why on Windows it can
sometimes take forever to timeout when the game dies, will dig into this
later
- Added some keybinds for common operations, shown here


https://user-images.githubusercontent.com/13153231/202890278-1ff2bb06-dddf-4bde-9178-aa0883799167.mp4
> builds the game, connects to it, attaches a debugger and continues,
launches it, gets the backtrace, stops the target -- all with only
keybinds.

If you want these keybinds to work inside VSCode's integrated terminal,
you need to add the following to your settings file
```json
"terminal.integrated.commandsToSkipShell": [
    "-workbench.action.quickOpen",
    "-workbench.action.quickOpenView"
  ]
```
2022-11-20 14:28:41 -05:00

180 lines
4.5 KiB
C++

/*!
* @file xsocket.cpp
* Cross platform socket library used for the listener.
*/
// clang-format off
#ifdef __linux
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>
#elif _WIN32
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <WS2tcpip.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "third-party/fmt/core.h"
#include "common/log/log.h"
// clang-format on
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) {
lg::error("WSAStartup failed: {}", iResult);
return 1;
}
return socket(af, type, protocol);
#endif
}
int connect_socket(int socket, sockaddr* addr, int nameLen) {
int result = connect(socket, addr, nameLen);
if (result == -1) {
return -1;
}
return result;
}
#ifdef __linux
int accept_socket(int socket, sockaddr* addr, socklen_t* addrLen) {
return accept(socket, addr, addrLen);
}
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;
}
#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) {
lg::error("WSAStartup failed: {}", iResult);
return 1;
}
return accept(socket, addr, addrLen);
}
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;
}
#endif
void close_socket(int sock) {
if (sock < 0) {
return;
}
#ifdef __linux
close(sock);
#elif _WIN32
closesocket(sock);
WSACleanup();
#endif
}
int set_socket_option(int socket, int level, int optname, const void* optval, int optlen) {
int ret = setsockopt(socket, level, optname, (const char*)optval, optlen);
if (ret < 0) {
lg::error("Failed to setsockopt({},{}, {}, _, _) - Error: {}", socket, level, optname,
strerror(errno));
}
#ifdef _WIN32
if (ret < 0) {
int err = WSAGetLastError();
lg::error("WSAGetLastError: {}", err);
}
#endif
return ret;
}
int set_socket_timeout(int socket, long microSeconds) {
#ifdef __linux
struct timeval timeout = {};
timeout.tv_sec = 0;
timeout.tv_usec = microSeconds;
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;
#elif _WIN32
DWORD timeout = microSeconds / 1000; // milliseconds
// TODO - NOTE this might be bad / unreliable if the socket ends up being in a bad state
// select() instead should be used, will do so if ends up being an issue in practice
return set_socket_option(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
#endif
}
int write_to_socket(int socket, const char* buf, int len) {
int bytes_wrote = 0;
#ifdef __linux
bytes_wrote = send(socket, buf, len, MSG_NOSIGNAL);
#elif _WIN32
bytes_wrote = send(socket, buf, len, 0);
#endif
if (bytes_wrote < 0) {
lg::error("[XSocket:{}] Error writing to socket", socket);
}
return bytes_wrote;
}
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
}
bool socket_timed_out() {
#ifdef __linux
return errno == EAGAIN;
#elif _WIN32
auto err = WSAGetLastError();
return err == WSAETIMEDOUT;
#endif
}