Abt to refactor again
This commit is contained in:
@ -8,7 +8,7 @@ include(FetchContent)
|
|||||||
# RayLib
|
# RayLib
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
raylib
|
raylib
|
||||||
GIT_REPOSITORY https://github.com/raysan5/raylib
|
URL https://github.com/raysan5/raylib/archive/refs/tags/5.5.tar.gz
|
||||||
GIT_TAG 5aa3f0ccc374c1fbfc880402b37871b9c3bb7d8e
|
URL_HASH MD5=61638c4c2c097fbca1d6a71e4da36c16
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(raylib)
|
FetchContent_MakeAvailable(raylib)
|
@ -19,8 +19,7 @@
|
|||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
typedef bool bool_t;
|
typedef bool bool_t;
|
||||||
typedef char char_t;
|
typedef char char_t;
|
||||||
|
@ -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(packet, "Packet is NULL");
|
||||||
|
assertNotNull(client, "Client is NULL");
|
||||||
assertTrue(packet->type == PACKET_TYPE_WELCOME, "Packet type is not WELCOME");
|
assertTrue(packet->type == PACKET_TYPE_WELCOME, "Packet type is not WELCOME");
|
||||||
|
|
||||||
if(packet->length != PACKET_WELCOME_SIZE) {
|
if(packet->length != PACKET_WELCOME_SIZE) {
|
||||||
|
@ -20,7 +20,7 @@ errorret_t networkedServerStart(
|
|||||||
assertIsMainThread("Server start must be on main thread");
|
assertIsMainThread("Server start must be on main thread");
|
||||||
|
|
||||||
// Initialize the networked server.
|
// 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));
|
memoryZero(&server->networked, sizeof(server->networked));
|
||||||
|
|
||||||
// Initialize the server socket
|
// Initialize the server socket
|
||||||
@ -28,10 +28,32 @@ errorret_t networkedServerStart(
|
|||||||
if(server->networked.socket < 0) {
|
if(server->networked.socket < 0) {
|
||||||
return error("Failed to create socket");
|
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_addr.s_addr = INADDR_ANY;
|
||||||
|
server->networked.address.sin_family = AF_INET;
|
||||||
server->networked.address.sin_port = htons(start.networked.port);
|
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
|
// Bind the socket to the address and port
|
||||||
int32_t res = bind(
|
int32_t res = bind(
|
||||||
server->networked.socket,
|
server->networked.socket,
|
||||||
@ -40,36 +62,37 @@ errorret_t networkedServerStart(
|
|||||||
);
|
);
|
||||||
if(res != 0) {
|
if(res != 0) {
|
||||||
close(server->networked.socket);
|
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
|
// Set the socket to listen for incoming connections
|
||||||
res = listen(server->networked.socket, SERVER_MAX_CLIENTS);
|
res = listen(server->networked.socket, SERVER_MAX_CLIENTS);
|
||||||
if(res != 0) {
|
if(res != 0) {
|
||||||
close(server->networked.socket);
|
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.
|
// Start the server thread.
|
||||||
|
pthread_mutex_init(&server->networked.lock, NULL);
|
||||||
server->state = SERVER_STATE_STARTING;
|
server->state = SERVER_STATE_STARTING;
|
||||||
|
|
||||||
res = pthread_create(&server->thread, NULL, networkedServerThread, server);
|
res = pthread_create(&server->thread, NULL, networkedServerThread, server);
|
||||||
if(res != 0) {
|
if(res != 0) {
|
||||||
perror("Failed to create server thread");
|
close(server->networked.socket);
|
||||||
serverStop();
|
pthread_mutex_destroy(&server->networked.lock);
|
||||||
|
server->state = SERVER_STATE_STOPPED;
|
||||||
return error("Failed to create server thread");
|
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.
|
// Server started, hand back.
|
||||||
consolePrint("Server started.");
|
consolePrint("Server started.");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@ -84,7 +107,6 @@ void networkedServerStop(server_t *server) {
|
|||||||
// Notify thread to stop
|
// Notify thread to stop
|
||||||
pthread_mutex_lock(&server->networked.lock);
|
pthread_mutex_lock(&server->networked.lock);
|
||||||
server->state = SERVER_STATE_STOPPING;
|
server->state = SERVER_STATE_STOPPING;
|
||||||
pthread_cond_signal(&server->networked.cond);
|
|
||||||
pthread_mutex_unlock(&server->networked.lock);
|
pthread_mutex_unlock(&server->networked.lock);
|
||||||
|
|
||||||
// Disconnect clients
|
// Disconnect clients
|
||||||
@ -95,34 +117,15 @@ void networkedServerStop(server_t *server) {
|
|||||||
serverClientClose(client);
|
serverClientClose(client);
|
||||||
} while(i < SERVER_MAX_CLIENTS);
|
} while(i < SERVER_MAX_CLIENTS);
|
||||||
|
|
||||||
// Wait for the thread to stop
|
// Wait for the server thread to finish
|
||||||
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
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Term the thread.
|
|
||||||
if(server->thread) {
|
|
||||||
pthread_join(server->thread, NULL);
|
pthread_join(server->thread, NULL);
|
||||||
server->thread = 0;
|
pthread_mutex_destroy(&server->networked.lock);
|
||||||
}
|
|
||||||
|
close(server->networked.socket);
|
||||||
|
|
||||||
|
server->networked.socket = -1;
|
||||||
|
server->state = SERVER_STATE_STOPPED;
|
||||||
|
consolePrint("Server stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void * networkedServerThread(void *arg) {
|
void * networkedServerThread(void *arg) {
|
||||||
@ -131,102 +134,91 @@ void * networkedServerThread(void *arg) {
|
|||||||
|
|
||||||
server_t *server = (server_t *)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);
|
pthread_mutex_lock(&server->networked.lock);
|
||||||
server->state = SERVER_STATE_RUNNING;
|
server->state = SERVER_STATE_RUNNING;
|
||||||
pthread_cond_signal(&server->networked.cond);
|
|
||||||
pthread_mutex_unlock(&server->networked.lock);
|
pthread_mutex_unlock(&server->networked.lock);
|
||||||
|
|
||||||
struct timeval timeout;
|
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
// Main thread loop.
|
// Main server loop
|
||||||
while(server->state == SERVER_STATE_RUNNING) {
|
while (1) {
|
||||||
// Prepare the select call, used for waiting for incoming connections.
|
// 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_ZERO(&readfds);
|
||||||
FD_SET(server->networked.socket, &readfds);
|
FD_SET(server->networked.socket, &readfds);
|
||||||
timeout.tv_sec = 1;
|
timeout.tv_sec = 1;
|
||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
// Wait for incoming connections
|
// Wait for incoming connections
|
||||||
int32_t activity = select(
|
int activity = select(
|
||||||
server->networked.socket + 1,
|
server->networked.socket + 1,
|
||||||
&readfds,
|
&readfds,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&timeout
|
&timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
// Timeout or no activity
|
|
||||||
if (activity <= 0) continue;
|
if (activity <= 0) continue;
|
||||||
|
|
||||||
// Check if there is a new connection
|
|
||||||
if (!FD_ISSET(server->networked.socket, &readfds)) continue;
|
if (!FD_ISSET(server->networked.socket, &readfds)) continue;
|
||||||
|
|
||||||
// Accept new connection.
|
// Accept incoming connection
|
||||||
int32_t clientSocket = accept(server->networked.socket, NULL, NULL);
|
int32_t clientSocket = accept(server->networked.socket, NULL, NULL);
|
||||||
if (clientSocket < 0) {
|
if (clientSocket < 0) {
|
||||||
consolePrint("Failed to accept connection");
|
consolePrint("Failed to accept connection");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find an available client slot.
|
// Find an available client slot
|
||||||
serverclient_t *client = NULL;
|
serverclient_t *client = NULL;
|
||||||
uint8_t i = 0;
|
for (uint8_t i = 0; i < SERVER_MAX_CLIENTS; i++) {
|
||||||
do {
|
|
||||||
if(server->clients[i].state != SERVER_CLIENT_STATE_DISCONNECTED) {
|
if(server->clients[i].state != SERVER_CLIENT_STATE_DISCONNECTED) {
|
||||||
i++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
client = &server->clients[i];
|
client = &server->clients[i];
|
||||||
break;
|
break;
|
||||||
} while(i < SERVER_MAX_CLIENTS);
|
}
|
||||||
|
|
||||||
// No available slots were found (Server full). This is the only time a
|
// Server full, send disconnect packet
|
||||||
// packet is sent without a client thread.
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
packet_t packet;
|
packet_t packet;
|
||||||
serverclient_t tempClient = {
|
serverclient_t tempClient = {
|
||||||
.networked = {
|
.networked = { .socket = clientSocket },
|
||||||
.socket = clientSocket,
|
|
||||||
},
|
|
||||||
.server = server,
|
.server = server,
|
||||||
.state = SERVER_CLIENT_STATE_ACCEPTING
|
.state = SERVER_CLIENT_STATE_ACCEPTING
|
||||||
};
|
};
|
||||||
packetDisconnectCreate(&packet, PACKET_DISCONNECT_REASON_SERVER_FULL);
|
packetDisconnectCreate(&packet, PACKET_DISCONNECT_REASON_SERVER_FULL);
|
||||||
networkedServerClientWritePacket(&tempClient, &packet);
|
networkedServerClientWritePacket(&tempClient, &packet);
|
||||||
if (errorCheck()) errorPrint();
|
if (errorCheck()) errorPrint();
|
||||||
consolePrint("Client %i disconnected: Server full.");
|
consolePrint("Client disconnected: Server full.");
|
||||||
close(clientSocket);
|
close(clientSocket);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hand off to server client for acceptance. Only one client can be
|
// Accept the client into the server
|
||||||
// accepted at a time at the moment.
|
|
||||||
errorret_t ret = serverClientAccept(client, (serverclientaccept_t){
|
errorret_t ret = serverClientAccept(client, (serverclientaccept_t){
|
||||||
.server = server,
|
.server = server,
|
||||||
.networked = {
|
.networked = { .socket = clientSocket }
|
||||||
.socket = clientSocket,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (ret != ERROR_OK) {
|
if (ret != ERROR_OK) {
|
||||||
consolePrint("Failed to accept client connection", errorString());
|
consolePrint("Failed to accept client connection: %s", errorString());
|
||||||
errorFlush();
|
errorFlush();
|
||||||
close(clientSocket);
|
close(clientSocket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread loop was exited. This is only possible when the server is stopped.
|
// Cleanup and signal server stop
|
||||||
assertTrue(
|
|
||||||
server->state != SERVER_STATE_RUNNING,
|
|
||||||
"Server thread exiting while server is running?"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Notify main thread that the server has stopped
|
|
||||||
pthread_mutex_lock(&server->networked.lock);
|
pthread_mutex_lock(&server->networked.lock);
|
||||||
server->state = SERVER_STATE_STOPPED;
|
server->state = SERVER_STATE_STOPPED;
|
||||||
pthread_cond_signal(&server->networked.cond);
|
|
||||||
pthread_mutex_unlock(&server->networked.lock);
|
pthread_mutex_unlock(&server->networked.lock);
|
||||||
|
|
||||||
|
consolePrint("Server thread exiting.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
@ -18,7 +18,6 @@ typedef struct {
|
|||||||
int socket;
|
int socket;
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
pthread_cond_t cond;
|
|
||||||
} networkedserver_t;
|
} networkedserver_t;
|
||||||
|
|
||||||
typedef struct server_s server_t;
|
typedef struct server_s server_t;
|
||||||
|
@ -26,7 +26,7 @@ errorret_t networkedServerClientAccept(
|
|||||||
client->networked.socket = accept.networked.socket;
|
client->networked.socket = accept.networked.socket;
|
||||||
|
|
||||||
// Set timeout to 8 seconds
|
// Set timeout to 8 seconds
|
||||||
client->networked.timeout.tv_sec = 4;
|
client->networked.timeout.tv_sec = 8;
|
||||||
client->networked.timeout.tv_usec = 0;
|
client->networked.timeout.tv_usec = 0;
|
||||||
|
|
||||||
// Initialize mutexs
|
// Initialize mutexs
|
||||||
|
@ -17,7 +17,7 @@ void cmdStart(const consolecmdexec_t *exec) {
|
|||||||
serverstart_t start;
|
serverstart_t start;
|
||||||
|
|
||||||
if(exec->argc > 0) {
|
if(exec->argc > 0) {
|
||||||
if(stringCompare(exec->argv[1], "0") == 0) {
|
if(stringCompare(exec->argv[0], "0") == 0) {
|
||||||
start.type = SERVER_TYPE_SINGLE_PLAYER;
|
start.type = SERVER_TYPE_SINGLE_PLAYER;
|
||||||
} else if(stringCompare(exec->argv[0], "1") == 0) {
|
} else if(stringCompare(exec->argv[0], "1") == 0) {
|
||||||
start.type = SERVER_TYPE_NETWORKED;
|
start.type = SERVER_TYPE_NETWORKED;
|
||||||
@ -90,7 +90,7 @@ errorret_t serverStart(const serverstart_t start) {
|
|||||||
uint8_t serverGetClientCount() {
|
uint8_t serverGetClientCount() {
|
||||||
uint8_t i = 0, clientCount = 0;
|
uint8_t i = 0, clientCount = 0;
|
||||||
do {
|
do {
|
||||||
if(SERVER.clients[i].state == SERVER_CLIENT_STATE_DISCONNECTED) continue;
|
if(SERVER.clients[i++].state == SERVER_CLIENT_STATE_DISCONNECTED) continue;
|
||||||
clientCount++;
|
clientCount++;
|
||||||
} while(i < SERVER_MAX_CLIENTS);
|
} while(i < SERVER_MAX_CLIENTS);
|
||||||
return clientCount;
|
return clientCount;
|
||||||
|
Reference in New Issue
Block a user