Abt to refactor again

This commit is contained in:
2025-04-28 07:49:03 -05:00
parent 3639fb211c
commit 28e8466a2a
7 changed files with 91 additions and 97 deletions

View File

@ -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)

View File

@ -19,8 +19,7 @@
#include <raylib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
typedef bool bool_t;
typedef char char_t;

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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

View File

@ -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;