diff --git a/CMakeLists.txt b/CMakeLists.txt index 952c0f572..bd5dd3baa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,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/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/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..a7f282707 --- /dev/null +++ b/common/cross_sockets/xsocket.cpp @@ -0,0 +1,88 @@ +#ifdef __linux +#include +#include +#include +#elif _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif +#include +#include +#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; + } +#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, (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("WSAGetLastError: %d\n", 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 + unsigned long timeout = microSeconds / 1000; // milliseconds + return set_socket_option(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); +#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 +} diff --git a/common/cross_sockets/xsocket.h b/common/cross_sockets/xsocket.h new file mode 100644 index 000000000..eb8e09b38 --- /dev/null +++ b/common/cross_sockets/xsocket.h @@ -0,0 +1,20 @@ +#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_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, 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/CMakeLists.txt b/game/CMakeLists.txt index 59cacdf7a..e51dde9e2 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 pthread) ENDIF() diff --git a/game/kernel/kboot.cpp b/game/kernel/kboot.cpp index b8605b36f..d005026d3 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" @@ -152,21 +155,14 @@ void KernelCheckAndDispatch() { } } - // 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 1c2d85d34..322d049e3 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 } } @@ -164,4 +156,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 6a030104f..f5b611b36 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 4fa7a585e..160ca28cb 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 @@ u32 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 diff --git a/game/system/Deci2Server.cpp b/game/system/Deci2Server.cpp index 600f34462..4d7f466aa 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 +#include +#include +#include +#endif #include "common/listener_common.h" #include "common/versions.h" @@ -33,67 +40,58 @@ 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 = open_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; +#elif _WIN32 + int server_socket_opt = SO_EXCLUSIVEADDRUSE; +#endif + int opt = 1; - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { - printf("[Deci2Server] Failed to setsockopt 1\n"); - close(server_fd); - server_fd = -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"); - int one = 1; - if (setsockopt(server_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { - printf("[Deci2Server] Failed to setsockopt 2\n"); - close(server_fd); - server_fd = -1; + 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"); - timeval timeout = {}; - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - - if (setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { - printf("[Deci2Server] Failed to setsockopt 3\n"); - close(server_fd); - server_fd = -1; + 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; 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 +102,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 +132,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 +189,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 +240,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 +259,14 @@ 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); + // 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}; - 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 1a26b2ec1..2e8ab6425 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 @@ -29,15 +23,12 @@ add_library(compiler regalloc/IRegister.cpp regalloc/Allocator.cpp regalloc/allocate.cpp - compiler/Compiler.cpp - ) + 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 util goos type_system listener mman) ELSE () target_link_libraries(compiler util goos type_system listener) diff --git a/goalc/listener/CMakeLists.txt b/goalc/listener/CMakeLists.txt index 1ec9728b8..4cc5c9033 100644 --- a/goalc/listener/CMakeLists.txt +++ b/goalc/listener/CMakeLists.txt @@ -1,7 +1,7 @@ -add_library(listener SHARED - Listener.cpp) +add_library(listener SHARED Listener.cpp) + IF (WIN32) - # + target_link_libraries(listener cross_sockets) ELSE () - target_link_libraries(listener pthread) + target_link_libraries(listener cross_sockets pthread) ENDIF () \ No newline at end of file diff --git a/goalc/listener/Listener.cpp b/goalc/listener/Listener.cpp index 961a3cb60..2081babad 100644 --- a/goalc/listener/Listener.cpp +++ b/goalc/listener/Listener.cpp @@ -5,15 +5,25 @@ * TODO - msg ID? */ -// TODO-Windows #ifdef __linux__ - #include #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 +#include +#include #include "Listener.h" #include "common/versions.h" @@ -30,8 +40,8 @@ Listener::~Listener() { disconnect(); delete[] m_buffer; - if (socket_fd >= 0) { - close(socket_fd); + if (listen_socket >= 0) { + close_socket(listen_socket); } } @@ -57,35 +67,29 @@ bool Listener::connect_to_target(int n_tries, const std::string& ip, int port) { return true; } - if (socket_fd >= 0) { - close(socket_fd); + if (listen_socket >= 0) { + close_socket(listen_socket); } // construct socket - socket_fd = 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; } - // set timeout for receive - 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"); - close(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 int one = 1; - if (setsockopt(socket_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { - printf("[Listener] failed to TCP_NODELAY\n"); - close(socket_fd); - socket_fd = -1; + if (set_socket_option(listen_socket, TCP_SOCKET_LEVEL, TCP_NODELAY, &one, sizeof(one))) { + close_socket(listen_socket); + listen_socket = -1; return false; } @@ -95,24 +99,24 @@ bool Listener::connect_to_target(int n_tries, 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); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } // connect! int rv, i; for (i = 0; i < n_tries; i++) { - rv = connect(socket_fd, (sockaddr*)&server_address, sizeof(server_address)); + rv = connect(listen_socket, (sockaddr*)&server_address, sizeof(server_address)); if (rv >= 0) { break; } - usleep(100000); + std::this_thread::sleep_for(std::chrono::microseconds(100000)); } if (rv < 0) { printf("[Listener] Failed to connect\n"); - close(socket_fd); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } else { printf("[Listener] Socket connected established! (took %d tries)\n", i); @@ -124,7 +128,7 @@ bool Listener::connect_to_target(int n_tries, 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(listen_socket, (char*)version_buffer + prog, 8 - prog); if (r < 0) { ok = false; break; @@ -138,8 +142,8 @@ bool Listener::connect_to_target(int n_tries, const std::string& ip, int port) { } if (!ok) { printf("[Listener] Failed to get version number\n"); - close(socket_fd); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } @@ -152,8 +156,8 @@ bool Listener::connect_to_target(int n_tries, 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); - socket_fd = -1; + close_socket(listen_socket); + listen_socket = -1; return false; } } @@ -169,7 +173,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(listen_socket, buff + rcvd, rcvd_desired - rcvd); rcvd += got > 0 ? got : 0; // kick us out if we got a bogus read result @@ -202,7 +206,8 @@ 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(listen_socket, ack_recv_buff + ack_recv_prog, + hdr->deci2_header.len - rcvd); got = got > 0 ? got : 0; rcvd += got; ack_recv_prog += got; @@ -224,7 +229,8 @@ void Listener::receive_func() { return; } - int got = read(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; @@ -309,7 +315,7 @@ void Listener::send_reset(bool shutdown) { header->u8 = shutdown ? UINT64_MAX : 0; send_buffer(sizeof(ListenerMessageHeader)); disconnect(); - close(socket_fd); + close_socket(listen_socket); printf("closed connection to target\n"); } @@ -342,7 +348,7 @@ void Listener::send_buffer(int sz) { waiting_for_ack = true; while (wrote < sz) { auto to_send = std::min(512, sz - wrote); - auto x = write(socket_fd, m_buffer + wrote, to_send); + auto x = write_to_socket(listen_socket, m_buffer + wrote, to_send); wrote += x; } @@ -378,4 +384,3 @@ bool Listener::wait_for_ack() { } } // namespace listener -#endif diff --git a/goalc/listener/Listener.h b/goalc/listener/Listener.h index b26b61994..0c16d3028 100644 --- a/goalc/listener/Listener.h +++ b/goalc/listener/Listener.h @@ -38,7 +38,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/CMakeLists.txt b/test/CMakeLists.txt index 698768586..25ba92bfe 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,9 +19,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..182d3dbd4 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" @@ -25,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 */ @@ -63,10 +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()); - // kind of a hack. - while (!s.check_for_listener()) { - // printf("...\n"); + bool connected = l.connect_to_target(); + EXPECT_TRUE(connected); + // TODO - some sort of backoff and retry would be better + while (connected && !s.check_for_listener()) { } EXPECT_TRUE(s.check_for_listener()); @@ -94,37 +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()); - while (!s.check_for_listener()) { - // printf("...\n"); + bool connected = l.connect_to_target(); + EXPECT_TRUE(connected); + // TODO - some sort of backoff and retry would be better + while (connected && !s.check_for_listener()) { } } } - -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(); - } -} - -#endif \ No newline at end of file