diff --git a/source/server/connections.c b/source/server/connections.c index 33bc100..a49759f 100644 --- a/source/server/connections.c +++ b/source/server/connections.c @@ -8,7 +8,7 @@ #include "connections.h" -struct ClientConnectionNode * findMiddle(struct ClientConnectionNode * start, struct ClientConnectionNode * end) +static struct ClientConnectionNode * findMiddle(struct ClientConnectionNode * start, struct ClientConnectionNode * end) { while (start != end) { diff --git a/source/server/main.c b/source/server/main.c index c2549aa..81f1871 100644 --- a/source/server/main.c +++ b/source/server/main.c @@ -101,6 +101,9 @@ int main (int argc, char ** argv) // Create a client connection list to allow us to associate TLS sessions and sockets and players: struct ClientConnectionList clientConnections; + + // Create some structures needed to store global state: + struct PlayerList * globalPlayerList = createPlayerList(); // Start a REPL thread: //pthread_t schemeREPLThread; @@ -120,7 +123,7 @@ int main (int argc, char ** argv) } for (int index = 0; index < eventsCount; index++) - { + { // If it's the master socket, it's a new client connecting: if (events[index].data.fd == masterSocket) { @@ -134,7 +137,7 @@ int main (int argc, char ** argv) // Accept the connection: int newSocket = accept(masterSocket, NULL, NULL); gnutls_transport_set_int(*tlsSession, newSocket); - + // Perform a TLS handshake: int handshakeReturnValue = 0; do @@ -142,7 +145,6 @@ int main (int argc, char ** argv) handshakeReturnValue = gnutls_handshake(*tlsSession); } while (handshakeReturnValue < 0 && gnutls_error_is_fatal(handshakeReturnValue) == 0); - // If the handshake was unsuccessful, close the connection: if (handshakeReturnValue < 0) { @@ -162,7 +164,9 @@ int main (int argc, char ** argv) // Add the connection to the list: struct ClientConnection * newConnection = addNewConnection(&clientConnections, newSocket, tlsSession); newConnection->player = createNewPlayer(newConnection); - sprintf(newConnection->player->name, "Player %02d", clientConnections.clientCount); + sprintf(newConnection->player->name, "Player %02d", globalPlayerList->count + 1); + addToPlayerList(newConnection->player, globalPlayerList); + // Print a message: printf("New connection established. %d client(s), session ID %u.\n", @@ -175,18 +179,17 @@ int main (int argc, char ** argv) if (connection != NULL) { // Read the data from the TLS session: - struct ClientToServerMessage message; - int returnValue = gnutls_record_recv(*connection->tlsSession, &message, sizeof(struct ClientToServerMessage)); + struct ClientToServerMessage message; + int returnValue = gnutls_record_recv(*connection->tlsSession, &message, sizeof(struct ClientToServerMessage)); if (returnValue == 0 || returnValue == -10) { - printf("Closing session ID: %u.\n", *connection->tlsSession); epoll_ctl(connectedClients, EPOLL_CTL_DEL, connection->fileDescriptor, &watchedEvents); - gnutls_bye(*connection->tlsSession, 2); shutdown(connection->fileDescriptor, 2); - close(connection->fileDescriptor); - deallocatePlayer(&connection->player); removeConnectionByFileDescriptor(&clientConnections, connection->fileDescriptor); + close(connection->fileDescriptor); + //deallocatePlayer(&connection->player); + continue; } else if (returnValue == sizeof(struct ClientToServerMessage)) { @@ -231,6 +234,9 @@ int main (int argc, char ** argv) // Wait for all other threads to terminate: //pthread_join(schemeREPLThread, NULL); + + // Deallocate the global state structures: + deallocatePlayerList(&globalPlayerList); // Return a successful status code to the operating system: return 0; diff --git a/source/server/player-data.c b/source/server/player-data.c index a304b87..14a6aed 100644 --- a/source/server/player-data.c +++ b/source/server/player-data.c @@ -3,9 +3,29 @@ // | Copyright (C) 2023, Barra Ó Catháin | // | See end of file for copyright notice. | // ========================================= +#include #include +#include #include "player-data.h" +// Internal Functions: +// =================== +static struct PlayerListNode * findMiddle(struct PlayerListNode * start, struct PlayerListNode * end) +{ + while (start != end) + { + start = start->next; + if(start == end) + { + return start; + } + end = end->previous; + } + + return start; +} +// ==================== + // Allocates and sets up a new player according to the world's starter character sheet: struct Player * createNewPlayer(struct ClientConnection * connection) { @@ -22,6 +42,152 @@ void deallocatePlayer(struct Player ** player) *player = NULL; } +struct PlayerList * createPlayerList() +{ + struct PlayerList * newPlayerList = calloc(1, sizeof(struct PlayerList)); + newPlayerList->count = 0; + newPlayerList->head = NULL; + newPlayerList->tail = NULL; + + return newPlayerList; +} + +void deallocatePlayerList(struct PlayerList ** playerList) +{ + struct PlayerListNode * node = (*playerList)->head, * nextNode; + + // Deallocate all nodes in the list: + while (node != NULL) + { + nextNode = node->next; + free(node); + node = nextNode; + } + + // Deallocate the list itself: + free(*playerList); + + // Set the pointer to null: + playerList = NULL; +} + +int addToPlayerList(struct Player * player, struct PlayerList * playerList) +{ + // Check that the player isn't already in the list: + if (isInPlayerList(player, playerList)) + { + return playerList->count; + } + else + { + // Create a node to add to the list: + struct PlayerListNode * newNode = calloc(1, sizeof(struct PlayerListNode)); + newNode->player = player; + newNode->next = NULL; + newNode->previous = NULL; + + // Find the position that the new node is to go into: + + // If the list is empty: + if (playerList->count == 0) + { + playerList->head = newNode; + playerList->tail = newNode; + playerList->count = 1; + return playerList->count; + } + + struct PlayerListNode * currentNode = playerList->head; + while (strncmp(player->name, currentNode->player->name, 64) < 0) + { + // If we reach the end of the list: + if (currentNode->next == NULL) + { + currentNode->next = newNode; + newNode->previous = currentNode; + playerList->tail = newNode; + playerList->count++; + + return playerList->count; + } + + else + { + currentNode = currentNode->next; + } + } + + // Set the appropriate pointers in the new node: + newNode->previous = currentNode->previous; + currentNode->previous = newNode; + newNode->next = currentNode; + + // Set the proper pointers if we're at the ends of the list: + if (newNode->previous == NULL) + { + playerList->head = newNode; + } + if (newNode->next == NULL) + { + playerList->tail = newNode; + } + + playerList->count++; + + return playerList->count; + } +} + +// Returns the Player with the given name from a PlayerList, or NULL otherwise: +struct Player * getFromPlayerList(char * playerName, struct PlayerList * playerList) +{ + struct PlayerListNode * start = playerList->head, * end = playerList->tail, * middle = findMiddle(start, end); + int returnValue = 0; + + while (start != end) + { + returnValue = strncmp(middle->player->name, playerName, 64); + + if (returnValue < 0) + { + start = middle->next; + middle = findMiddle(start, end); + } + else if (returnValue > 0) + { + end = middle->next; + middle = findMiddle(start, end); + } + else if (returnValue == 0) + { + return middle->player; + } + } + if (strncmp(start->player->name, playerName, 64) == 0) + { + return start->player; + } + else + { + return NULL; + } +} + +// Returns true if the given Player is in the given PlayerList: +bool isInPlayerList(struct Player * player, struct PlayerList * playerList) +{ + struct PlayerListNode * currentNode = playerList->head; + while (currentNode != NULL) + { + if (currentNode->player == player) + { + return true; + } + currentNode = currentNode->next; + } + return false; +} + // =================================================== // | End of player-data.c, copyright notice follows. | // =================================================== diff --git a/source/server/player-data.h b/source/server/player-data.h index 46998d2..d908e5e 100644 --- a/source/server/player-data.h +++ b/source/server/player-data.h @@ -5,20 +5,61 @@ // ========================================= #ifndef PLAYER_DATA_H #define PLAYER_DATA_H +#include #include "connections.h" +// ================================================================= +// Players - A structure for representing a single player character: +// ================================================================= struct Player { struct ClientConnection * connection; char name[64]; }; +// Functions: +// ========== + // Allocates and sets up a new player according to the world's starter character sheet: struct Player * createNewPlayer(struct ClientConnection * connection); // Deallocates a player: void deallocatePlayer(struct Player ** player); +// ======================================================================================== +// Player Lists - A structure for managing a collection of players in a doubly linked list: +// ======================================================================================== +struct PlayerListNode +{ + struct Player * player; + struct PlayerListNode * next, * previous; +}; + +struct PlayerList +{ + size_t count; + struct PlayerListNode * head, * tail; +}; + +// Functions: +// ========== + +struct PlayerList * createPlayerList(); +void deallocatePlayerList(struct PlayerList ** playerList); + +// Adds a Player into a PlayerList, in a sorted position by character name. +// Returns the count of players in the list: +int addToPlayerList(struct Player * player, struct PlayerList * playerList); + +// Remove a Player from a PlayerList. Returns the count of players in the list: +int removeFromPlayerList(struct Player * player, struct PlayerList * playerList); + +// Returns the Player with the given name from a PlayerList, or NULL otherwise: +struct Player * getFromPlayerList(char * playerName, struct PlayerList * playerList); + +// Returns true if the given Player is in the given PlayerList: +bool isInPlayerList(struct Player * player, struct PlayerList * playerList); + #endif // =================================================== // | End of player-data.h, copyright notice follows. | diff --git a/source/server/scheme-integration.c b/source/server/scheme-integration.c index b1b98f2..56bd86d 100644 --- a/source/server/scheme-integration.c +++ b/source/server/scheme-integration.c @@ -5,23 +5,7 @@ // =========================================== #include -#include "scheme-integration.h" - -// The function ran by the Scheme thread which runs a text-based REPL: -void * schemeREPLHandler (void * threadParameters) -{ - // Initialize Scheme: - scm_init_guile(); - - // Enable Readline support: - scm_c_eval_string("(begin (use-modules (ice-9 readline)) (activate-readline))"); - - // Start a Scheme REPL: - scm_shell(0, NULL); - - // Return NULL to the calling thread: - return NULL; -} +SCM scheme_get_player_by_name(SCM name); // ========================================================== // | End of scheme-integration.c, copyright notice follows. | diff --git a/source/server/scheme-integration.h b/source/server/scheme-integration.h index 860427b..9992bfb 100644 --- a/source/server/scheme-integration.h +++ b/source/server/scheme-integration.h @@ -6,14 +6,8 @@ #ifndef SCHEME_INTEGRATION_H #define SCHEME_INTEGRATION_H -struct SchemeThreadArguments -{ - -}; - -// The function ran by the Scheme thread which initializes the REPL: -void * schemeREPLHandler (void * threadParameters); - +SCM scheme_get_player_by_name(SCM name); + #endif // ========================================================== // | End of scheme-integration.h, copyright notice follows. |