Fixes timeouts causing disconnections (also helps with multi-client TCP support)

This commit is contained in:
beerpsi 2023-12-31 00:06:04 +07:00
parent c9484640d0
commit 2e0010d374

View File

@ -33,10 +33,7 @@ enum {
CARD_FELICA,
};
enum {
FUNCTION_COIN = 1,
FUNCTION_CARD
};
enum { FUNCTION_COIN = 1, FUNCTION_CARD };
typedef struct {
SOCKET sock;
@ -62,7 +59,8 @@ int socket_bind(SOCKET sHost, unsigned long addr, uint16_t port) {
return bind(sHost, (struct sockaddr *)&srcaddr, sizeof(srcaddr));
}
int socket_send_to(SOCKET sHost, const struct sockaddr_in* addr, const char* buf, int len) {
int socket_send_to(SOCKET sHost, const struct sockaddr_in *addr, const char *buf,
int len) {
return sendto(sHost, buf, len, 0, (struct sockaddr *)&addr, sizeof(&addr));
}
@ -81,7 +79,8 @@ void print_err(const char* fmt, ...) {
va_end(ap);
}
void get_socks_address(const struct PacketConnect* pkt, char* address, int address_len, uint16_t *port) {
void get_socks_address(const struct PacketConnect *pkt, char *address, int address_len,
uint16_t *port) {
if (!pkt || !address || !port) {
return;
}
@ -100,21 +99,21 @@ void get_socks_address(const struct PacketConnect* pkt, char* address, int addre
}
}
void update_packet_id(thread_ctx *ctx, uint32_t new_packet_id)
{
void update_packet_id(thread_ctx *ctx, uint32_t new_packet_id) {
if (ctx->last_input_packet_id > new_packet_id) {
print_err("[WARN] Packet #%" PRIu32 " came too late\n", new_packet_id);
} else if (new_packet_id > ctx->last_input_packet_id + 1) {
print_err("[WARN] Packets between #%" PRIu32 " and #%" PRIu32 " total %" PRIu32 " packet(s) are missing, probably too late or dropped\n",
ctx->last_input_packet_id, new_packet_id, new_packet_id - ctx->last_input_packet_id - 1);
print_err("[WARN] Packets between #%" PRIu32 " and #%" PRIu32 " total %" PRIu32
" packet(s) are missing, probably too late or dropped\n",
ctx->last_input_packet_id, new_packet_id,
new_packet_id - ctx->last_input_packet_id - 1);
} else if (new_packet_id == ctx->last_input_packet_id) {
print_err("[WARN] Packet #%" PRIu32 " duplicated\n", new_packet_id);
}
ctx->last_input_packet_id = new_packet_id;
}
void dump_bytes(const void *ptr, size_t nbytes, bool hex_string)
{
void dump_bytes(const void *ptr, size_t nbytes, bool hex_string) {
const uint8_t *bytes;
uint8_t c;
size_t i;
@ -206,7 +205,6 @@ unsigned int __stdcall thread_led_broadcast(void *v) {
uint8_t current_led_status[3 * 32];
while (!atomic_load(&ctx->exit_flag)) {
if (!atomic_load(&ctx->connected)) {
Sleep(50);
@ -233,16 +231,23 @@ unsigned int __stdcall thread_led_broadcast(void *v) {
print_err("[ERROR] Cannot send packet: error %lu\n", GetLastError());
if (tcp_mode) {
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
int error = WSAGetLastError();
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN ||
error == WSAETIMEDOUT) {
continue;
} else {
print_err("[INFO] Device disconnected!\n");
}
print_err("[INFO] Device disconnected (could not send packet), "
"error %d, os error %ld\n",
errno, error);
atomic_store(&ctx->connected, false);
atomic_store(&ctx->exit_flag, true);
break;
}
}
}
skip_count = 0;
}
@ -272,8 +277,9 @@ unsigned int __stdcall thread_input_recv(void *v) {
while (!atomic_load(&ctx->exit_flag)) {
if (!tcp_mode) {
/**
on UDP mode data is sent as packets, so just receive into a buffer big enough for 1 packet
each recvfrom call will only get 1 packet of data, the remaining data is discarded
on UDP mode data is sent as packets, so just receive into a buffer big
enough for 1 packet each recvfrom call will only get 1 packet of data, the
remaining data is discarded
**/
if ((recv_len = recvfrom(sHost, buffer, BUFSIZ - 1, 0, NULL, NULL)) == -1) {
@ -289,8 +295,8 @@ unsigned int __stdcall thread_input_recv(void *v) {
packet_len = real_len + 1;
} else {
/**
on TCP mode packets are length-prefixed, so we read in the first 4 bytes to
figure out how much we need to read, then read in the full data.
on TCP mode packets are length-prefixed, so we read in the first 4 bytes
to figure out how much we need to read, then read in the full data.
**/
recv_len = 0;
@ -298,15 +304,21 @@ unsigned int __stdcall thread_input_recv(void *v) {
int read = recv(sHost, buffer + recv_len, 4 - recv_len, 0);
if (read == -1) {
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
int error = WSAGetLastError();
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN ||
error == WSAETIMEDOUT) {
continue;
} else {
print_err("[INFO] Device disconnected!\n");
}
print_err("[INFO] Device disconnected (could not receive packet), "
"errno %d, os error %ld\n",
errno, error);
atomic_store(&ctx->connected, false);
atomic_store(&ctx->exit_flag, true);
break;
}
}
recv_len = recv_len + read;
}
@ -318,38 +330,49 @@ unsigned int __stdcall thread_input_recv(void *v) {
int read = recv(sHost, buffer + recv_len, packet_len - recv_len, 0);
if (read == -1) {
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
int error = WSAGetLastError();
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN ||
error == WSAETIMEDOUT) {
continue;
} else {
print_err("[INFO] Device disconnected!\n");
}
print_err("[INFO] Device disconnected (could not receive packet), "
"errno %d, os error %ld\n",
errno, error);
atomic_store(&ctx->connected, false);
atomic_store(&ctx->exit_flag, true);
break;
}
}
recv_len = recv_len + read;
}
}
if (packet_len >= sizeof(struct PacketInput) && buffer[1] == 'I' && buffer[2] == 'N' && buffer[3] == 'P') {
if (packet_len >= sizeof(struct PacketInput) && buffer[1] == 'I' &&
buffer[2] == 'N' && buffer[3] == 'P') {
struct PacketInput *pkt = (struct PacketInput *)buffer;
memcpy(memory->airIoStatus, pkt->airIoStatus, sizeof(pkt->airIoStatus));
memcpy(memory->sliderIoStatus, pkt->sliderIoStatus, sizeof(pkt->sliderIoStatus));
memcpy(memory->sliderIoStatus, pkt->sliderIoStatus,
sizeof(pkt->sliderIoStatus));
memory->testBtn = pkt->testBtn;
memory->serviceBtn = pkt->serviceBtn;
update_packet_id(ctx, ntohl(pkt->packetId));
} else if (packet_len >= sizeof(struct PacketInputNoAir) && buffer[1] == 'I' && buffer[2] == 'P' && buffer[3] == 'T') { // without air
} else if (packet_len >= sizeof(struct PacketInputNoAir) && buffer[1] == 'I' &&
buffer[2] == 'P' && buffer[3] == 'T') { // without air
struct PacketInputNoAir *pkt = (struct PacketInputNoAir *)buffer;
memcpy(memory->sliderIoStatus, pkt->sliderIoStatus, sizeof(pkt->sliderIoStatus));
memcpy(memory->sliderIoStatus, pkt->sliderIoStatus,
sizeof(pkt->sliderIoStatus));
memory->testBtn = pkt->testBtn;
memory->serviceBtn = pkt->serviceBtn;
update_packet_id(ctx, ntohl(pkt->packetId));
} else if (packet_len >= sizeof(struct PacketFunction) && buffer[1] == 'F' && buffer[2] == 'N' && buffer[3] == 'C') {
} else if (packet_len >= sizeof(struct PacketFunction) && buffer[1] == 'F' &&
buffer[2] == 'N' && buffer[3] == 'C') {
struct PacketFunction *pkt = (struct PacketFunction *)buffer;
switch (pkt->funcBtn) {
@ -360,28 +383,33 @@ unsigned int __stdcall thread_input_recv(void *v) {
memory->cardRead = 1;
break;
}
} else if (packet_len >= sizeof(struct PacketConnect) && buffer[1] == 'C' && buffer[2] == 'O' && buffer[3] == 'N') {
} else if (packet_len >= sizeof(struct PacketConnect) && buffer[1] == 'C' &&
buffer[2] == 'O' && buffer[3] == 'N') {
struct PacketConnect *pkt = (struct PacketConnect *)buffer;
get_socks_address(pkt, ctx->remote_address, BUFSIZ - 1, &ctx->remote_port);
print_err("[INFO] Device %s:%d connected.\n", ctx->remote_address, ctx->remote_port);
print_err("[INFO] Device %s:%d connected.\n", ctx->remote_address,
ctx->remote_port);
ctx->last_input_packet_id = 0;
atomic_store(&ctx->connected, true);
} else if (packet_len >= 4 && buffer[1] == 'D' && buffer[2] == 'I' && buffer[3] == 'S') {
} else if (packet_len >= 4 && buffer[1] == 'D' && buffer[2] == 'I' &&
buffer[3] == 'S') {
atomic_store(&ctx->connected, false);
if (tcp_mode) {
atomic_store(&ctx->exit_flag, true);
print_err("[INFO] Device disconnected!\n");
print_err("[INFO] Device disconnected (clean disconnect)\n");
break;
}
if (strlen(ctx->remote_address)) {
print_err("[INFO] Device %s:%d disconnected.\n", ctx->remote_address, ctx->remote_port);
print_err("[INFO] Device %s:%d disconnected.\n", ctx->remote_address,
ctx->remote_port);
memset(ctx->remote_address, 0, BUFSIZ);
}
} else if (packet_len >= sizeof(struct PacketPing) && buffer[1] == 'P' && buffer[2] == 'I' && buffer[3] == 'N') {
} else if (packet_len >= sizeof(struct PacketPing) && buffer[1] == 'P' &&
buffer[2] == 'I' && buffer[3] == 'N') {
if (!atomic_load(&ctx->connected)) {
continue;
}
@ -391,7 +419,8 @@ unsigned int __stdcall thread_input_recv(void *v) {
response[2] = 'O';
socket_send_to(sHost, &addr, response, 13);
} else if (packet_len >= sizeof(struct PacketCard) && buffer[1] == 'C' && buffer[2] == 'R' && buffer[3] == 'D') {
} else if (packet_len >= sizeof(struct PacketCard) && buffer[1] == 'C' &&
buffer[2] == 'R' && buffer[3] == 'D') {
struct PacketCard *pkt = (struct PacketCard *)buffer;
if (pkt->remoteCardRead) {
@ -426,16 +455,16 @@ unsigned int __stdcall server_thread_proc(void* ctx) {
print_err("[INFO] Waiting for device on port %d...\n", server_port);
thread_ctx args = {
.sock = sHost,
thread_ctx args = {.sock = sHost,
.exit_flag = ATOMIC_VAR_INIT(false),
.connected = ATOMIC_VAR_INIT(false),
.last_input_packet_id = 0,
.memory = memory
};
.memory = memory};
HANDLE led_thread = (HANDLE)_beginthreadex(NULL, 0, thread_led_broadcast, &args, 0, NULL);
HANDLE input_thread = (HANDLE)_beginthreadex(NULL, 0, thread_input_recv, &args, 0, NULL);
HANDLE led_thread =
(HANDLE)_beginthreadex(NULL, 0, thread_led_broadcast, &args, 0, NULL);
HANDLE input_thread =
(HANDLE)_beginthreadex(NULL, 0, thread_input_recv, &args, 0, NULL);
WaitForSingleObject(led_thread, INFINITE);
WaitForSingleObject(input_thread, INFINITE);
@ -458,24 +487,26 @@ unsigned int __stdcall server_thread_proc(void* ctx) {
for (;;) {
struct sockaddr_in user_socket = {};
socklen_t sock_size = sizeof(struct sockaddr_in);
SOCKET acc_socket = accept(sHost, (struct sockaddr *)&user_socket, &sock_size);
SOCKET acc_socket =
accept(sHost, (struct sockaddr *)&user_socket, &sock_size);
char buffer[20] = {};
const char* user_address = inet_ntop(AF_INET, &user_socket.sin_addr, buffer, 20);
const char *user_address =
inet_ntop(AF_INET, &user_socket.sin_addr, buffer, 20);
if (user_address != NULL) {
print_err("[INFO] Device %s:%d connected.\n", user_address, user_socket.sin_port);
print_err("[INFO] Device %s:%d connected.\n", user_address,
user_socket.sin_port);
}
thread_ctx args = {
.sock = acc_socket,
.exit_flag = ATOMIC_VAR_INIT(false),
.connected = ATOMIC_VAR_INIT(true),
.last_input_packet_id = 0,
.memory = memory
};
thread_ctx *args = malloc(sizeof(thread_ctx));
args->sock = acc_socket;
args->exit_flag = ATOMIC_VAR_INIT(false);
args->connected = ATOMIC_VAR_INIT(true);
args->last_input_packet_id = 0;
args->memory = memory;
_beginthreadex(NULL, 0, thread_led_broadcast, &args, 0, NULL);
_beginthreadex(NULL, 0, thread_input_recv, &args, 0, NULL);
_beginthreadex(NULL, 0, thread_led_broadcast, args, 0, NULL);
_beginthreadex(NULL, 0, thread_input_recv, args, 0, NULL);
}
#pragma clang diagnostic pop
}
@ -484,8 +515,10 @@ unsigned int __stdcall server_thread_proc(void* ctx) {
}
HRESULT server_start() {
tcp_mode = GetPrivateProfileIntW(L"brokenithm", L"tcp", 0, L".\\segatools.ini") == 1;
server_port = GetPrivateProfileIntW(L"brokenithm", L"port", 52468, L".\\segatools.ini");
tcp_mode =
GetPrivateProfileIntW(L"brokenithm", L"tcp", 0, L".\\segatools.ini") == 1;
server_port =
GetPrivateProfileIntW(L"brokenithm", L"port", 52468, L".\\segatools.ini");
struct WSAData wsaData = {};
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
@ -496,18 +529,21 @@ HRESULT server_start() {
HANDLE hMapFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, memFileName);
if (hMapFile == NULL) {
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, memFileName);
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
1024, memFileName);
if (hMapFile == NULL) {
print_err("[ERROR] CreateFileMapping failed! error: %lu\n", GetLastError());
return E_FAIL;
}
}
struct IPCMemoryInfo* memory = (struct IPCMemoryInfo*)MapViewOfFileEx(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024, NULL);
struct IPCMemoryInfo *memory = (struct IPCMemoryInfo *)MapViewOfFileEx(
hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024, NULL);
chuni_io_file_mapping = memory;
if (memory == NULL) {
print_err("[ERROR] Cannot get view of memory map! error: %lu\n", GetLastError());
print_err("[ERROR] Cannot get view of memory map! error: %lu\n",
GetLastError());
return E_FAIL;
}
@ -528,13 +564,19 @@ void chuni_io_init_shared_memory() {
return;
}
if ((chuni_io_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(struct IPCMemoryInfo), memFileName)) == 0) {
dprintf("chuni_io_init_shared_memory: could not create file mapping: %ld\n", GetLastError());
if ((chuni_io_file_mapping_handle =
CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
sizeof(struct IPCMemoryInfo), memFileName)) == 0) {
dprintf("chuni_io_init_shared_memory: could not create file mapping: %ld\n",
GetLastError());
return;
}
if ((chuni_io_file_mapping = (struct IPCMemoryInfo*)MapViewOfFile(chuni_io_file_mapping_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct IPCMemoryInfo))) == 0) {
dprintf("chuni_io_init_shared_memory: could not get view of file: %ld\n", GetLastError());
if ((chuni_io_file_mapping = (struct IPCMemoryInfo *)MapViewOfFile(
chuni_io_file_mapping_handle, FILE_MAP_ALL_ACCESS, 0, 0,
sizeof(struct IPCMemoryInfo))) == 0) {
dprintf("chuni_io_init_shared_memory: could not get view of file: %ld\n",
GetLastError());
return;
}
@ -543,7 +585,6 @@ void chuni_io_init_shared_memory() {
}
#endif
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx);
static bool chuni_io_coin;
@ -553,9 +594,7 @@ static HANDLE chuni_io_slider_thread;
static bool chuni_io_slider_stop_flag;
static struct chuni_io_config chuni_io_cfg;
uint16_t chuni_io_get_api_version() {
return 0x0102;
}
uint16_t chuni_io_get_api_version() { return 0x0102; }
HRESULT chuni_io_jvs_init() {
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
@ -598,11 +637,13 @@ void chuni_io_jvs_read_coin_counter(uint16_t *out) {
void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) {
size_t i;
if ((chuni_io_file_mapping && chuni_io_file_mapping->testBtn) || GetAsyncKeyState(chuni_io_cfg.vk_test)) {
if ((chuni_io_file_mapping && chuni_io_file_mapping->testBtn) ||
GetAsyncKeyState(chuni_io_cfg.vk_test)) {
*opbtn |= CHUNI_IO_OPBTN_TEST; /* Test */
}
if ((chuni_io_file_mapping && chuni_io_file_mapping->serviceBtn) || GetAsyncKeyState(chuni_io_cfg.vk_service)) {
if ((chuni_io_file_mapping && chuni_io_file_mapping->serviceBtn) ||
GetAsyncKeyState(chuni_io_cfg.vk_service)) {
*opbtn |= CHUNI_IO_OPBTN_SERVICE; /* Service */
}
@ -631,22 +672,15 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) {
}
}
HRESULT chuni_io_slider_init() {
return S_OK;
}
HRESULT chuni_io_slider_init() { return S_OK; }
void chuni_io_slider_start(void *callback) {
if (chuni_io_slider_thread != NULL) {
return;
}
chuni_io_slider_thread = (HANDLE) _beginthreadex(
NULL,
0,
chuni_io_slider_thread_proc,
callback,
0,
NULL);
chuni_io_slider_thread =
(HANDLE)_beginthreadex(NULL, 0, chuni_io_slider_thread_proc, callback, 0, NULL);
}
void chuni_io_slider_stop(void) {
@ -668,14 +702,11 @@ void chuni_io_slider_set_leds(const uint8_t *rgb) {
}
}
HRESULT chuni_io_led_init(void) {
return S_OK;
}
HRESULT chuni_io_led_init(void) { return S_OK; }
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb) {}
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
{
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) {
chuni_io_slider_callback_t callback;
uint8_t pressure[32];