Basic implementation of player lists and tying connections to players

This commit is contained in:
Barra Ó Catháin 2023-09-12 22:32:19 +01:00
parent 5a53e9f197
commit 54b613befe
6 changed files with 227 additions and 36 deletions

View File

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

View File

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

View File

@ -3,9 +3,29 @@
// | Copyright (C) 2023, Barra Ó Catháin |
// | See end of file for copyright notice. |
// =========================================
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#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. |
// ===================================================

View File

@ -5,20 +5,61 @@
// =========================================
#ifndef PLAYER_DATA_H
#define PLAYER_DATA_H
#include <stdbool.h>
#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. |

View File

@ -5,23 +5,7 @@
// ===========================================
#include <libguile.h>
#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. |

View File

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