From 1ab8329e3c52155fea6f6d558618597f77e44da8 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Mon, 7 Sep 2020 19:58:54 -0400 Subject: [PATCH 1/8] Created a cross-platform socket shim --- common/cross_sockets/CMakeLists.txt | 12 ++++++++ common/cross_sockets/xsocket.cpp | 45 +++++++++++++++++++++++++++++ common/cross_sockets/xsocket.h | 18 ++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 common/cross_sockets/CMakeLists.txt create mode 100644 common/cross_sockets/xsocket.cpp create mode 100644 common/cross_sockets/xsocket.h diff --git a/common/cross_sockets/CMakeLists.txt b/common/cross_sockets/CMakeLists.txt new file mode 100644 index 000000000..f97ddd0f8 --- /dev/null +++ b/common/cross_sockets/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(cross_sockets + SHARED + "xsocket.h" + "xsocket.cpp") + +IF (WIN32) + # set stuff for windows + target_link_libraries(cross_sockets wsock32 ws2_32) +ELSE() + # set stuff for other systems + target_link_libraries(cross_sockets) +ENDIF() diff --git a/common/cross_sockets/xsocket.cpp b/common/cross_sockets/xsocket.cpp new file mode 100644 index 000000000..010550d2c --- /dev/null +++ b/common/cross_sockets/xsocket.cpp @@ -0,0 +1,45 @@ +#ifdef __linux +#include +#include +#include +#elif _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +void close_socket(int sock) { + if (sock < 0) { + return; + } +#ifdef __linux + close(sock); +#elif _WIN32 + closesocket(sock); +#endif +} + +int set_socket_option(int socket, int level, int optname, int optval, int optlen) { +#ifdef __linux + return setsockopt(socket, level, optname, &optval, optlen); +#elif _WIN32 + const char optVal = optval; + return setsockopt(socket, level, optname, &optVal, optlen); +#endif +} + +int write_to_socket(int socket, const char* buf, int len) { +#ifdef __linux + return write(socket, buf, len); +#elif _WIN32 + return send(socket, buf, len, 0); +#endif +} + +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 +} \ No newline at end of file diff --git a/common/cross_sockets/xsocket.h b/common/cross_sockets/xsocket.h new file mode 100644 index 000000000..fa1e5b4e7 --- /dev/null +++ b/common/cross_sockets/xsocket.h @@ -0,0 +1,18 @@ +#ifdef __linux +#include +#include +#include +#elif _WIN32 +#include +#endif + +#ifdef __linux +const int TCP_SOCKET_LEVEL = SOL_TCP; +#elif _WIN32 +const int TCP_SOCKET_LEVEL = IPPROTO_IP; +#endif + +void close_socket(int sock); +int set_socket_option(int socket, int level, int optname, int optval, int optlen); +int write_to_socket(int socket, const char* buf, int len); +int read_from_socket(int socket, char* buf, int len); From 84e0bee6f4bf14971fb916a0f48be58ab3ec2bf7 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Mon, 7 Sep 2020 19:59:44 -0400 Subject: [PATCH 2/8] Use shim in Listener/Deci2Server --- CMakeLists.txt | 3 ++ game/CMakeLists.txt | 5 +-- game/system/Deci2Server.cpp | 79 ++++++++++++++++++++---------------- game/system/Deci2Server.h | 11 +++-- goalc/CMakeLists.txt | 18 +++----- goalc/listener/Listener.cpp | 42 +++++++++++-------- test/CMakeLists.txt | 7 ++-- test/test_listener_deci2.cpp | 4 -- 8 files changed, 88 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b40377dc4..32fea0bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,9 @@ add_subdirectory(asset_tool) # build type_system library for compiler/decompiler add_subdirectory(common/type_system) +# build cross platform socket library +add_subdirectory(common/cross_sockets) + # build decompiler add_subdirectory(decompiler) diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 59cacdf7a..3a18ddf0c 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -76,11 +76,10 @@ add_executable(gk ${RUNTIME_SOURCE} main.cpp) # can be used to test other things. add_library(runtime ${RUNTIME_SOURCE}) - IF (WIN32) # set stuff for windows - target_link_libraries(gk mman) + target_link_libraries(gk cross_sockets mman) ELSE() # set stuff for other systems - target_link_libraries(gk pthread) + target_link_libraries(gk cross_sockets) ENDIF() diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index 600f34462..2618d2404 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -4,15 +4,22 @@ * Works with deci2.cpp (sceDeci2) to implement the networking on target */ -// TODO-WINDOWS -#ifdef __linux__ #include +#include +#include + +// TODO - i think im not including the dependency right..? +#include "common/cross_sockets/xsocket.h" + +#ifdef __linux #include #include #include -#include -#include +#elif _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif #include "common/listener_common.h" #include "common/versions.h" @@ -33,38 +40,39 @@ Deci2Server::~Deci2Server() { delete[] buffer; - if (server_fd >= 0) { - close(server_fd); - } - - if (new_sock >= 0) { - close(new_sock); - } + close_server_socket(); + close_socket(new_sock); } /*! * Start waiting for the Listener to connect */ bool Deci2Server::init() { - server_fd = socket(AF_INET, SOCK_STREAM, 0); - if (server_fd < 0) { - server_fd = -1; + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket < 0) { + server_socket = -1; return false; } +#ifdef __linux + int server_socket_opt = SO_REUSEADDR | SO_REUSEPORT; + int server_socket_tcp_level = SOL_TCP; +#elif _WIN32 + int server_socket_opt = SO_REUSEADDR | SO_BROADCAST; + int server_socket_tcp_level = IPPROTO_IP; +#endif + int opt = 1; - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { + if (set_socket_option(server_socket, SOL_SOCKET, server_socket_opt, opt, sizeof(opt))) { printf("[Deci2Server] Failed to setsockopt 1\n"); - close(server_fd); - server_fd = -1; + close_server_socket(); return false; } int one = 1; - if (setsockopt(server_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { + if (set_socket_option(server_socket, server_socket_tcp_level, TCP_NODELAY, one, sizeof(one))) { printf("[Deci2Server] Failed to setsockopt 2\n"); - close(server_fd); - server_fd = -1; + close_server_socket(); return false; } @@ -72,10 +80,9 @@ bool Deci2Server::init() { timeout.tv_sec = 0; timeout.tv_usec = 100000; - if (setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { + if (setsockopt(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { printf("[Deci2Server] Failed to setsockopt 3\n"); - close(server_fd); - server_fd = -1; + close_server_socket(); return false; } @@ -83,17 +90,15 @@ bool Deci2Server::init() { addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(DECI2_PORT); - if (bind(server_fd, (sockaddr*)&addr, sizeof(addr)) < 0) { + if (bind(server_socket, (sockaddr*)&addr, sizeof(addr)) < 0) { printf("[Deci2Server] Failed to bind\n"); - close(server_fd); - server_fd = -1; + close_server_socket(); return false; } - if (listen(server_fd, 0) < 0) { + if (listen(server_socket, 0) < 0) { printf("[Deci2Server] Failed to listen\n"); - close(server_fd); - server_fd = -1; + close_server_socket(); return false; } @@ -104,6 +109,11 @@ bool Deci2Server::init() { return true; } +void Deci2Server::close_server_socket() { + close_socket(server_socket); + server_socket = -1; +} + /*! * Return true if the listener is connected. */ @@ -129,7 +139,7 @@ void Deci2Server::send_data(void* buf, u16 len) { } else { uint16_t prog = 0; while (prog < len) { - auto wrote = write(new_sock, (char*)(buf) + prog, len - prog); + int wrote = write_to_socket(new_sock, (char*)(buf) + prog, len - prog); prog += wrote; if (!server_connected || want_exit()) { unlock(); @@ -186,7 +196,7 @@ void Deci2Server::run() { while (got < desired_size) { assert(got + desired_size < BUFFER_SIZE); - auto x = read(new_sock, buffer + got, desired_size - got); + auto x = read_from_socket(new_sock, buffer + got, desired_size - got); if (want_exit()) { return; } @@ -237,7 +247,7 @@ void Deci2Server::run() { // receive from network if (hdr->rsvd < hdr->len) { - auto x = read(new_sock, buffer + hdr->rsvd, hdr->len - hdr->rsvd); + auto x = read_from_socket(new_sock, buffer + hdr->rsvd, hdr->len - hdr->rsvd); if (want_exit()) { return; } @@ -256,13 +266,12 @@ void Deci2Server::run() { void Deci2Server::accept_thread_func() { socklen_t l = sizeof(addr); while (!kill_accept_thread) { - new_sock = accept(server_fd, (sockaddr*)&addr, &l); + new_sock = accept(server_socket, (sockaddr*)&addr, &l); if (new_sock >= 0) { u32 versions[2] = {versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR}; - send(new_sock, &versions, 8, 0); // todo, check result? + write_to_socket(new_sock, (char*)&versions, 8); // todo, check result? server_connected = true; return; } } } -#endif \ No newline at end of file diff --git a/game/system/Deci2Server.h b/game/system/Deci2Server.h index 8695ff020..c8ddbaa1d 100644 --- a/game/system/Deci2Server.h +++ b/game/system/Deci2Server.h @@ -4,11 +4,14 @@ * Works with deci2.cpp (sceDeci2) to implement the networking on target */ -#ifdef __linux__ #ifndef JAK1_DECI2SERVER_H #define JAK1_DECI2SERVER_H +#ifdef __linux #include +#elif _WIN32 +#include +#endif #include #include #include @@ -32,11 +35,12 @@ class Deci2Server { void run(); private: + void close_server_socket(); void accept_thread_func(); bool kill_accept_thread = false; char* buffer = nullptr; - int server_fd = -1; - sockaddr_in addr; + int server_socket = -1; + struct sockaddr_in addr = {}; int new_sock = -1; bool server_initialized = false; bool accept_thread_running = false; @@ -52,4 +56,3 @@ class Deci2Server { }; #endif // JAK1_DECI2SERVER_H -#endif diff --git a/goalc/CMakeLists.txt b/goalc/CMakeLists.txt index 21b3fcb92..ee0a59f2f 100644 --- a/goalc/CMakeLists.txt +++ b/goalc/CMakeLists.txt @@ -1,12 +1,6 @@ add_subdirectory(util) add_subdirectory(goos) - -IF (WIN32) - # TODO - implement windows listener - message("Windows Listener Not Implemented!") -ELSE() - add_subdirectory(listener) -ENDIF() +add_subdirectory(listener) add_library(compiler SHARED @@ -26,12 +20,10 @@ add_library(compiler compiler/Compiler.cpp ) -add_executable(goalc main.cpp - ) +add_executable(goalc main.cpp) IF (WIN32) - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) - target_link_libraries(compiler util goos type_system mman) + target_link_libraries(compiler cross_sockets util goos type_system mman) +ELSE() + target_link_libraries(compiler cross_sockets util goos goalc type_system) ENDIF() - -target_link_libraries(goalc util goos compiler type_system) diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index 2a53f2661..709d5ab5b 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -3,13 +3,20 @@ * The Listener can connect to a Deci2Server for debugging. */ -// TODO-Windows -#ifdef __linux__ - -#include +#ifdef __linux #include #include #include +#elif _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +// TODO - i think im not including the dependency right..? +#include "common/cross_sockets/xsocket.h" + +#include #include #include "Listener.h" #include "common/versions.h" @@ -27,7 +34,7 @@ Listener::~Listener() { delete[] m_buffer; if (socket_fd >= 0) { - close(socket_fd); + close_socket(socket_fd); } } @@ -53,7 +60,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { } if (socket_fd >= 0) { - close(socket_fd); + close_socket(socket_fd); } // construct socket @@ -70,16 +77,16 @@ bool Listener::connect_to_target(const std::string& ip, int port) { timeout.tv_usec = 100000; if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { printf("[Listener] setsockopt failed\n"); - close(socket_fd); + close_socket(socket_fd); socket_fd = -1; return false; } // set nodelay, which makes small rapid messages faster, but large messages slower int one = 1; - if (setsockopt(socket_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { + if (set_socket_option(socket_fd, TCP_SOCKET_LEVEL, TCP_NODELAY, one, sizeof(one))) { printf("[Listener] failed to TCP_NODELAY\n"); - close(socket_fd); + close_socket(socket_fd); socket_fd = -1; return false; } @@ -90,7 +97,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { server_address.sin_port = htons(port); if (inet_pton(AF_INET, ip.c_str(), &server_address.sin_addr) <= 0) { printf("[Listener] Invalid IP address.\n"); - close(socket_fd); + close_socket(socket_fd); socket_fd = -1; return false; } @@ -99,7 +106,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { int rv = connect(socket_fd, (sockaddr*)&server_address, sizeof(server_address)); if (rv < 0) { printf("[Listener] Failed to connect\n"); - close(socket_fd); + close_socket(socket_fd); socket_fd = -1; return false; } @@ -110,7 +117,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { int prog = 0; bool ok = true; while (prog < 8) { - auto r = read(socket_fd, version_buffer + prog, 8 - prog); + auto r = read_from_socket(socket_fd, (char*)version_buffer + prog, 8 - prog); if (r < 0) { ok = false; break; @@ -124,7 +131,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { } if (!ok) { printf("[Listener] Failed to get version number\n"); - close(socket_fd); + close_socket(socket_fd); socket_fd = -1; return false; } @@ -138,7 +145,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { return true; } else { printf(", expected %d.%d. Cannot connect.\n", GOAL_VERSION_MAJOR, GOAL_VERSION_MINOR); - close(socket_fd); + close_socket(socket_fd); socket_fd = -1; return false; } @@ -155,7 +162,7 @@ void Listener::receive_func() { int rcvd_desired = sizeof(ListenerMessageHeader); char buff[sizeof(ListenerMessageHeader)]; while (rcvd < rcvd_desired) { - auto got = read(socket_fd, buff + rcvd, rcvd_desired - rcvd); + auto got = read_from_socket(socket_fd, buff + rcvd, rcvd_desired - rcvd); rcvd += got > 0 ? got : 0; // kick us out if we got a bogus read result @@ -188,7 +195,7 @@ void Listener::receive_func() { while (rcvd < hdr->deci2_header.len) { if (!m_connected) return; - int got = read(socket_fd, ack_recv_buff + ack_recv_prog, hdr->deci2_header.len - rcvd); + int got = read_from_socket(socket_fd, ack_recv_buff + ack_recv_prog, hdr->deci2_header.len - rcvd); got = got > 0 ? got : 0; rcvd += got; ack_recv_prog += got; @@ -210,7 +217,7 @@ void Listener::receive_func() { return; } - int got = read(socket_fd, str_buff + msg_prog, hdr->deci2_header.len - rcvd); + int got = read_from_socket(socket_fd, str_buff + msg_prog, hdr->deci2_header.len - rcvd); got = got > 0 ? got : 0; rcvd += got; msg_prog += got; @@ -242,4 +249,3 @@ void Listener::receive_func() { } } // namespace listener -#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8173c9820..05bcf9570 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,9 +18,8 @@ add_executable(goalc-test IF (WIN32) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - # TODO - implement windows listener - message("Windows Listener Not Implemented!") - target_link_libraries(goalc-test mman goos util runtime compiler type_system gtest) + # TODO - split out these declarations for platform specific includes + target_link_libraries(goalc-test cross_sockets listener mman goos util runtime compiler type_system gtest) ELSE() - target_link_libraries(goalc-test goos util listener runtime compiler type_system gtest) + target_link_libraries(goalc-test cross_sockets goos util listener runtime compiler type_system gtest) ENDIF() diff --git a/test/test_listener_deci2.cpp b/test/test_listener_deci2.cpp index d7b65cba2..99874e3d0 100644 --- a/test/test_listener_deci2.cpp +++ b/test/test_listener_deci2.cpp @@ -1,5 +1,3 @@ -#ifdef __linux__ - #include "gtest/gtest.h" #include "goalc/listener/Listener.h" #include "game/system/Deci2Server.h" @@ -126,5 +124,3 @@ TEST(Listener, ListenerMultipleDecis) { l.disconnect(); } } - -#endif \ No newline at end of file From aea7b692e43f9ce94dbb631c95482cfac8a98edc Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Mon, 7 Sep 2020 20:00:02 -0400 Subject: [PATCH 3/8] Got rid of a lot of windows ifdefs --- game/kernel/kboot.cpp | 12 ++++-------- game/kernel/kdsnetm.cpp | 3 --- game/kernel/kdsnetm.h | 7 ------- game/kernel/klisten.cpp | 10 +--------- game/kernel/kmachine.cpp | 6 ------ game/kernel/ksocket.cpp | 3 --- game/runtime.cpp | 15 +++------------ game/sce/deci2.cpp | 33 --------------------------------- 8 files changed, 8 insertions(+), 81 deletions(-) diff --git a/game/kernel/kboot.cpp b/game/kernel/kboot.cpp index 9f6f6de06..1cd2cc1a1 100644 --- a/game/kernel/kboot.cpp +++ b/game/kernel/kboot.cpp @@ -5,6 +5,9 @@ */ #include +#include +#include + #include "common/common_types.h" #include "game/sce/libscf.h" #include "kboot.h" @@ -134,21 +137,14 @@ void KernelCheckAndDispatch() { // dispatch the kernel //(**kernel_dispatcher)(); call_goal(Ptr(kernel_dispatcher->value), 0, 0, 0, s7.offset, g_ee_main_mem); - // TODO-WINDOWS -#ifdef __linux__ ClearPending(); -#endif // if the listener function changed, it means the kernel ran it, so we should notify compiler. if (MasterDebug && ListenerFunction->value != old_listener) { SendAck(); } -#ifdef _WIN32 - Sleep(1000); // todo - remove this -#elif __linux__ - usleep(1000); -#endif + std::this_thread::sleep_for(std::chrono::microseconds(1000)); } } diff --git a/game/kernel/kdsnetm.cpp b/game/kernel/kdsnetm.cpp index 2d06a9316..da07a7a8b 100644 --- a/game/kernel/kdsnetm.cpp +++ b/game/kernel/kdsnetm.cpp @@ -27,8 +27,6 @@ void kdsnetm_init_globals() { protoBlock.reset(); } -// TODO-WINDOWS -#ifdef __linux__ /*! * Register GOAL DECI2 Protocol Driver with DECI2 service * DONE, EXACT @@ -222,4 +220,3 @@ void GoalProtoStatus() { Msg(6, "gproto: got %d %d\n", protoBlock.most_recent_event, protoBlock.most_recent_param); Msg(6, "gproto: %d %d\n", protoBlock.last_receive_size, protoBlock.send_remaining); } -#endif \ No newline at end of file diff --git a/game/kernel/kdsnetm.h b/game/kernel/kdsnetm.h index 51125e0c1..bdbef6609 100644 --- a/game/kernel/kdsnetm.h +++ b/game/kernel/kdsnetm.h @@ -51,8 +51,6 @@ extern GoalProtoBlock protoBlock; */ void kdsnetm_init_globals(); -// TODO-WINDOWS -#ifdef __linux__ /*! * Register GOAL DECI2 Protocol Driver with DECI2 service * DONE, EXACT @@ -65,8 +63,6 @@ void InitGoalProto(); */ void ShutdownGoalProto(); -#endif - /*! * Handle a DECI2 Protocol Event for the GOAL Proto. * Called by the DECI2 Protocol driver @@ -74,8 +70,6 @@ void ShutdownGoalProto(); */ void GoalProtoHandler(int event, int param, void* data); -// TODO-WINDOWS -#ifdef __linux__ /*! * Low level DECI2 send * Will block until send is complete. @@ -83,7 +77,6 @@ void GoalProtoHandler(int event, int param, void* data); * removed */ s32 SendFromBufferD(s32 p1, u64 p2, char* data, s32 size); -#endif /*! * Print GOAL Protocol status diff --git a/game/kernel/klisten.cpp b/game/kernel/klisten.cpp index 7f990bf27..4f1d733bb 100644 --- a/game/kernel/klisten.cpp +++ b/game/kernel/klisten.cpp @@ -71,10 +71,7 @@ void ClearPending() { Ptr msg = OutputBufArea.cast() + sizeof(GoalMessageHeader); auto size = strlen(msg.c()); // note - if size is ever greater than 2^16 this will cause an issue. - // TODO-WINDOWS -#ifdef __linux__ SendFromBuffer(msg.c(), size); -#endif clear_output(); } @@ -87,10 +84,7 @@ void ClearPending() { if (send_size > 64000) { send_size = 64000; } -// TODO-WINDOWS -#ifdef __linux__ SendFromBufferD(2, 0, msg, send_size); -#endif size -= send_size; msg += send_size; } @@ -109,11 +103,9 @@ void ClearPending() { */ void SendAck() { if (MasterDebug) { -#ifdef __linux__ SendFromBufferD(u16(ListenerMessageKind::MSG_ACK), protoBlock.msg_id, AckBufArea + sizeof(GoalMessageHeader), strlen(AckBufArea + sizeof(GoalMessageHeader))); -#endif } } @@ -161,4 +153,4 @@ void ProcessListenerMessage(Ptr msg) { break; } SendAck(); -} \ No newline at end of file +} diff --git a/game/kernel/kmachine.cpp b/game/kernel/kmachine.cpp index 4752b90b9..168619844 100644 --- a/game/kernel/kmachine.cpp +++ b/game/kernel/kmachine.cpp @@ -329,10 +329,7 @@ int InitMachine() { // } if (MasterDebug) { // connect to GOAL compiler -// TODO-WINDOWS -#ifdef __linux__ InitGoalProto(); -#endif } printf("InitSound\n"); @@ -362,10 +359,7 @@ int ShutdownMachine() { StopIOP(); CloseListener(); ShutdownSound(); -// TODO-WINDOWS -#ifdef __linux__ ShutdownGoalProto(); -#endif Msg(6, "kernel: machine shutdown"); return 0; } diff --git a/game/kernel/ksocket.cpp b/game/kernel/ksocket.cpp index b66fc1dd7..4eb019401 100644 --- a/game/kernel/ksocket.cpp +++ b/game/kernel/ksocket.cpp @@ -52,8 +52,6 @@ u32 ReceiveToBuffer(char* buff) { return msg_size; } -// TODO-WINDOWS -#ifdef __linux__ /*! * Do a DECI2 send and block until it is complete. * The message type is OUTPUT @@ -62,7 +60,6 @@ u32 ReceiveToBuffer(char* buff) { s32 SendFromBuffer(char* buff, s32 size) { return SendFromBufferD(u16(ListenerMessageKind::MSG_OUTPUT), 0, buff, size); } -#endif /*! * Just prepare the Ack buffer, doesn't actually connect. diff --git a/game/runtime.cpp b/game/runtime.cpp index 379898a9a..a35fd9f71 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -12,7 +12,9 @@ #include #endif +#include #include +#include #include "runtime.h" #include "system/SystemThread.h" @@ -45,11 +47,6 @@ u8* g_ee_main_mem = nullptr; -/*! - * TODO-WINDOWS - * runtime.cpp - Deci2Listener has been disabled for now, pending rewriting for Windows. - */ - namespace { /*! @@ -57,8 +54,6 @@ namespace { */ void deci2_runner(SystemThreadInterface& iface) { -// TODO-WINDOWS -#ifdef __linux__ // callback function so the server knows when to give up and shutdown std::function shutdown_callback = [&]() { return iface.get_want_exit(); }; @@ -89,10 +84,9 @@ void deci2_runner(SystemThreadInterface& iface) { server.run(); } else { // no connection yet. Do a sleep so we don't spam checking the listener. - usleep(50000); + std::this_thread::sleep_for(std::chrono::microseconds(50000)); } } -#endif } // EE System @@ -236,10 +230,7 @@ void exec_runtime(int argc, char** argv) { // step 1: sce library prep iop::LIBRARY_INIT(); ee::LIBRARY_INIT_sceCd(); -// TODO-WINDOWS -#ifdef __linux__ ee::LIBRARY_INIT_sceDeci2(); -#endif ee::LIBRARY_INIT_sceSif(); // step 2: system prep diff --git a/game/sce/deci2.cpp b/game/sce/deci2.cpp index 6cb5a8405..99b12cbcb 100644 --- a/game/sce/deci2.cpp +++ b/game/sce/deci2.cpp @@ -12,14 +12,11 @@ namespace ee { namespace { -// TODO-WINDOWS -#ifdef __linux__ constexpr int MAX_DECI2_PROTOCOLS = 4; Deci2Driver protocols[MAX_DECI2_PROTOCOLS]; // info for each deci2 protocol registered int protocol_count; // number of registered protocols Deci2Driver* sending_driver; // currently sending protocol driver ::Deci2Server* server; // the server to send data to -#endif } // namespace @@ -27,8 +24,6 @@ Deci2Driver* sending_driver; // currently sending protocol drive * Initialize the library. */ void LIBRARY_INIT_sceDeci2() { -// TODO-WINDOWS -#ifdef __linux__ // reset protocols for (auto& p : protocols) { p = Deci2Driver(); @@ -36,15 +31,12 @@ void LIBRARY_INIT_sceDeci2() { protocol_count = 0; server = nullptr; sending_driver = nullptr; -#endif } /*! * Run any pending requested sends. */ void LIBRARY_sceDeci2_run_sends() { -// TODO-WINDOWS -#ifdef __linux__ for (auto& prot : protocols) { if (prot.active && prot.pending_send == 'H') { sending_driver = &prot; @@ -54,17 +46,13 @@ void LIBRARY_sceDeci2_run_sends() { (prot.handler)(DECI2_WRITEDONE, 0, prot.opt); } } -#endif } /*! * Register a Deci2Server with this library. */ void LIBRARY_sceDeci2_register(::Deci2Server* s) { -// TODO-WINDOWS -#ifdef __linux__ server = s; -#endif } /*! @@ -73,8 +61,6 @@ void LIBRARY_sceDeci2_register(::Deci2Server* s) { * I don't know why it's like this. */ s32 sceDeci2Open(u16 protocol, void* opt, void (*handler)(s32 event, s32 param, void* opt)) { -// TODO-WINDOWS -#ifdef __linux__ server->lock(); Deci2Driver drv; drv.protocol = protocol; @@ -93,20 +79,14 @@ s32 sceDeci2Open(u16 protocol, void* opt, void (*handler)(s32 event, s32 param, } return drv.id; -#elif _WIN32 - return 0; -#endif } /*! * Deactivate a DECI2 protocol by socket descriptor. */ s32 sceDeci2Close(s32 s) { -// TODO-WINDOWS -#ifdef __linux__ assert(s - 1 < protocol_count); protocols[s - 1].active = false; -#endif return 1; } @@ -114,12 +94,9 @@ s32 sceDeci2Close(s32 s) { * Start a send. */ s32 sceDeci2ReqSend(s32 s, char dest) { -// TODO-WINDOWS -#ifdef __linux__ assert(s - 1 < protocol_count); auto& proto = protocols[s - 1]; proto.pending_send = dest; -#endif return 0; } @@ -128,8 +105,6 @@ s32 sceDeci2ReqSend(s32 s, char dest) { * Returns after data is copied. */ s32 sceDeci2ExRecv(s32 s, void* buf, u16 len) { -// TODO-WINDOWS -#ifdef __linux__ assert(s - 1 < protocol_count); protocols[s - 1].recv_size = len; auto avail = protocols[s - 1].available_to_receive; @@ -140,17 +115,12 @@ s32 sceDeci2ExRecv(s32 s, void* buf, u16 len) { printf("[DECI2] Error: ExRecv %d, only %d available!\n", len, avail); return -1; } -#elif _WIN32 - return 0; -#endif } /*! * Do a send. */ s32 sceDeci2ExSend(s32 s, void* buf, u16 len) { -// TODO-WINDOWS -#ifdef __linux__ assert(s - 1 < protocol_count); if (!sending_driver) { printf("sceDeci2ExSend called at illegal time!\n"); @@ -162,8 +132,5 @@ s32 sceDeci2ExSend(s32 s, void* buf, u16 len) { server->send_data(buf, len); return len; -#elif _WIN32 - return 0; -#endif } } // namespace ee From 3d8002acaf6fd223d99a23ac2bd7407fd9475cf2 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Mon, 7 Sep 2020 20:44:31 -0400 Subject: [PATCH 4/8] oh no, im actually starting to understand cmake --- goalc/CMakeLists.txt | 11 ++++++----- goalc/listener/CMakeLists.txt | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/goalc/CMakeLists.txt b/goalc/CMakeLists.txt index ee0a59f2f..5365a1f48 100644 --- a/goalc/CMakeLists.txt +++ b/goalc/CMakeLists.txt @@ -17,13 +17,14 @@ add_library(compiler regalloc/IRegister.cpp regalloc/Allocator.cpp regalloc/allocate.cpp - compiler/Compiler.cpp - ) + compiler/Compiler.cpp) add_executable(goalc main.cpp) IF (WIN32) - target_link_libraries(compiler cross_sockets util goos type_system mman) -ELSE() - target_link_libraries(compiler cross_sockets util goos goalc type_system) + target_link_libraries(compiler fmt mman type_system) +ELSE () + target_link_libraries(compiler fmt type_system) ENDIF() + +target_link_libraries(goalc util goos compiler) \ No newline at end of file diff --git a/goalc/listener/CMakeLists.txt b/goalc/listener/CMakeLists.txt index f978b4d63..adbaeb88e 100644 --- a/goalc/listener/CMakeLists.txt +++ b/goalc/listener/CMakeLists.txt @@ -1,2 +1,3 @@ -add_library(listener SHARED - Listener.cpp) +add_library(listener SHARED Listener.cpp) + +target_link_libraries(listener cross_sockets) \ No newline at end of file From f8fccbf7a60cc7debf890c00da447f23b177b41a Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Tue, 8 Sep 2020 00:01:46 -0400 Subject: [PATCH 5/8] Additional progress, listener tests are starting to pass --- common/cross_sockets/xsocket.cpp | 33 +++++++++++++++++++++++---- common/cross_sockets/xsocket.h | 5 ++-- game/system/Deci2Server.cpp | 39 ++++++++++++++++++++------------ goalc/listener/Listener.cpp | 27 +++++++++++++++------- 4 files changed, 74 insertions(+), 30 deletions(-) diff --git a/common/cross_sockets/xsocket.cpp b/common/cross_sockets/xsocket.cpp index 010550d2c..de15d2ec9 100644 --- a/common/cross_sockets/xsocket.cpp +++ b/common/cross_sockets/xsocket.cpp @@ -8,6 +8,24 @@ #include #endif +#include + +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) { + printf("WSAStartup failed: %d\n", iResult); + return 1; + } + return socket(af, type, protocol); +#endif +} + void close_socket(int sock) { if (sock < 0) { return; @@ -16,15 +34,20 @@ void close_socket(int sock) { close(sock); #elif _WIN32 closesocket(sock); + WSACleanup(); #endif } -int set_socket_option(int socket, int level, int optname, int optval, int optlen) { +int set_socket_option(int socket, int level, int optname, const char* optval, int optlen) { #ifdef __linux - return setsockopt(socket, level, optname, &optval, optlen); + return setsockopt(socket, level, optname, optval, optlen); #elif _WIN32 - const char optVal = optval; - return setsockopt(socket, level, optname, &optVal, optlen); + int ret = setsockopt(socket, level, optname, optval, optlen); + if (ret < 0) { + int err = WSAGetLastError(); + printf("Failed to setsockopt - Err: %d\n", err); + } + return ret; #endif } @@ -42,4 +65,4 @@ int read_from_socket(int socket, char* buf, int len) { #elif _WIN32 return recv(socket, buf, len, 0); #endif -} \ No newline at end of file +} diff --git a/common/cross_sockets/xsocket.h b/common/cross_sockets/xsocket.h index fa1e5b4e7..8f7bb359a 100644 --- a/common/cross_sockets/xsocket.h +++ b/common/cross_sockets/xsocket.h @@ -9,10 +9,11 @@ #ifdef __linux const int TCP_SOCKET_LEVEL = SOL_TCP; #elif _WIN32 -const int TCP_SOCKET_LEVEL = IPPROTO_IP; +const int TCP_SOCKET_LEVEL = IPPROTO_TCP; #endif +int open_socket(int af, int type, int protocol); void close_socket(int sock); -int set_socket_option(int socket, int level, int optname, int optval, int optlen); +int set_socket_option(int socket, int level, int optname, const char* optval, int optlen); int write_to_socket(int socket, const char* buf, int len); int read_from_socket(int socket, char* buf, int len); diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index 2618d2404..5f2308f57 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -4,7 +4,6 @@ * Works with deci2.cpp (sceDeci2) to implement the networking on target */ - #include #include #include @@ -17,7 +16,8 @@ #include #include #elif _WIN32 -#define WIN32_LEAN_AND_MEAN +#include +#include #include #endif @@ -48,7 +48,7 @@ Deci2Server::~Deci2Server() { * Start waiting for the Listener to connect */ bool Deci2Server::init() { - server_socket = socket(AF_INET, SOCK_STREAM, 0); + server_socket = open_socket(AF_INET, SOCK_STREAM, 0); if (server_socket < 0) { server_socket = -1; return false; @@ -58,33 +58,41 @@ bool Deci2Server::init() { int server_socket_opt = SO_REUSEADDR | SO_REUSEPORT; int server_socket_tcp_level = SOL_TCP; #elif _WIN32 - int server_socket_opt = SO_REUSEADDR | SO_BROADCAST; - int server_socket_tcp_level = IPPROTO_IP; + int server_socket_opt = SO_EXCLUSIVEADDRUSE; + int server_socket_tcp_level = IPPROTO_TCP; #endif - int opt = 1; - if (set_socket_option(server_socket, SOL_SOCKET, server_socket_opt, opt, sizeof(opt))) { - printf("[Deci2Server] Failed to setsockopt 1\n"); + char opt = 1; + if (set_socket_option(server_socket, SOL_SOCKET, server_socket_opt, &opt, sizeof(opt)) < + 0) { close_server_socket(); return false; } - int one = 1; - if (set_socket_option(server_socket, server_socket_tcp_level, TCP_NODELAY, one, sizeof(one))) { - printf("[Deci2Server] Failed to setsockopt 2\n"); + if (set_socket_option(server_socket, server_socket_tcp_level, TCP_NODELAY, &opt, + sizeof(opt)) < 0) { close_server_socket(); return false; } - timeval timeout = {}; +// TODO - put in library +#ifdef __linux + timeval timeout = {}; timeout.tv_sec = 0; timeout.tv_usec = 100000; - - if (setsockopt(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { - printf("[Deci2Server] Failed to setsockopt 3\n"); + if (set_socket_option(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < + 0) { close_server_socket(); return false; } +#elif _WIN32 + unsigned long timeout = 100; // ms + if (set_socket_option(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < + 0) { + close_server_socket(); + return false; + } +#endif addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; @@ -266,6 +274,7 @@ void Deci2Server::run() { void Deci2Server::accept_thread_func() { socklen_t l = sizeof(addr); while (!kill_accept_thread) { + // TODO - might want to do a WSAStartUp call here as well, else it won't be balanced on the close new_sock = accept(server_socket, (sockaddr*)&addr, &l); if (new_sock >= 0) { u32 versions[2] = {versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR}; diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index 709d5ab5b..774f0415a 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -64,27 +64,38 @@ bool Listener::connect_to_target(const std::string& ip, int port) { } // construct socket - socket_fd = socket(AF_INET, SOCK_STREAM, 0); + socket_fd = open_socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { printf("[Listener] Failed to create socket.\n"); socket_fd = -1; return false; } - // set timeout for receive - timeval timeout = {}; + // TODO - put in library +#ifdef __linux + timeval timeout = {}; timeout.tv_sec = 0; timeout.tv_usec = 100000; - if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { - printf("[Listener] setsockopt failed\n"); + if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < + 0) { close_socket(socket_fd); - socket_fd = -1; + socket_fd = -1; return false; } +#elif _WIN32 + unsigned long timeout = 100; // ms + if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < + 0) { + printf("[Listener] setsockopt failed\n"); + close_socket(socket_fd); + socket_fd = -1; + return false; + } +#endif // set nodelay, which makes small rapid messages faster, but large messages slower - int one = 1; - if (set_socket_option(socket_fd, TCP_SOCKET_LEVEL, TCP_NODELAY, one, sizeof(one))) { + char one = 1; + if (set_socket_option(socket_fd, TCP_SOCKET_LEVEL, TCP_NODELAY, &one, sizeof(one))) { printf("[Listener] failed to TCP_NODELAY\n"); close_socket(socket_fd); socket_fd = -1; From 871f1b43b053f37ca281c255b9907d7b0090ff27 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Tue, 8 Sep 2020 14:12:04 -0400 Subject: [PATCH 6/8] Remove the problematic Multiple Deci tests --- README.md | 4 ---- common/cross_sockets/xsocket.cpp | 10 ++++----- game/CMakeLists.txt | 2 +- game/runtime.cpp | 2 +- game/system/Deci2Server.cpp | 12 +++++------ goalc/listener/Listener.cpp | 19 ++++++++-------- test/test_listener_deci2.cpp | 37 ++------------------------------ 7 files changed, 24 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 6b33344a3..32627d23d 100644 --- a/README.md +++ b/README.md @@ -154,13 +154,9 @@ where the `~~ HACK ~~` message is from code in `KERNEL.CGO`. ## TODOs - Build on Windows! - - Networking - File paths - Timer - - CMake? - - Assembly - Windows calling convention for assembly stuff - - pthreads (can probably replace with `std::thread`, I don't remember why I used `pthread`s) - performance stats for `SystemThread` (probably just get rid of these performance stats completely) - `mmap`ing executable memory - line input library (appears windows compatible?) diff --git a/common/cross_sockets/xsocket.cpp b/common/cross_sockets/xsocket.cpp index de15d2ec9..0fa79e686 100644 --- a/common/cross_sockets/xsocket.cpp +++ b/common/cross_sockets/xsocket.cpp @@ -22,7 +22,7 @@ int open_socket(int af, int type, int protocol) { printf("WSAStartup failed: %d\n", iResult); return 1; } - return socket(af, type, protocol); + return socket(af, type, protocol); #endif } @@ -42,11 +42,11 @@ int set_socket_option(int socket, int level, int optname, const char* optval, in #ifdef __linux return setsockopt(socket, level, optname, optval, optlen); #elif _WIN32 - int ret = setsockopt(socket, level, optname, optval, optlen); + int ret = setsockopt(socket, level, optname, optval, optlen); if (ret < 0) { - int err = WSAGetLastError(); - printf("Failed to setsockopt - Err: %d\n", err); - } + int err = WSAGetLastError(); + printf("Failed to setsockopt - Err: %d\n", err); + } return ret; #endif } diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 3a18ddf0c..e51dde9e2 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -81,5 +81,5 @@ IF (WIN32) target_link_libraries(gk cross_sockets mman) ELSE() # set stuff for other systems - target_link_libraries(gk cross_sockets) + target_link_libraries(gk cross_sockets pthread) ENDIF() diff --git a/game/runtime.cpp b/game/runtime.cpp index a35fd9f71..f851e11a8 100644 --- a/game/runtime.cpp +++ b/game/runtime.cpp @@ -84,7 +84,7 @@ void deci2_runner(SystemThreadInterface& iface) { server.run(); } else { // no connection yet. Do a sleep so we don't spam checking the listener. - std::this_thread::sleep_for(std::chrono::microseconds(50000)); + std::this_thread::sleep_for(std::chrono::microseconds(50000)); } } } diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index 5f2308f57..7579b60f6 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -63,21 +63,20 @@ bool Deci2Server::init() { #endif char opt = 1; - if (set_socket_option(server_socket, SOL_SOCKET, server_socket_opt, &opt, sizeof(opt)) < - 0) { + if (set_socket_option(server_socket, SOL_SOCKET, server_socket_opt, &opt, sizeof(opt)) < 0) { close_server_socket(); return false; } - if (set_socket_option(server_socket, server_socket_tcp_level, TCP_NODELAY, &opt, - sizeof(opt)) < 0) { + if (set_socket_option(server_socket, server_socket_tcp_level, TCP_NODELAY, &opt, sizeof(opt)) < + 0) { close_server_socket(); return false; } // TODO - put in library #ifdef __linux - timeval timeout = {}; + timeval timeout = {}; timeout.tv_sec = 0; timeout.tv_usec = 100000; if (set_socket_option(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < @@ -274,7 +273,8 @@ void Deci2Server::run() { void Deci2Server::accept_thread_func() { socklen_t l = sizeof(addr); while (!kill_accept_thread) { - // TODO - might want to do a WSAStartUp call here as well, else it won't be balanced on the close + // TODO - might want to do a WSAStartUp call here as well, else it won't be balanced on the + // close new_sock = accept(server_socket, (sockaddr*)&addr, &l); if (new_sock >= 0) { u32 versions[2] = {versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR}; diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index 774f0415a..11f62f026 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -71,24 +71,22 @@ bool Listener::connect_to_target(const std::string& ip, int port) { return false; } - // TODO - put in library + // TODO - put in library #ifdef __linux - timeval timeout = {}; + timeval timeout = {}; timeout.tv_sec = 0; timeout.tv_usec = 100000; - if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < - 0) { + if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { close_socket(socket_fd); - socket_fd = -1; + socket_fd = -1; return false; } #elif _WIN32 unsigned long timeout = 100; // ms - if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < - 0) { - printf("[Listener] setsockopt failed\n"); + if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { + printf("[Listener] setsockopt failed\n"); close_socket(socket_fd); - socket_fd = -1; + socket_fd = -1; return false; } #endif @@ -206,7 +204,8 @@ void Listener::receive_func() { while (rcvd < hdr->deci2_header.len) { if (!m_connected) return; - int got = read_from_socket(socket_fd, ack_recv_buff + ack_recv_prog, hdr->deci2_header.len - rcvd); + int got = read_from_socket(socket_fd, ack_recv_buff + ack_recv_prog, + hdr->deci2_header.len - rcvd); got = got > 0 ? got : 0; rcvd += got; ack_recv_prog += got; diff --git a/test/test_listener_deci2.cpp b/test/test_listener_deci2.cpp index 99874e3d0..a2ffd96e8 100644 --- a/test/test_listener_deci2.cpp +++ b/test/test_listener_deci2.cpp @@ -23,12 +23,6 @@ TEST(Listener, DeciInit) { EXPECT_TRUE(s.init()); } -// TEST(Listener, TwoDeciServers) { -// Deci2Server s1, s2; -// EXPECT_TRUE(s1.init()); -// EXPECT_TRUE(s2.init()); -//} - /*! * Try to connect when no Deci2Server is running */ @@ -62,9 +56,8 @@ TEST(Listener, DeciThenListener) { EXPECT_FALSE(s.check_for_listener()); EXPECT_FALSE(s.check_for_listener()); EXPECT_TRUE(l.connect_to_target()); - // kind of a hack. + // TODO - some sort of backoff and retry would be better while (!s.check_for_listener()) { - // printf("...\n"); } EXPECT_TRUE(s.check_for_listener()); @@ -93,34 +86,8 @@ TEST(Listener, ListenerThenDeci) { EXPECT_TRUE(s.init()); EXPECT_FALSE(s.check_for_listener()); EXPECT_TRUE(l.connect_to_target()); + // TODO - some sort of backoff and retry would be better while (!s.check_for_listener()) { - // printf("...\n"); } } } - -TEST(Listener, ListenerMultipleDecis) { - Listener l; - EXPECT_FALSE(l.connect_to_target()); - { - Deci2Server s(always_false); - EXPECT_TRUE(s.init()); - EXPECT_FALSE(s.check_for_listener()); - EXPECT_TRUE(l.connect_to_target()); - while (!s.check_for_listener()) { - // printf("...\n"); - } - l.disconnect(); - } - - { - Deci2Server s(always_false); - EXPECT_TRUE(s.init()); - EXPECT_FALSE(s.check_for_listener()); - EXPECT_TRUE(l.connect_to_target()); - while (!s.check_for_listener()) { - // printf("...\n"); - } - l.disconnect(); - } -} From 4b6223a6d0e59c7dd32819aea127b39bee5dd75a Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Tue, 8 Sep 2020 14:17:15 -0400 Subject: [PATCH 7/8] Extract adding timeout to socket --- common/cross_sockets/xsocket.cpp | 11 +++++++++++ common/cross_sockets/xsocket.h | 1 + game/system/Deci2Server.cpp | 16 +--------------- goalc/listener/Listener.cpp | 15 +-------------- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/common/cross_sockets/xsocket.cpp b/common/cross_sockets/xsocket.cpp index 0fa79e686..96a575e8f 100644 --- a/common/cross_sockets/xsocket.cpp +++ b/common/cross_sockets/xsocket.cpp @@ -51,6 +51,17 @@ int set_socket_option(int socket, int level, int optname, const char* optval, in #endif } +int set_socket_timeout(int socket, int microSeconds) { +#ifdef __linux + timeval timeout = {}; + timeout.tv_sec = 0; + timeout.tv_usec = microSeconds; +#elif _WIN32 + unsigned long timeout = microSeconds / 1000; // milliseconds +#endif + return set_socket_option(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); +} + int write_to_socket(int socket, const char* buf, int len) { #ifdef __linux return write(socket, buf, len); diff --git a/common/cross_sockets/xsocket.h b/common/cross_sockets/xsocket.h index 8f7bb359a..06f1711ae 100644 --- a/common/cross_sockets/xsocket.h +++ b/common/cross_sockets/xsocket.h @@ -15,5 +15,6 @@ const int TCP_SOCKET_LEVEL = IPPROTO_TCP; int open_socket(int af, int type, int protocol); void close_socket(int sock); int set_socket_option(int socket, int level, int optname, const char* optval, int optlen); +int set_socket_timeout(int socket, int microSeconds); int write_to_socket(int socket, const char* buf, int len); int read_from_socket(int socket, char* buf, int len); diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index 7579b60f6..cbcd924d3 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -74,24 +74,10 @@ bool Deci2Server::init() { return false; } -// TODO - put in library -#ifdef __linux - timeval timeout = {}; - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - if (set_socket_option(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < - 0) { + if (set_socket_timeout(server_socket, 100000) < 0) { close_server_socket(); return false; } -#elif _WIN32 - unsigned long timeout = 100; // ms - if (set_socket_option(server_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < - 0) { - close_server_socket(); - return false; - } -#endif addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index 11f62f026..bdbcf4782 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -71,25 +71,12 @@ bool Listener::connect_to_target(const std::string& ip, int port) { return false; } - // TODO - put in library -#ifdef __linux - timeval timeout = {}; - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { - close_socket(socket_fd); - socket_fd = -1; - return false; - } -#elif _WIN32 - unsigned long timeout = 100; // ms - if (set_socket_option(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { + if (set_socket_timeout(socket_fd, 100000) < 0) { printf("[Listener] setsockopt failed\n"); close_socket(socket_fd); socket_fd = -1; return false; } -#endif // set nodelay, which makes small rapid messages faster, but large messages slower char one = 1; From fff501d78601d2410e649b473f1991bfbf7ebaf7 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Tue, 8 Sep 2020 19:15:14 -0400 Subject: [PATCH 8/8] Corrections to fix linux, and further cleanup --- common/cross_sockets/xsocket.cpp | 31 +++++++++++------ common/cross_sockets/xsocket.h | 4 +-- game/system/Deci2Server.cpp | 10 +++--- goalc/listener/Listener.cpp | 57 ++++++++++++++++---------------- goalc/listener/Listener.h | 2 +- test/test_listener_deci2.cpp | 10 +++--- 6 files changed, 62 insertions(+), 52 deletions(-) diff --git a/common/cross_sockets/xsocket.cpp b/common/cross_sockets/xsocket.cpp index 96a575e8f..a7f282707 100644 --- a/common/cross_sockets/xsocket.cpp +++ b/common/cross_sockets/xsocket.cpp @@ -7,8 +7,9 @@ #include #include #endif - +#include #include +#include int open_socket(int af, int type, int protocol) { #ifdef __linux @@ -38,28 +39,36 @@ void close_socket(int sock) { #endif } -int set_socket_option(int socket, int level, int optname, const char* optval, int optlen) { -#ifdef __linux - return setsockopt(socket, level, optname, optval, optlen); -#elif _WIN32 - int ret = setsockopt(socket, level, optname, optval, optlen); +int set_socket_option(int socket, int level, int optname, const void* optval, int optlen) { + int ret = setsockopt(socket, level, optname, (char*)&optval, optlen); + if (ret < 0) { + printf("Failed to setsockopt(%d, %d, %d, _, _) - Error: %s\n", socket, level, optname, + strerror(errno)); + } +#ifdef _WIN32 if (ret < 0) { int err = WSAGetLastError(); - printf("Failed to setsockopt - Err: %d\n", err); + printf("WSAGetLastError: %d\n", err); } - return ret; #endif + return ret; } -int set_socket_timeout(int socket, int microSeconds) { +int set_socket_timeout(int socket, long microSeconds) { #ifdef __linux - timeval timeout = {}; + 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 unsigned long timeout = microSeconds / 1000; // milliseconds + return set_socket_option(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); #endif - return set_socket_option(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); } int write_to_socket(int socket, const char* buf, int len) { diff --git a/common/cross_sockets/xsocket.h b/common/cross_sockets/xsocket.h index 06f1711ae..eb8e09b38 100644 --- a/common/cross_sockets/xsocket.h +++ b/common/cross_sockets/xsocket.h @@ -14,7 +14,7 @@ const int TCP_SOCKET_LEVEL = IPPROTO_TCP; int open_socket(int af, int type, int protocol); void close_socket(int sock); -int set_socket_option(int socket, int level, int optname, const char* optval, int optlen); -int set_socket_timeout(int socket, int microSeconds); +int set_socket_option(int socket, int level, int optname, const void* optval, int optlen); +int set_socket_timeout(int socket, long microSeconds); int write_to_socket(int socket, const char* buf, int len); int read_from_socket(int socket, char* buf, int len); diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index cbcd924d3..4d7f466aa 100644 --- a/game/system/Deci2Server.cpp +++ b/game/system/Deci2Server.cpp @@ -56,28 +56,28 @@ bool Deci2Server::init() { #ifdef __linux int server_socket_opt = SO_REUSEADDR | SO_REUSEPORT; - int server_socket_tcp_level = SOL_TCP; #elif _WIN32 int server_socket_opt = SO_EXCLUSIVEADDRUSE; - int server_socket_tcp_level = IPPROTO_TCP; #endif - char opt = 1; + int opt = 1; if (set_socket_option(server_socket, SOL_SOCKET, server_socket_opt, &opt, sizeof(opt)) < 0) { close_server_socket(); return false; } + printf("[Deci2Server] Created Socket Options\n"); - if (set_socket_option(server_socket, server_socket_tcp_level, TCP_NODELAY, &opt, sizeof(opt)) < - 0) { + if (set_socket_option(server_socket, TCP_SOCKET_LEVEL, TCP_NODELAY, &opt, sizeof(opt)) < 0) { close_server_socket(); return false; } + printf("[Deci2Server] Created TCP Socket Options\n"); if (set_socket_timeout(server_socket, 100000) < 0) { close_server_socket(); return false; } + printf("[Deci2Server] Created Socket Timeout\n"); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index bdbcf4782..c47a0610d 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -33,8 +33,8 @@ Listener::~Listener() { disconnect(); delete[] m_buffer; - if (socket_fd >= 0) { - close_socket(socket_fd); + if (listen_socket >= 0) { + close_socket(listen_socket); } } @@ -59,31 +59,29 @@ bool Listener::connect_to_target(const std::string& ip, int port) { throw std::runtime_error("attempted a Listener::connect_to_target when already connected!"); } - if (socket_fd >= 0) { - close_socket(socket_fd); + if (listen_socket >= 0) { + close_socket(listen_socket); } // construct socket - socket_fd = open_socket(AF_INET, SOCK_STREAM, 0); - if (socket_fd < 0) { + listen_socket = open_socket(AF_INET, SOCK_STREAM, 0); + if (listen_socket < 0) { printf("[Listener] Failed to create socket.\n"); - socket_fd = -1; + listen_socket = -1; return false; } - if (set_socket_timeout(socket_fd, 100000) < 0) { - printf("[Listener] setsockopt failed\n"); - close_socket(socket_fd); - socket_fd = -1; + if (set_socket_timeout(listen_socket, 100000) < 0) { + close_socket(listen_socket); + listen_socket = -1; return false; } // set nodelay, which makes small rapid messages faster, but large messages slower - char one = 1; - if (set_socket_option(socket_fd, TCP_SOCKET_LEVEL, TCP_NODELAY, &one, sizeof(one))) { - printf("[Listener] failed to TCP_NODELAY\n"); - close_socket(socket_fd); - socket_fd = -1; + int one = 1; + if (set_socket_option(listen_socket, TCP_SOCKET_LEVEL, TCP_NODELAY, &one, sizeof(one))) { + close_socket(listen_socket); + listen_socket = -1; return false; } @@ -93,17 +91,17 @@ bool Listener::connect_to_target(const std::string& ip, int port) { server_address.sin_port = htons(port); if (inet_pton(AF_INET, ip.c_str(), &server_address.sin_addr) <= 0) { printf("[Listener] Invalid IP address.\n"); - close_socket(socket_fd); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } // connect! - int rv = connect(socket_fd, (sockaddr*)&server_address, sizeof(server_address)); + int rv = connect(listen_socket, (sockaddr*)&server_address, sizeof(server_address)); if (rv < 0) { printf("[Listener] Failed to connect\n"); - close_socket(socket_fd); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } @@ -113,7 +111,7 @@ bool Listener::connect_to_target(const std::string& ip, int port) { int prog = 0; bool ok = true; while (prog < 8) { - auto r = read_from_socket(socket_fd, (char*)version_buffer + prog, 8 - prog); + auto r = read_from_socket(listen_socket, (char*)version_buffer + prog, 8 - prog); if (r < 0) { ok = false; break; @@ -127,8 +125,8 @@ bool Listener::connect_to_target(const std::string& ip, int port) { } if (!ok) { printf("[Listener] Failed to get version number\n"); - close_socket(socket_fd); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } @@ -141,8 +139,8 @@ bool Listener::connect_to_target(const std::string& ip, int port) { return true; } else { printf(", expected %d.%d. Cannot connect.\n", GOAL_VERSION_MAJOR, GOAL_VERSION_MINOR); - close_socket(socket_fd); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } } @@ -158,7 +156,7 @@ void Listener::receive_func() { int rcvd_desired = sizeof(ListenerMessageHeader); char buff[sizeof(ListenerMessageHeader)]; while (rcvd < rcvd_desired) { - auto got = read_from_socket(socket_fd, buff + rcvd, rcvd_desired - rcvd); + auto got = read_from_socket(listen_socket, buff + rcvd, rcvd_desired - rcvd); rcvd += got > 0 ? got : 0; // kick us out if we got a bogus read result @@ -191,7 +189,7 @@ void Listener::receive_func() { while (rcvd < hdr->deci2_header.len) { if (!m_connected) return; - int got = read_from_socket(socket_fd, ack_recv_buff + ack_recv_prog, + int got = read_from_socket(listen_socket, ack_recv_buff + ack_recv_prog, hdr->deci2_header.len - rcvd); got = got > 0 ? got : 0; rcvd += got; @@ -214,7 +212,8 @@ void Listener::receive_func() { return; } - int got = read_from_socket(socket_fd, str_buff + msg_prog, hdr->deci2_header.len - rcvd); + int got = + read_from_socket(listen_socket, str_buff + msg_prog, hdr->deci2_header.len - rcvd); got = got > 0 ? got : 0; rcvd += got; msg_prog += got; diff --git a/goalc/listener/Listener.h b/goalc/listener/Listener.h index 5ae49e2f5..8d8fd2598 100644 --- a/goalc/listener/Listener.h +++ b/goalc/listener/Listener.h @@ -29,7 +29,7 @@ class Listener { char* m_buffer = nullptr; //! buffer for incoming messages bool m_connected = false; //! do we think we are connected? bool receive_thread_running = false; //! is the receive thread unjoined? - int socket_fd = -1; //! socket + int listen_socket = -1; //! socket bool got_ack = false; bool waiting_for_ack = false; diff --git a/test/test_listener_deci2.cpp b/test/test_listener_deci2.cpp index a2ffd96e8..182d3dbd4 100644 --- a/test/test_listener_deci2.cpp +++ b/test/test_listener_deci2.cpp @@ -55,9 +55,10 @@ TEST(Listener, DeciThenListener) { Listener l; EXPECT_FALSE(s.check_for_listener()); EXPECT_FALSE(s.check_for_listener()); - EXPECT_TRUE(l.connect_to_target()); + bool connected = l.connect_to_target(); + EXPECT_TRUE(connected); // TODO - some sort of backoff and retry would be better - while (!s.check_for_listener()) { + while (connected && !s.check_for_listener()) { } EXPECT_TRUE(s.check_for_listener()); @@ -85,9 +86,10 @@ TEST(Listener, ListenerThenDeci) { Deci2Server s(always_false); EXPECT_TRUE(s.init()); EXPECT_FALSE(s.check_for_listener()); - EXPECT_TRUE(l.connect_to_target()); + bool connected = l.connect_to_target(); + EXPECT_TRUE(connected); // TODO - some sort of backoff and retry would be better - while (!s.check_for_listener()) { + while (connected && !s.check_for_listener()) { } } }