From a89671351093ccc210275686ed724edf93e1f6e4 Mon Sep 17 00:00:00 2001 From: MysterD Date: Sun, 9 Aug 2020 13:23:27 -0700 Subject: [PATCH] Made sockets platform-independent, supporting Linux --- Makefile | 7 +-- network.sh | 18 +++++- src/game/ingame_menu.c | 3 + src/menu/star_select.c | 5 +- src/pc/network/network.c | 87 +++++++------------------- src/pc/network/packets/packet_object.c | 1 + src/pc/network/socket/socket.c | 49 +++++++++++++++ src/pc/network/socket/socket.h | 16 +++++ src/pc/network/socket/socket_linux.c | 30 +++++++++ src/pc/network/socket/socket_linux.h | 18 ++++++ src/pc/network/socket/socket_windows.c | 40 ++++++++++++ src/pc/network/socket/socket_windows.h | 11 ++++ 12 files changed, 211 insertions(+), 74 deletions(-) mode change 100644 => 100755 network.sh create mode 100644 src/pc/network/socket/socket.c create mode 100644 src/pc/network/socket/socket.h create mode 100644 src/pc/network/socket/socket_linux.c create mode 100644 src/pc/network/socket/socket_linux.h create mode 100644 src/pc/network/socket/socket_windows.c create mode 100644 src/pc/network/socket/socket_windows.h diff --git a/Makefile b/Makefile index 84225e7c..04efab65 100644 --- a/Makefile +++ b/Makefile @@ -286,7 +286,7 @@ LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h))) # Directories containing source files # Hi, I'm a PC -SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/pc/network src/pc/network/packets +SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/pc/network src/pc/network/packets src/pc/network/socket ASM_DIRS := ifeq ($(DISCORDRPC),1) @@ -526,9 +526,8 @@ ifeq ($(SDL_USED),2) endif ifeq ($(WINDOWS_BUILD),1) - CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) - CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv - + CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -DWINSOCK + CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -DWINSOCK else ifeq ($(TARGET_WEB),1) CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2 CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -s USE_SDL=2 diff --git a/network.sh b/network.sh old mode 100644 new mode 100755 index 84bbdda0..58955d55 --- a/network.sh +++ b/network.sh @@ -1,5 +1,17 @@ set -e make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 -./build/us_pc/sm64.us.f3dex2e.exe --server --configfile sm64config_server.txt & -#./build/us_pc/sm64.us.f3dex2e.exe --client --configfile sm64config_client.txt & -winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run --client --configfile sm64config_client.txt' -ex 'quit' + +# find file +FILE=./build/us_pc/sm64.us.f3dex2e.exe +if [ ! -f "$FILE" ]; then + FILE=./build/us_pc/sm64.us.f3dex2e +fi + +$FILE --server --configfile sm64config_server.txt & + +# debug if cgdb exists +if ! [ -x "$(command -v cgdb)" ]; then + $FILE --client --configfile sm64config_client.txt & +else + winpty cgdb $FILE -ex 'break debug_breakpoint_here' -ex 'run --client --configfile sm64config_client.txt' -ex 'quit' +fi diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 832884b2..d411bf00 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -2765,7 +2765,10 @@ s16 render_sync_level_screen(void) { u8 colorFade = sins(gDialogColorFadeTimer) * 50.0f + 200.0f; gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255); + + #define TEXT_SYNCHRONIZING 0x1C,0x22,0x17,0x0C,0x11,0x1B,0x18,0x17,0x12,0x02,0x12,0x17,0x10,0xFF u8 synchronizing[] = { TEXT_SYNCHRONIZING }; + print_hud_lut_string(HUD_LUT_GLOBAL, 80, 200, synchronizing); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); diff --git a/src/menu/star_select.c b/src/menu/star_select.c index 03856a26..17ac8a08 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -263,7 +263,10 @@ void print_act_selector_strings(void) { u8 colorFade = sin(fadeTimer++ * 0.2f) * 50.0f + 200.0f; gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, colorFade, colorFade, colorFade, 255); + + #define TEXT_SYNCHRONIZING 0x1C,0x22,0x17,0x0C,0x11,0x1B,0x18,0x17,0x12,0x02,0x12,0x17,0x10,0xFF u8 synchronizing[] = { TEXT_SYNCHRONIZING }; + print_hud_lut_string(HUD_LUT_GLOBAL, 80, 8, synchronizing); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); } @@ -456,4 +459,4 @@ void star_select_finish_selection(void) { sLoadedActNum = sInitSelectedActNum; } gDialogCourseActNum = sSelectedActIndex + 1; -} \ No newline at end of file +} diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 86584e58..5d2e496d 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -2,15 +2,7 @@ #include "network.h" #include "object_fields.h" #include "object_constants.h" - -// Winsock includes -#include -#include -//#pragma comment(lib, "Ws2_32.lib") - -////////////////////////// -// TODO: port to linux! // -////////////////////////// +#include "socket/socket.h" enum NetworkType networkType; SOCKET gSocket; @@ -20,62 +12,34 @@ void network_init(enum NetworkType inNetworkType) { networkType = inNetworkType; if (networkType == NT_NONE) { return; } - //----------------------------------------------- - // Initialize Winsock - WSADATA wsaData; - int rc = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (rc != NO_ERROR) { - wprintf(L"%s WSAStartup failed with error %d\n", NETWORKTYPESTR, rc); - return; - } - //----------------------------------------------- // Create a receiver socket to receive datagrams - gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (gSocket == INVALID_SOCKET) { - wprintf(L"%s socket failed with error %d\n", NETWORKTYPESTR, WSAGetLastError()); - return; - } - - // Set non-blocking mode - u_long iMode = 1; - rc = ioctlsocket(gSocket, FIONBIO, &iMode); - if (rc != NO_ERROR) { - printf("%s ioctlsocket failed with error: %ld\n", NETWORKTYPESTR, rc); - } + gSocket = socket_initialize(); + if (gSocket == INVALID_SOCKET) { return; } // Bind the socket to any address and the specified port. - struct sockaddr_in rxAddr; - rxAddr.sin_family = AF_INET; - rxAddr.sin_port = htons(networkType == NT_SERVER ? 27015 : 27016); - rxAddr.sin_addr.s_addr = htonl(INADDR_ANY); - rc = bind(gSocket, (SOCKADDR *)& rxAddr, sizeof(rxAddr)); - if (rc != 0) { - wprintf(L"%s bind failed with error %d\n", NETWORKTYPESTR, WSAGetLastError()); - return; - } + unsigned int port = (networkType == NT_SERVER) ? 27015 : 27016; + int rc = socket_bind(gSocket, port); + if (rc != NO_ERROR) { return; } // Save the port to send to - txPort = htons(networkType == NT_SERVER ? 27016 : 27015); + txPort = (networkType == NT_SERVER) ? 27016 : 27015; } void network_send(struct Packet* p) { + // sanity checks if (networkType == NT_NONE) { return; } if (p->error) { printf("%s packet error!\n", NETWORKTYPESTR); return; } - struct sockaddr_in txAddr; - txAddr.sin_family = AF_INET; - txAddr.sin_port = txPort; - txAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + // remember reliable packets network_remember_reliable(p); + // save inside packet buffer u32 hash = packet_hash(p); memcpy(&p->buffer[p->dataLength], &hash, sizeof(u32)); - int rc = sendto(gSocket, p->buffer, p->cursor + sizeof(u32), 0, (SOCKADDR *)& txAddr, sizeof(txAddr)); - if (rc == SOCKET_ERROR) { - wprintf(L"%s sendto failed with error: %d\n", NETWORKTYPESTR, WSAGetLastError()); - return; - } + // send + int rc = socket_send(gSocket, "127.0.0.1", txPort, p->buffer, p->cursor + sizeof(u32)); + if (rc != NO_ERROR) { return; } p->sent = true; } @@ -93,24 +57,19 @@ void network_update(void) { } do { - struct sockaddr_in rxAddr; - int rxAddrSize = sizeof(rxAddr); + // receive packet struct Packet p = { .cursor = 3 }; - int rc = recvfrom(gSocket, p.buffer, PACKET_LENGTH, 0, (SOCKADDR *)&rxAddr, &rxAddrSize); - if (rc == SOCKET_ERROR) { - int error = WSAGetLastError(); - if (error != WSAEWOULDBLOCK && error != WSAECONNRESET) { - wprintf(L"%s recvfrom failed with error %d\n", NETWORKTYPESTR, WSAGetLastError()); - } - break; - } - if (rc == 0) { break; } + int rc = socket_receive(gSocket, p.buffer, PACKET_LENGTH, &p.dataLength); + if (rc != NO_ERROR) { break; } - p.dataLength = rc - sizeof(u32); + // subtract and check hash + p.dataLength -= sizeof(u32); if (!packet_check_hash(&p)) { printf("Invalid packet!\n"); + continue; } + // execute packet switch (p.buffer[0]) { case PACKET_ACK: network_receive_ack(&p); break; case PACKET_PLAYER: network_receive_player(&p); break; @@ -134,9 +93,5 @@ void network_update(void) { void network_shutdown(void) { if (networkType == NT_NONE) { return; } - int rc = closesocket(gSocket); - if (rc == SOCKET_ERROR) { - wprintf(L"%s closesocket failed with error %d\n", NETWORKTYPESTR, WSAGetLastError()); - } - WSACleanup(); + socket_close(gSocket); } diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 3178fbd6..48589d50 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -1,4 +1,5 @@ #include +#include #include "../network.h" #include "object_fields.h" #include "object_constants.h" diff --git a/src/pc/network/socket/socket.c b/src/pc/network/socket/socket.c new file mode 100644 index 00000000..b47ca59a --- /dev/null +++ b/src/pc/network/socket/socket.c @@ -0,0 +1,49 @@ +#include "socket.h" +#include "../network.h" + +int socket_bind(SOCKET sock, unsigned int port) { + struct sockaddr_in rxAddr; + rxAddr.sin_family = AF_INET; + rxAddr.sin_port = htons(port); + rxAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + int rc = bind(sock, (SOCKADDR*)&rxAddr, sizeof(rxAddr)); + if (rc != 0) { + printf("%s bind failed with error %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + } + + return rc; +} + +int socket_send(SOCKET sock, char* ip, unsigned int port, char* buffer, int bufferLength) { + struct sockaddr_in txAddr; + txAddr.sin_family = AF_INET; + txAddr.sin_port = htons(port); + txAddr.sin_addr.s_addr = inet_addr(ip); + + int rc = sendto(sock, buffer, bufferLength, 0, (SOCKADDR*)&txAddr, sizeof(txAddr)); + if (rc == SOCKET_ERROR) { + printf("%s sendto failed with error: %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + } + + return rc; +} + +int socket_receive(SOCKET sock, char* buffer, int bufferLength, int* receiveLength) { + *receiveLength = 0; + + struct sockaddr_in rxAddr; + int rxAddrSize = sizeof(rxAddr); + + int rc = recvfrom(sock, buffer, bufferLength, 0, (SOCKADDR*)&rxAddr, &rxAddrSize); + if (rc == SOCKET_ERROR) { + int error = SOCKET_LAST_ERROR; + if (error != EWOULDBLOCK && error != ECONNRESET) { + printf("%s recvfrom failed with error %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + } + return rc; + } + + *receiveLength = rc; + return NO_ERROR; +} diff --git a/src/pc/network/socket/socket.h b/src/pc/network/socket/socket.h new file mode 100644 index 00000000..2687e9d9 --- /dev/null +++ b/src/pc/network/socket/socket.h @@ -0,0 +1,16 @@ +#ifndef SOCKET_H +#define SOCKET_H + +#ifdef WINSOCK +#include "socket_windows.h" +#else +#include "socket_linux.h" +#endif + +SOCKET socket_initialize(void); +int socket_bind(SOCKET sock, unsigned int port); +int socket_send(SOCKET sock, char* ip, unsigned int port, char* buffer, int bufferLength); +int socket_receive(SOCKET sock, char* buffer, int bufferLength, int* receiveLength); +void socket_close(SOCKET sock); + +#endif diff --git a/src/pc/network/socket/socket_linux.c b/src/pc/network/socket/socket_linux.c new file mode 100644 index 00000000..b66706e9 --- /dev/null +++ b/src/pc/network/socket/socket_linux.c @@ -0,0 +1,30 @@ +#ifndef WINSOCK +#include "socket_linux.h" +#include "../network.h" + +SOCKET socket_initialize(void) { + // initialize socket + SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock == INVALID_SOCKET) { + printf("%s socket failed with error %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + return INVALID_SOCKET; + } + + // set non-blocking mode + int rc = fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK); + if (rc == INVALID_SOCKET) { + printf("%s fcntl failed with error: %d\n", NETWORKTYPESTR, rc); + return INVALID_SOCKET; + } + + return sock; +} + +void socket_close(SOCKET sock) { + int rc = closesocket(sock); + if (rc == SOCKET_ERROR) { + printf("%s closesocket failed with error %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + } +} + +#endif diff --git a/src/pc/network/socket/socket_linux.h b/src/pc/network/socket/socket_linux.h new file mode 100644 index 00000000..282b35dc --- /dev/null +++ b/src/pc/network/socket/socket_linux.h @@ -0,0 +1,18 @@ +#ifndef SOCKET_LINUX_H +#define SOCKET_LINUX_H + +#include +#include +#include +#include +#include + +#define SOCKET unsigned int +#define INVALID_SOCKET (unsigned int)(-1) +#define SOCKET_LAST_ERROR errno +#define NO_ERROR (0) +#define SOCKADDR struct sockaddr +#define SOCKET_ERROR (-1) +#define closesocket(fd) close(fd) + +#endif diff --git a/src/pc/network/socket/socket_windows.c b/src/pc/network/socket/socket_windows.c new file mode 100644 index 00000000..f6017077 --- /dev/null +++ b/src/pc/network/socket/socket_windows.c @@ -0,0 +1,40 @@ +#ifdef WINSOCK +#include "socket_windows.h" +#include "../network.h" + +SOCKET socket_initialize(void) { + // start up winsock + WSADATA wsaData; + int rc = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (rc != NO_ERROR) { + printf("%s WSAStartup failed with error %d\n", NETWORKTYPESTR, rc); + return INVALID_SOCKET; + } + + // initialize socket + SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock == INVALID_SOCKET) { + printf("%s socket failed with error %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + return INVALID_SOCKET; + } + + // set non-blocking mode + u_long iMode = 1; + rc = ioctlsocket(sock, FIONBIO, &iMode); + if (rc != NO_ERROR) { + printf("%s ioctlsocket failed with error: %d\n", NETWORKTYPESTR, rc); + return INVALID_SOCKET; + } + + return sock; +} + +void socket_close(SOCKET sock) { + int rc = closesocket(sock); + if (rc == SOCKET_ERROR) { + printf("%s closesocket failed with error %d\n", NETWORKTYPESTR, SOCKET_LAST_ERROR); + } + WSACleanup(); +} + +#endif diff --git a/src/pc/network/socket/socket_windows.h b/src/pc/network/socket/socket_windows.h new file mode 100644 index 00000000..5c37c3b3 --- /dev/null +++ b/src/pc/network/socket/socket_windows.h @@ -0,0 +1,11 @@ +#ifndef SOCKET_WINDOWS_H +#define SOCKET_WINDOWS_H + +#include +#include + +#define SOCKET_LAST_ERROR WSAGetLastError() +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ECONNRESET WSAECONNRESET + +#endif