From 2f7935980646885b8458c4456cd266ea6eaa6652 Mon Sep 17 00:00:00 2001 From: Barry Kane Date: Sat, 14 Oct 2023 00:27:03 +0100 Subject: [PATCH] Working Tree On <2023-10-13> Signed-off-by: Barry Kane --- source/Spacewar-Client.c | 58 +++++++++++--- source/Spacewar-Graphics.h | 4 +- source/Spacewar-Messages.h | 7 +- source/Spacewar-Physics.h | 5 +- source/Spacewar-Server.c | 153 +++++++++++++++++++++++++------------ source/Spacewar-Server.h | 14 +++- 6 files changed, 172 insertions(+), 69 deletions(-) diff --git a/source/Spacewar-Client.c b/source/Spacewar-Client.c index 0ca4651..50c96cd 100644 --- a/source/Spacewar-Client.c +++ b/source/Spacewar-Client.c @@ -3,15 +3,18 @@ // | Copyright (C) 2023, Barra Ó Catháin | // | See end of file for copyright notice. | // ========================================= +#include #include #include #include #include #include #include - -#include "Spacewar-Server.h" +#include "Spacewar-Messages.h" #include "Spacewar-Graphics.h" +#include "Spacewar-Server.h" + +const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG", "SECRET"}; int main(int argc, char ** argv) { @@ -49,10 +52,7 @@ int main(int argc, char ** argv) // Set up event handling: SDL_Event event; bool keepRunning = true; - - SpacewarServerConfiguration serverConfig = {5200}; - pthread_t serverThread; - pthread_create(&serverThread, NULL, runSpacewarServer, &serverConfig); + bool runServer = false; // Display the titlescreen until we get an input: while (!titlescreenInput && keepRunning) @@ -79,7 +79,12 @@ int main(int argc, char ** argv) { titlescreenInput = true; } - + if(keyboardState[SDL_SCANCODE_SPACE] == 1 && !runServer) + { + runServer = true; + printf("Running server!\n"); + } + // Draw the title screen: drawTitleScreen(&titlescreen); @@ -87,6 +92,14 @@ int main(int argc, char ** argv) SDL_Delay(1000 / 60); } + if (runServer) + { + SpacewarServerConfiguration serverConfig = {5200}; + pthread_t serverThread; + pthread_create(&serverThread, NULL, runSpacewarServer, &serverConfig); + sleep(1); + } + // Give me a socket, and make sure it's working: int serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket == -1) @@ -108,13 +121,40 @@ int main(int argc, char ** argv) exit(0); } - while(true) + printf("Connected.\n"); + + bool playerNumberSet, secretKeySet; + uint32_t playerNumber, secretKey; + SpacewarMessage message; + + while (!playerNumberSet || !secretKeySet) { - usleep(1); + recv(serverSocket, &message, sizeof(SpacewarMessage), 0); + switch (message.type) + { + case 0: + { + playerNumberSet = true; + playerNumber = message.content; + break; + } + case 4: + { + secretKeySet = true; + secretKey = message.content; + } + } } + + printf("Player Number: %u\n" + "Secret Key: %u\n", playerNumber, secretKey); + // Spawn network thread: // Spawn game thread: + while(keepRunning) + { + } // Spawn graphics thread: diff --git a/source/Spacewar-Graphics.h b/source/Spacewar-Graphics.h index dd94e32..f0a2a22 100644 --- a/source/Spacewar-Graphics.h +++ b/source/Spacewar-Graphics.h @@ -3,8 +3,8 @@ // | Copyright (C) 2023, Barra Ó Catháin | // | See end of file for copyright notice. | // ========================================= -#ifndef SPACEWAR_GRAPHICS -#define SPACEWAR_GRAPHICS +#ifndef SPACEWAR_GRAPHICS_H +#define SPACEWAR_GRAPHICS_H #include #include diff --git a/source/Spacewar-Messages.h b/source/Spacewar-Messages.h index d0c8775..ed3d72e 100644 --- a/source/Spacewar-Messages.h +++ b/source/Spacewar-Messages.h @@ -3,13 +3,10 @@ // | Copyright (C) 2023, Barra Ó Catháin | // | See end of file for copyright notice. | // ========================================= -#ifndef SPACEWAR_MESSAGES -#define SPACEWAR_MESSAGES - +#ifndef SPACEWAR_MESSAGES_H +#define SPACEWAR_MESSAGES_H #include -const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG", "SECRET"}; - typedef struct SpacewarMessage { uint8_t type; diff --git a/source/Spacewar-Physics.h b/source/Spacewar-Physics.h index 8745bec..f8d946b 100644 --- a/source/Spacewar-Physics.h +++ b/source/Spacewar-Physics.h @@ -20,6 +20,8 @@ typedef struct SpacewarShipState typedef struct SpacewarClientInput { + uint8_t playerNumber; + uint32_t secret; double turningAmount, acceleratingAmount; bool turningClockwise, turningAnticlockwise, accelerating; } SpacewarClientInput; @@ -35,9 +37,6 @@ typedef struct SpacewarState // Does a single step of the physics: void doPhysicsTick(SpacewarState * state); -// Adds a new player to a physics simulation: -void addNewPlayer(SpacewarConnection * connection, SpacewarState * state); - #endif // ======================================================== // | End of Spacewar-Physics.h, copyright notice follows. | diff --git a/source/Spacewar-Server.c b/source/Spacewar-Server.c index d3c629f..7855de6 100644 --- a/source/Spacewar-Server.c +++ b/source/Spacewar-Server.c @@ -14,8 +14,20 @@ #include #include #include -#include "Spacewar-Physics.h" #include "Spacewar-Messages.h" +#include "Spacewar-Physics.h" + +SpacewarConnection * getConnectionBySocket(SpacewarConnection * connections, size_t connectionCount, int socket) +{ + for (size_t connectionIndex = 0; connectionIndex < connectionCount; connectionIndex++) + { + if (connections[connectionIndex].clientSocket == socket) + { + return &connections[connectionIndex]; + } + } + return NULL; +} void * runServerPhysics(void * parameters) { @@ -23,42 +35,80 @@ void * runServerPhysics(void * parameters) while (true) { -// doPhysicsTick(state); + //doPhysicsTick(state); + //sendCurrentState(); usleep(15625); } + + return NULL; +} + +void * runUDPSocket(void * parameters) +{ + SpacewarServerSharedState * sharedState = (SpacewarServerSharedState *)parameters; + int udpSocket, bytesRead; + socklen_t socketAddressLength; + struct sockaddr_in clientAddress, serverAddress; + if ((udpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + exit(EXIT_FAILURE); + } + + memset(&serverAddress, 0, sizeof(serverAddress)); + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(5200); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + SpacewarClientInput input; + bind(udpSocket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in)); + + while (true) + { + bytesRead = recvfrom(udpSocket, &input, sizeof(SpacewarClientInput), 0, + (struct sockaddr *)&clientAddress, &socketAddressLength); + if (bytesRead == sizeof(SpacewarClientInput)) + { + if (input.playerNumber < 32) + { + if (input.secret == sharedState->connections[input.playerNumber].playerSecret) + { + memcpy(&sharedState->connections[input.playerNumber].clientAddress, + &clientAddress, sizeof(struct sockaddr_in)); + memcpy(&sharedState->state->playerInputs[input.playerNumber], &input, + sizeof(struct SpacewarClientInput)); + } + } + } + bzero(&input, sizeof(struct SpacewarClientInput)); + } + + return NULL; +} + +// Adds a new player to a physics simulation. Returns a randomly generated secret key: +uint32_t addPlayer(SpacewarConnection * connection, int playerNumber, SpacewarState * state) +{ + connection->playerSecret = rand(); + state->playerStates[playerNumber].inPlay = false; + + return connection->playerSecret; } // Creates a Spacewar server, intended to be ran by the standalone server or forked by the game client: void * runSpacewarServer(void * configuration) { SpacewarServerConfiguration * serverConfig = (SpacewarServerConfiguration *)configuration; - printf("Starting Server. \n"); - - // Initialize a simulation: - SpacewarState * currentState = calloc(1, sizeof(SpacewarState)); - + printf("Starting Server.\n"); + // Create our network listeners: int masterSocket = socket(AF_INET, SOCK_STREAM, 0); - int masterListeningSocket = socket(AF_INET, SOCK_DGRAM, 0); - int masterSendingSocket = socket(AF_INET, SOCK_DGRAM, 0); - - if (masterListeningSocket < 0 || masterSendingSocket < 0 || masterSocket < 0) + if (masterSocket < 0) { fprintf(stderr, "Failed to create socket.\n"); exit(EXIT_FAILURE); } - - // Make the socket timeout: - struct timeval readTimeout; - readTimeout.tv_sec = 0; - readTimeout.tv_usec = 800; - setsockopt(masterListeningSocket, SOL_SOCKET, SO_RCVTIMEO, &readTimeout, sizeof(readTimeout)); - - // Create a structure to store the address we're sending to: - struct sockaddr_in sendingAddress; - sendingAddress.sin_family = AF_INET; // IPv4 - sendingAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); - sendingAddress.sin_port = htons(serverConfig->port); + setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); + setsockopt(masterSocket, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)); // Create a structure to bind the listening socket: struct sockaddr_in listeningAddress; @@ -73,16 +123,13 @@ void * runSpacewarServer(void * configuration) fprintf(stderr, "Failed to bind socket.\n"); exit(EXIT_FAILURE); } - if (bind(masterListeningSocket, (const struct sockaddr *)&listeningAddress, sizeof(listeningAddress)) < 0) - { - fprintf(stderr, "Failed to bind socket.\n"); - exit(EXIT_FAILURE); - } // Begin listening on the master socket: listen(masterSocket, 32); // Create an epoll descriptor to keep track of clients: + int recievedEventCount = 0; + struct epoll_event receivedEvents[32]; int epollDescriptor = epoll_create(1); // Add the master socket to the epoll set: @@ -91,15 +138,21 @@ void * runSpacewarServer(void * configuration) requestedEvents.data.fd = masterSocket; epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, masterSocket, &requestedEvents); - int recievedEventCount = 0; - struct epoll_event receivedEvents[32]; - // Create a set of connection structs to store the current connection information: - SpacewarConnection connectedClients[32]; + SpacewarConnection * connectedClients = calloc(32, sizeof(SpacewarConnection)); + for(int index = 0; index < 32; index++) + { + connectedClients[index].active = false; + } // Begin the simulation: - pthread_t physicsThread; - pthread_create(&physicsThread, NULL, runServerPhysics, currentState); + pthread_t physicsThread, udpThread; + SpacewarState * currentState = calloc(1, sizeof(SpacewarState)); + SpacewarServerSharedState threadState; + threadState.state = currentState; + threadState.connections = connectedClients; + pthread_create(&physicsThread, NULL, runServerPhysics, &threadState); + pthread_create(&udpThread, NULL, runUDPSocket, &threadState); // Manage clients and sending packets back and forth: while (true) @@ -110,10 +163,8 @@ void * runSpacewarServer(void * configuration) // If there's activity on the master socket, there's a new connection: if (receivedEvents[eventIndex].data.fd == masterSocket) { - struct sockaddr_in clientAddress; - socklen_t clientSocketLength = sizeof(struct sockaddr_in); - int newClientSocket = accept(masterSocket, (struct sockaddr *)&clientAddress, - &clientSocketLength); + struct sockaddr_in clientAddress; + int newClientSocket = accept(masterSocket, NULL, NULL); // Check that the socket is functional: if (newClientSocket < 0) @@ -135,8 +186,6 @@ void * runSpacewarServer(void * configuration) connectedClients[index].active = true; connectedClients[index].missedPongs = false; connectedClients[index].clientSocket = newClientSocket; - memcpy(&connectedClients[index].clientAddress, &clientAddress, - sizeof(struct sockaddr_in)); // Send the HELLO packet to the player: SpacewarMessage helloMessage; @@ -145,9 +194,12 @@ void * runSpacewarServer(void * configuration) send(newClientSocket, &helloMessage, sizeof(SpacewarMessage), 0); // Add the player to the simulation: - //addPlayer(&connectedClients[index], index, currentState); + uint32_t secret = addPlayer(&connectedClients[index], index, currentState); // Send the SECRET packet to the player: + helloMessage.type = 4; + helloMessage.content = secret; + send(newClientSocket, &helloMessage, sizeof(SpacewarMessage), 0); break; } @@ -156,8 +208,11 @@ void * runSpacewarServer(void * configuration) // Otherwise, we've been sent a packet from one of the connected clients: else { + SpacewarConnection * client = getConnectionBySocket(connectedClients, 32, + receivedEvents->data.fd); + SpacewarMessage receivedMessage; - size_t bytesRead = recv(receivedEvents->data.fd, &receivedMessage, + size_t bytesRead = recv(client->clientSocket, &receivedMessage, sizeof(SpacewarMessage), 0); if (bytesRead == 0) @@ -166,19 +221,19 @@ void * runSpacewarServer(void * configuration) SpacewarMessage goodbyeMessage; goodbyeMessage.type = 1; goodbyeMessage.content = 0; - send(receivedEvents->data.fd, &goodbyeMessage, sizeof(SpacewarMessage), 0); + send(client->clientSocket, &goodbyeMessage, sizeof(SpacewarMessage), 0); // Remove the socket from the epoll interest set: - epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, receivedEvents->data.fd, NULL); + epoll_ctl(epollDescriptor, EPOLL_CTL_DEL, client->clientSocket, NULL); // Remove the player from the simulation: - // removePlayer(&connectedClients[index], currentState); - - // Clear the player struct: - // clearPlayer(findPlayerBySocket(connectedClients, 32, receivedEvents->data.fd)); + //removePlayer(&connectedClients[index], currentState); // Shutdown the socket: - shutdown(receivedEvents->data.fd, SHUT_RDWR); + shutdown(client->clientSocket, SHUT_RDWR); + + // Deactivate the connection: + client->active = false; } else diff --git a/source/Spacewar-Server.h b/source/Spacewar-Server.h index 4974d8d..b7a6311 100644 --- a/source/Spacewar-Server.h +++ b/source/Spacewar-Server.h @@ -10,6 +10,10 @@ #include #include +#include "Spacewar-Physics.h" + +typedef struct SpacewarState SpacewarState; + typedef struct SpacewarConnection { bool active; @@ -19,11 +23,19 @@ typedef struct SpacewarConnection struct sockaddr_in clientAddress; } SpacewarConnection; + typedef struct SpacewarServerConfiguration { uint16_t port; } SpacewarServerConfiguration; + +typedef struct SpacewarServerSharedState +{ + SpacewarState * state; + SpacewarConnection * connections; +} SpacewarServerSharedState; + // Creates a spacewar server, intended to be ran by the standalone server or forked by the game client: void * runSpacewarServer(void * configuration); @@ -43,4 +55,4 @@ void * runSpacewarServer(void * configuration); // GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . +// along with this program. If not, see .