diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f448f33..19d1276 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -8,7 +8,7 @@ include(FetchContent) # RayLib FetchContent_Declare( raylib - GIT_REPOSITORY https://github.com/raysan5/raylib - GIT_TAG 5aa3f0ccc374c1fbfc880402b37871b9c3bb7d8e + URL https://github.com/raysan5/raylib/archive/refs/tags/5.5.tar.gz + URL_HASH MD5=61638c4c2c097fbca1d6a71e4da36c16 ) FetchContent_MakeAvailable(raylib) \ No newline at end of file diff --git a/src/dusk.h b/src/dusk.h index dc64519..d192615 100644 --- a/src/dusk.h +++ b/src/dusk.h @@ -19,8 +19,7 @@ #include #include #include - -#include +#include typedef bool bool_t; typedef char char_t; diff --git a/src/network/packet/packetwelcome.c b/src/network/packet/packetwelcome.c index 0fadbfb..b124590 100644 --- a/src/network/packet/packetwelcome.c +++ b/src/network/packet/packetwelcome.c @@ -16,8 +16,12 @@ void packetWelcomeCreate(packet_t *packet) { ); } -errorret_t packetWelcomeClient(packet_t *packet) { +errorret_t packetWelcomeClientProcess( + const packet_t *packet, + client_t *client +) { assertNotNull(packet, "Packet is NULL"); + assertNotNull(client, "Client is NULL"); assertTrue(packet->type == PACKET_TYPE_WELCOME, "Packet type is not WELCOME"); if(packet->length != PACKET_WELCOME_SIZE) { diff --git a/src/network/server/networked/networkedserver.c b/src/network/server/networked/networkedserver.c index fa0872b..f957bca 100644 --- a/src/network/server/networked/networkedserver.c +++ b/src/network/server/networked/networkedserver.c @@ -15,12 +15,12 @@ errorret_t networkedServerStart( const serverstart_t start ) { assertNotNull(server, "Server is null"); - assertTrue(start.type == SERVER_TYPE_NETWORKED,"Invalid server type"); + assertTrue(start.type == SERVER_TYPE_NETWORKED, "Invalid server type"); assertTrue(server->state == SERVER_STATE_STOPPED,"Server is already running"); assertIsMainThread("Server start must be on main thread"); // Initialize the networked server. - consolePrint("Starting server on port %d...\n", start.networked.port); + consolePrint("Starting server on port %d...", start.networked.port); memoryZero(&server->networked, sizeof(server->networked)); // Initialize the server socket @@ -28,10 +28,32 @@ errorret_t networkedServerStart( if(server->networked.socket < 0) { return error("Failed to create socket"); } - server->networked.address.sin_family = AF_INET; + + // Setup the socket options server->networked.address.sin_addr.s_addr = INADDR_ANY; + server->networked.address.sin_family = AF_INET; server->networked.address.sin_port = htons(start.networked.port); + // Set the socket to reuse the address + int opt = 1; + setsockopt( + server->networked.socket, + SOL_SOCKET, + SO_REUSEADDR, + &opt, + sizeof(opt) + ); + + // Set the socket to non-blocking + int flags = fcntl(server->networked.socket, F_GETFL, 0); + if( + flags < 0 || + fcntl(server->networked.socket, F_SETFL, flags | O_NONBLOCK) < 0 + ) { + close(server->networked.socket); + return error("Failed to set socket to non-blocking %s", strerror(errno)); + } + // Bind the socket to the address and port int32_t res = bind( server->networked.socket, @@ -40,36 +62,37 @@ errorret_t networkedServerStart( ); if(res != 0) { close(server->networked.socket); - return error("Failed to bind socket"); + return error( + "Socket bind to port %d failed: %s", + start.networked.port, + strerror(errno) + ); } // Set the socket to listen for incoming connections res = listen(server->networked.socket, SERVER_MAX_CLIENTS); if(res != 0) { close(server->networked.socket); - return error("Failed to listen on socket"); + return error( + "Failed to listen on port %d: %s", + start.networked.port, + strerror(errno) + ); } - // Initialize mutex and condition variable - pthread_mutex_init(&server->networked.lock, NULL); - pthread_cond_init(&server->networked.cond, NULL); // Start the server thread. + pthread_mutex_init(&server->networked.lock, NULL); server->state = SERVER_STATE_STARTING; + res = pthread_create(&server->thread, NULL, networkedServerThread, server); if(res != 0) { - perror("Failed to create server thread"); - serverStop(); + close(server->networked.socket); + pthread_mutex_destroy(&server->networked.lock); + server->state = SERVER_STATE_STOPPED; return error("Failed to create server thread"); } - // Wait for the thread to start. - pthread_mutex_lock(&server->networked.lock); - while(server->state == SERVER_STATE_STARTING) { - pthread_cond_wait(&server->networked.cond, &server->networked.lock); - } - pthread_mutex_unlock(&server->networked.lock); - // Server started, hand back. consolePrint("Server started."); return ERROR_OK; @@ -77,14 +100,13 @@ errorret_t networkedServerStart( void networkedServerStop(server_t *server) { assertNotNull(server, "Server is null"); - assertTrue(server->state != SERVER_STATE_STOPPED, "Server is already stopped"); + assertTrue(server->state != SERVER_STATE_STOPPED,"Server is already stopped"); assertTrue(server->state != SERVER_STATE_STARTING, "Server is starting"); assertIsMainThread("Server stop must be on main thread"); // Notify thread to stop pthread_mutex_lock(&server->networked.lock); server->state = SERVER_STATE_STOPPING; - pthread_cond_signal(&server->networked.cond); pthread_mutex_unlock(&server->networked.lock); // Disconnect clients @@ -95,34 +117,15 @@ void networkedServerStop(server_t *server) { serverClientClose(client); } while(i < SERVER_MAX_CLIENTS); - // Wait for the thread to stop - int32_t maxWaits = 0; - pthread_mutex_lock(&server->networked.lock); - while(server->state == SERVER_STATE_STOPPING) { - if(maxWaits++ >= 1000) { - consolePrint("Server thread did not stop in time, forcing exit."); - server->state = SERVER_STATE_STOPPED; - break; - } - pthread_cond_wait(&server->networked.cond, &server->networked.lock); - } - pthread_mutex_unlock(&server->networked.lock); - - // Destroy mutex and condition variable + // Wait for the server thread to finish + pthread_join(server->thread, NULL); pthread_mutex_destroy(&server->networked.lock); - pthread_cond_destroy(&server->networked.cond); - // Close the socket - if(server->networked.socket >= 0) { - close(server->networked.socket); - server->networked.socket = -1; - } + close(server->networked.socket); - // Term the thread. - if(server->thread) { - pthread_join(server->thread, NULL); - server->thread = 0; - } + server->networked.socket = -1; + server->state = SERVER_STATE_STOPPED; + consolePrint("Server stopped."); } void * networkedServerThread(void *arg) { @@ -131,102 +134,91 @@ void * networkedServerThread(void *arg) { server_t *server = (server_t *)arg; - // Notify main thread that the server is running + // Set server state to running pthread_mutex_lock(&server->networked.lock); server->state = SERVER_STATE_RUNNING; - pthread_cond_signal(&server->networked.cond); pthread_mutex_unlock(&server->networked.lock); - struct timeval timeout; fd_set readfds; + struct timeval timeout; - // Main thread loop. - while(server->state == SERVER_STATE_RUNNING) { - // Prepare the select call, used for waiting for incoming connections. + // Main server loop + while (1) { + // Check if the server should continue running + pthread_mutex_lock(&server->networked.lock); + if (server->state != SERVER_STATE_RUNNING) { + pthread_mutex_unlock(&server->networked.lock); + break; + } + pthread_mutex_unlock(&server->networked.lock); + + // Prepare the select call to wait for new connections FD_ZERO(&readfds); FD_SET(server->networked.socket, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; // Wait for incoming connections - int32_t activity = select( + int activity = select( server->networked.socket + 1, &readfds, NULL, NULL, &timeout ); + if (activity <= 0) continue; + if (!FD_ISSET(server->networked.socket, &readfds)) continue; - // Timeout or no activity - if(activity <= 0) continue; - - // Check if there is a new connection - if(!FD_ISSET(server->networked.socket, &readfds)) continue; - - // Accept new connection. + // Accept incoming connection int32_t clientSocket = accept(server->networked.socket, NULL, NULL); - if(clientSocket < 0) { + if (clientSocket < 0) { consolePrint("Failed to accept connection"); continue; } - // Find an available client slot. + // Find an available client slot serverclient_t *client = NULL; - uint8_t i = 0; - do { + for (uint8_t i = 0; i < SERVER_MAX_CLIENTS; i++) { if(server->clients[i].state != SERVER_CLIENT_STATE_DISCONNECTED) { - i++; continue; } client = &server->clients[i]; break; - } while(i < SERVER_MAX_CLIENTS); + } - // No available slots were found (Server full). This is the only time a - // packet is sent without a client thread. - if(!client) { + // Server full, send disconnect packet + if (!client) { packet_t packet; serverclient_t tempClient = { - .networked = { - .socket = clientSocket, - }, + .networked = { .socket = clientSocket }, .server = server, .state = SERVER_CLIENT_STATE_ACCEPTING }; packetDisconnectCreate(&packet, PACKET_DISCONNECT_REASON_SERVER_FULL); networkedServerClientWritePacket(&tempClient, &packet); - if(errorCheck()) errorPrint(); - consolePrint("Client %i disconnected: Server full."); + if (errorCheck()) errorPrint(); + consolePrint("Client disconnected: Server full."); close(clientSocket); continue; } - // Hand off to server client for acceptance. Only one client can be - // accepted at a time at the moment. + // Accept the client into the server errorret_t ret = serverClientAccept(client, (serverclientaccept_t){ .server = server, - .networked = { - .socket = clientSocket, - } + .networked = { .socket = clientSocket } }); - if(ret != ERROR_OK) { - consolePrint("Failed to accept client connection", errorString()); + if (ret != ERROR_OK) { + consolePrint("Failed to accept client connection: %s", errorString()); errorFlush(); close(clientSocket); } } - // Thread loop was exited. This is only possible when the server is stopped. - assertTrue( - server->state != SERVER_STATE_RUNNING, - "Server thread exiting while server is running?" - ); - - // Notify main thread that the server has stopped + // Cleanup and signal server stop pthread_mutex_lock(&server->networked.lock); server->state = SERVER_STATE_STOPPED; - pthread_cond_signal(&server->networked.cond); pthread_mutex_unlock(&server->networked.lock); + consolePrint("Server thread exiting."); return NULL; -} \ No newline at end of file +} diff --git a/src/network/server/networked/networkedserver.h b/src/network/server/networked/networkedserver.h index 4512ae7..32c5563 100644 --- a/src/network/server/networked/networkedserver.h +++ b/src/network/server/networked/networkedserver.h @@ -18,7 +18,6 @@ typedef struct { int socket; struct sockaddr_in address; pthread_mutex_t lock; - pthread_cond_t cond; } networkedserver_t; typedef struct server_s server_t; diff --git a/src/network/server/networked/networkedserverclient.c b/src/network/server/networked/networkedserverclient.c index 72ba6b1..b52ae5b 100644 --- a/src/network/server/networked/networkedserverclient.c +++ b/src/network/server/networked/networkedserverclient.c @@ -26,7 +26,7 @@ errorret_t networkedServerClientAccept( client->networked.socket = accept.networked.socket; // Set timeout to 8 seconds - client->networked.timeout.tv_sec = 4; + client->networked.timeout.tv_sec = 8; client->networked.timeout.tv_usec = 0; // Initialize mutexs diff --git a/src/network/server/server.c b/src/network/server/server.c index f5fb9c1..99d744a 100644 --- a/src/network/server/server.c +++ b/src/network/server/server.c @@ -17,7 +17,7 @@ void cmdStart(const consolecmdexec_t *exec) { serverstart_t start; if(exec->argc > 0) { - if(stringCompare(exec->argv[1], "0") == 0) { + if(stringCompare(exec->argv[0], "0") == 0) { start.type = SERVER_TYPE_SINGLE_PLAYER; } else if(stringCompare(exec->argv[0], "1") == 0) { start.type = SERVER_TYPE_NETWORKED; @@ -90,7 +90,7 @@ errorret_t serverStart(const serverstart_t start) { uint8_t serverGetClientCount() { uint8_t i = 0, clientCount = 0; do { - if(SERVER.clients[i].state == SERVER_CLIENT_STATE_DISCONNECTED) continue; + if(SERVER.clients[i++].state == SERVER_CLIENT_STATE_DISCONNECTED) continue; clientCount++; } while(i < SERVER_MAX_CLIENTS); return clientCount;