Added initial GnuTLS encryption.

- Added inputoutput.c
- Added inputoutput.h
- inputoutput contains wrapper and helper functions for transmitting messages over GnuTLS.
- Moved the userMessage struct definition to inputoutput.
- Reworked client and server to use GnuTLS.
- Removed all commands from server in preperation for upcoming command and message queues.
- Names and areas are no longer considered for messaging.
- Changed Makefile to link GnuTLS.
This commit is contained in:
Barry 2022-03-06 00:36:42 +00:00
parent 235ff8e74f
commit 5d772df469
7 changed files with 234 additions and 200 deletions

View File

@ -5,8 +5,8 @@ clientobj = $(clientsrc:.c=.o)
serversrc = $(wildcard src/misc/*.c) \
src/SilverMUDServer.c
serverobj = $(serversrc:.c=.o)
CLIENTLDFLAGS= -lpthread -lncurses
SERVERLDFLAGS= -lncurses
CLIENTLDFLAGS= -lpthread -lncurses -lgnutls
SERVERLDFLAGS= -lncurses -lgnutls
SilverMUDClient: $(clientobj)
gcc -s -O3 -o $@ $^ $(CLIENTLDFLAGS)

View File

@ -9,17 +9,19 @@
#include <ncurses.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <gnutls/gnutls.h>
#include "misc/playerdata.h"
#include "misc/texteffects.h"
#include "misc/inputoutput.h"
#include "misc/inputhandling.h"
#define MAX 2048
#define PORT 5000
#define SA struct sockaddr
static int MAX = 2048;
// A struct for passing arguments to our threads containing a file descriptor and a window pointer:
typedef struct threadparameters
{
int socketDescriptor;
gnutls_session_t tlssession;
FILE * loggingstream;
bool loggingflag;
WINDOW * window;
@ -32,28 +34,28 @@ void * messageSender(void * parameters)
{
// Takes user input in a window, sanatizes it, and sends it to the server:
struct threadparameters *threadParameters = parameters;
char sendBuffer[MAX];
userMessage sendBuffer;
while (!shouldExit)
{
bzero(sendBuffer, MAX);
wprintw(threadParameters->window, "\n\n\nCOMM-LINK> ");
if(wgetnstr(threadParameters->window, sendBuffer, MAX) == ERR)
if(wgetnstr(threadParameters->window, sendBuffer.messageContent, MAX) == ERR)
{
// Quit if there's any funny business with getting input:
pthread_exit(NULL);
}
if(sendBuffer[0] == '\n')
if(sendBuffer.messageContent[0] == '\n')
{
continue;
}
if(threadParameters->loggingflag == true)
{
fputs(sendBuffer, threadParameters->loggingstream);
fputs(sendBuffer.messageContent, threadParameters->loggingstream);
fputs("\n", threadParameters->loggingstream);
fflush(threadParameters->loggingstream);
}
write(threadParameters->socketDescriptor, sendBuffer, MAX);
wprintw(threadParameters->window, sendBuffer.messageContent);
messageSend(threadParameters->tlssession, &sendBuffer);
}
pthread_exit(NULL);
}
@ -66,15 +68,14 @@ void * messageReceiver(void * parameters)
userMessage receiveBuffer;
while (!shouldExit)
{
read(threadParameters->socketDescriptor, &receiveBuffer.senderName, sizeof(receiveBuffer.senderName));
read(threadParameters->socketDescriptor, &receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent));
messageReceive(threadParameters->tlssession, &receiveBuffer);
if(receiveBuffer.senderName[0] == '\0')
{
if(receiveBuffer.messageContent[0] == '\0')
{
shouldExit = true;
pthread_exit(NULL);
}
//if(receiveBuffer.messageContent[0] == '\0')
//{
// shouldExit = true;
// pthread_exit(NULL);
//}
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window);
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window);
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window);
@ -92,9 +93,6 @@ void * messageReceiver(void * parameters)
slowPrintNcurses(": ", 8000, threadParameters->window);
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window);
}
bzero(receiveBuffer.senderName, sizeof(receiveBuffer.senderName));
bzero(receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent));
}
pthread_exit(NULL);
}
@ -192,7 +190,30 @@ int main(int argc, char **argv)
}
usleep(100000);
// Setup Ncurses:
/* TODO: Negotiate TLS
Need to pull in GNU TLS, and do the same on the server-side. */
// Setup a GnuTLS session and initialize it:
gnutls_session_t tlssession = NULL;
if(gnutls_init(&tlssession, GNUTLS_CLIENT) < 0)
{
// Failure Case
exit(EXIT_FAILURE);
}
gnutls_anon_client_credentials_t clientkey = NULL;
gnutls_anon_allocate_client_credentials(&clientkey);
gnutls_credentials_set(tlssession, GNUTLS_CRD_ANON, &clientkey);
/* Bind the open socket to the TLS session. */
gnutls_transport_set_int(tlssession, sockfd);
gnutls_priority_set_direct(tlssession, "PERFORMANCE:+ANON-ECDH:+ANON-DH", NULL);
/* Set default timeout for the handshake. */
gnutls_handshake_set_timeout(tlssession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
int r = -1;
do {
r = gnutls_handshake(tlssession);
} while (r < 0 && gnutls_error_is_fatal(r) == 0);
// Setup Ncurses:
initscr();
// Create two pointers to structs to pass arguments to the threads:
@ -204,14 +225,14 @@ int main(int argc, char **argv)
// Make the windows for the structs, and pass the socket descriptor:
logArea->window = newwin(LINES - 5, COLS - 2, 1, 1);
logArea->socketDescriptor = sockfd;
logArea->tlssession = tlssession;
logArea->loggingflag = chatlogging;
if(chatlog != NULL)
{
logArea->loggingstream = chatlog;
}
messageArea->window = newwin(3, COLS, LINES - 3, 0);
messageArea->socketDescriptor = sockfd;
messageArea->tlssession = tlssession;
messageArea->loggingflag = gamelogging;
if(gamelog != NULL)
{
@ -244,7 +265,7 @@ int main(int argc, char **argv)
{
fclose(gamelog);
}
if(chatlog != NULL)
if(chatlog != NULL)
{
fclose(chatlog);
}

View File

@ -12,23 +12,27 @@
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <gnutls/gnutls.h>
#include "misc/lists.h"
#include "misc/playerdata.h"
#include "misc/texteffects.h"
#include "misc/inputoutput.h"
#include "misc/inputhandling.h"
const int PORT = 5000;
const int PLAYERCOUNT = 64;
typedef struct sockaddr sockaddr;
int main()
{
bool keepRunning = true;
int socketFileDesc, connectionFileDesc, length, clientsAmount,
socketCheck, activityCheck, readLength;
int clientSockets[64];
int maxClients = 64;
userMessage messageBuffer;
char receiveBuffer[2048];
socketCheck, activityCheck, readLength, returnVal;
fd_set connectedClients;
playerInfo connectedPlayers[64];
int clientSockets[PLAYERCOUNT];
userMessage sendBuffer, receiveBuffer;
playerInfo connectedPlayers[PLAYERCOUNT];
char testString[32] = "Hehe.";
struct sockaddr_in serverAddress, clientAddress;
// Initialize areas:
@ -39,7 +43,7 @@ int main()
createPath(getAreaFromList(areas, 2), getAreaFromList(areas, 1), "Back to South Spawn", "Path to Enlightenment.");
// Initialize playerdata:
for (int index = 0; index < maxClients; index++)
for (int index = 0; index < PLAYERCOUNT; index++)
{
strcpy(connectedPlayers[index].playerName, "UNNAMED");
connectedPlayers[index].currentArea = getAreaFromList(areas, 0);
@ -50,7 +54,7 @@ int main()
slowPrint("\n--==== \033[33;40mSILVERKIN INDUSTRIES\033[0m COMM-LINK SERVER ====--\nVersion Alpha 0.3\n", 5000);
// Initialize the sockets to 0, so we don't crash.
for (int index = 0; index < maxClients; index++)
for (int index = 0; index < PLAYERCOUNT; index++)
{
clientSockets[index] = 0;
}
@ -59,13 +63,13 @@ int main()
socketFileDesc = socket(AF_INET, SOCK_STREAM, 0);
if (socketFileDesc == -1)
{
perror("Socket creation is \033[33;40mRED.\033[0m Aborting launch.\n");
perror("\tSocket Creation is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
exit(0);
}
else
{
slowPrint(" Socket creation is \033[32;40mGREEN.\033[0m\n", 5000);
slowPrint("\tSocket Creation is:\t\033[32;40mGREEN.\033[0m\n", 5000);
}
bzero(&serverAddress, sizeof(serverAddress));
@ -78,37 +82,59 @@ int main()
// Binding newly created socket to given IP, and checking it works:
if ((bind(socketFileDesc, (sockaddr*)&serverAddress, sizeof(serverAddress))) != 0)
{
perror("Socket binding is \033[33;40mRED.\033[0m Aborting launch.\n");
perror("\tSocket Binding is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
exit(0);
}
else
{
slowPrint(" Socket binding is \033[32;40mGREEN.\033[0m\n", 5000);
slowPrint("\tSocket Binding is:\t\033[32;40mGREEN.\033[0m\n", 5000);
}
// Let's start listening:
if ((listen(socketFileDesc, 64)) != 0)
if ((listen(socketFileDesc, PLAYERCOUNT)) != 0)
{
perror("Server listening is \033[33;40mRED.\033[0m Aborting launch.\n");
exit(0);
perror("\tServer Listening is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
exit(EXIT_FAILURE);
}
else
{
slowPrint(" Server listening is \033[32;40mGREEN.\033[0m\n", 5000);
slowPrint("\tServer Listening is:\t\033[32;40mGREEN.\033[0m\n", 5000);
}
length = sizeof(clientAddress);
// Accept the data packet from client and verify it:
while (1)
gnutls_session_t tlssessions[PLAYERCOUNT];
gnutls_anon_server_credentials_t serverkey = NULL;
gnutls_anon_allocate_server_credentials(&serverkey);
gnutls_anon_set_server_known_dh_params(serverkey, GNUTLS_SEC_PARAM_MEDIUM);
// Initialize all the TLS Sessions to NULL: We use this to check if it's an "empty connection."
for (int index = 0; index < PLAYERCOUNT; index++)
{
tlssessions[index] = NULL;
if (gnutls_init(&tlssessions[index], GNUTLS_SERVER) < 0)
{
perror("\tTLS Sessions Initialization is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
exit(EXIT_FAILURE);
}
gnutls_priority_set_direct(tlssessions[index], "NORMAL:+ANON-ECDH:+ANON-DH", NULL);
gnutls_credentials_set(tlssessions[index], GNUTLS_CRD_ANON, &serverkey);
gnutls_handshake_set_timeout(tlssessions[index], GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
slowPrint("\tTLS Sessions Initialization is:\t\033[32;40mGREEN.\033[0m\n", 5000);
while(keepRunning)
{
// Clear the set of file descriptors and add the master socket:
FD_ZERO(&connectedClients);
FD_SET(socketFileDesc, &connectedClients);
clientsAmount = socketFileDesc;
bzero(receiveBuffer, sizeof(receiveBuffer));
for (int i = 0; i < maxClients; i++)
// Find all sockets that are still working and place them in the set:
for(int index = 0; index < PLAYERCOUNT; index++)
{
// Just get the one we're working with to another name:
socketCheck = clientSockets[i];
socketCheck = clientSockets[index];
// If it's working, bang it into the list:
if(socketCheck > 0)
@ -134,165 +160,81 @@ int main()
// If it's the master socket selected, there is a new connection:
if (FD_ISSET(socketFileDesc, &connectedClients))
{
if ((connectionFileDesc = accept(socketFileDesc, (struct sockaddr *)&clientAddress, (socklen_t*)&length))<0)
if ((connectionFileDesc = accept(socketFileDesc, (struct sockaddr *)&clientAddress, (socklen_t*)&length)) < 0)
{
perror("Failed to accept connection. Aborting.\n");
exit(EXIT_FAILURE);
}
// Print new connection details:
printf("Client connected: Socket file descriptor: #%d, IP address: %s, Port: %d.\n",
connectionFileDesc, inet_ntoa(clientAddress.sin_addr) , ntohs
(clientAddress.sin_port));
// See if we can put in the client:
for (int i = 0; i < maxClients; i++)
for (int index = 0; index < PLAYERCOUNT; index++)
{
// When there is an empty slot, pop it in:
if( clientSockets[i] == 0 )
if (clientSockets[index] == 0)
{
clientSockets[i] = connectionFileDesc;
printf("Adding to list of sockets as %d.\n" , i);
clientSockets[index] = connectionFileDesc;
printf("Adding to list of sockets as %d.\n", index);
gnutls_transport_set_int(tlssessions[index], clientSockets[index]);
do
{
returnVal = gnutls_handshake(tlssessions[index]);
}
while (returnVal < 0 && gnutls_error_is_fatal(returnVal) == 0);
strcpy(sendBuffer.senderName, "");
strcpy(sendBuffer.messageContent, "Welcome to the server!");
messageSend(tlssessions[index], &sendBuffer);
break;
}
}
}
// Otherwise, it's a client we need to interact with:
else
{
// Otherwise, it's a client socket to be interacted with:
for (int i = 0; i < maxClients; i++)
for (int index = 0; index < PLAYERCOUNT; index++)
{
socketCheck = clientSockets[i];
socketCheck = clientSockets[index];
if (FD_ISSET(socketCheck, &connectedClients))
if(FD_ISSET(socketCheck, &connectedClients))
{
//Check if it was for closing, and also read the incoming message
explicit_bzero(receiveBuffer, sizeof(receiveBuffer));
readLength = read(socketCheck, receiveBuffer, sizeof(receiveBuffer));
userInputSanatize(receiveBuffer, 2048);
if (readLength == 0)
messageReceive(tlssessions[index], &receiveBuffer);
sprintf(testString, "User %d", index);
strcpy(sendBuffer.senderName, testString);
userInputSanatize(receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent));
strcpy(sendBuffer.messageContent, receiveBuffer.messageContent);
for (int sendIndex = 0; sendIndex < clientsAmount; sendIndex++)
{
// Somebody disconnected , get his details and print:
getpeername(socketCheck, (struct sockaddr*)&clientAddress, (socklen_t*)&length);
printf("Client disconnected: IP Address: %s, Port: %d.\n",
inet_ntoa(clientAddress.sin_addr) , ntohs(clientAddress.sin_port));
// Close the socket and mark as 0 in list for reuse:
close(socketCheck);
clientSockets[i] = 0;
}
// Name change command: Move logic to a command interpreter later:
else if (receiveBuffer[0] == '/')
{
if(strncmp(receiveBuffer, "/NAME", 5) == 0)
{
char newName[32];
strncpy(newName, &receiveBuffer[6], 32);
// Remove newlines:
for (int index = 0; index < 32; index++)
{
if (newName[index] == '\n')
{
newName[index] = '\0';
}
}
for (int index = 0; index < maxClients; index++)
{
if(strncmp(newName, connectedPlayers[index].playerName, 32) == 0)
{
break;
}
}
if(newName[0] != '\0')
{
strncpy(connectedPlayers[i].playerName, newName, 32);
}
}
else if(strncmp(receiveBuffer, "/EXIT", 5) == 0)
{
strcpy(messageBuffer.senderName, "\0");
strcpy(messageBuffer.messageContent, "\0");
write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName));
write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
printf("Client disconnected: IP Address: %s, Port: %d.\n",
inet_ntoa(clientAddress.sin_addr) , ntohs(clientAddress.sin_port));
close(socketCheck);
clientSockets[i] = 0;
}
else if(strncmp(receiveBuffer, "/LOOK", 5) == 0)
{
strcat(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaDescription);
strcat(messageBuffer.messageContent, "\nYou see:");
for(int index = 0; index < 16; index++)
{
if(connectedPlayers[i].currentArea->areaExits[index] != NULL)
{
strcat(messageBuffer.messageContent, "\n - ");
strcat(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaExits[index]->pathName);
}
}
write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName));
write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
bzero(messageBuffer.senderName, sizeof(messageBuffer.senderName));
bzero(messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
}
else if(strncmp(receiveBuffer, "/MOVE", 5) == 0)
{
char requestedPath[32];
strncpy(requestedPath, &receiveBuffer[6], 32);
userInputSanatize(requestedPath, 32);
// Remove newlines:
for (int index = 0; index < 32; index++)
{
if (requestedPath[index] == '\n')
{
requestedPath[index] = '\0';
}
}
requestedPath[31] = '\0';
if(movePlayerToArea(&connectedPlayers[i], requestedPath) == 0)
{
strcpy(messageBuffer.senderName, "\0");
strcpy(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaDescription);
write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName));
write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
}
else
{
strcpy(messageBuffer.senderName, "");
strcpy(messageBuffer.messageContent, "You can't go somewhere that doesn't exist!");
write(socketCheck, messageBuffer.senderName, sizeof(messageBuffer.senderName));
write(socketCheck, messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
bzero(messageBuffer.senderName, sizeof(messageBuffer.senderName));
bzero(messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
}
}
}
// Echo back the message that came in:
else if (receiveBuffer[0] == '\n')
{
continue;
}
else
{
printf("%d/%s/%s: %s", clientSockets[i], connectedPlayers[i].currentArea->areaName, connectedPlayers[i].playerName, receiveBuffer);
fflush(stdout);
strcpy(messageBuffer.senderName, connectedPlayers[i].playerName);
strcpy(messageBuffer.messageContent, receiveBuffer);
for (int sendIndex = 0; sendIndex < clientsAmount; sendIndex++)
{
if(clientSockets[sendIndex] != STDIN_FILENO && (connectedPlayers[i].currentArea == connectedPlayers[sendIndex].currentArea))
{
write(clientSockets[sendIndex], messageBuffer.senderName, sizeof(messageBuffer.senderName));
write(clientSockets[sendIndex], messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
}
}
bzero(messageBuffer.senderName, sizeof(messageBuffer.senderName));
bzero(messageBuffer.messageContent, sizeof(messageBuffer.messageContent));
messageSend(tlssessions[sendIndex], &sendBuffer);
}
}
}
}
}
/* // TODO: Implement the ability to connect clients, and pass messages to the relevant queues. */
/* // Check if there's a new client by checking the master socket: */
/* connectionFileDesc = accept(socketFileDesc,(struct sockaddr *)&clientAddress, (socklen_t*)&length); */
/* gnutls_transport_set_int(tlssessions[0], connectionFileDesc); */
/* int returnVal = -1; */
/* do */
/* { */
/* returnVal = gnutls_handshake(tlssessions[0]); */
/* } */
/* while (returnVal < 0 && gnutls_error_is_fatal(returnVal) == 0); */
/* if (returnVal < 0) */
/* { */
/* fprintf(stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror(returnVal)); */
/* } */
/* strcpy(sendBuffer.senderName, "Test"); */
/* strcpy(sendBuffer.messageContent, "GnuTLS, baybee!\n"); */
/* messageSend(tlssessions[0], &sendBuffer); */
/* while(true) */
/* { */
/* messageReceive(tlssessions[0], &receiveBuffer); */
/* userInputSanatize(receiveBuffer.messageContent, 2048); */
/* strcpy(sendBuffer.messageContent, receiveBuffer.messageContent); */
/* messageSend(tlssessions[0], &sendBuffer); */
/* } */
/* gnutls_bye(tlssessions[0], GNUTLS_SHUT_RDWR); */
return 0;
}

33
src/misc/inputoutput.c Normal file
View File

@ -0,0 +1,33 @@
// inputoutput.c: Implementation of input output library for SilverMUD.
// Barry Kane, 2022.
#include <stdio.h>
#include "inputoutput.h"
#include <gnutls/gnutls.h>
// Sends a message to a given TLS session, wraps the calls to gnutls_write:
void messageSend(gnutls_session_t receivingSession, userMessage * messageToSend)
{
int returnValue = 0;
do
{
returnValue = gnutls_record_send(receivingSession, messageToSend->senderName, sizeof(((userMessage*)0)->senderName));
} while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
do
{
returnValue = gnutls_record_send(receivingSession, messageToSend->messageContent, sizeof(((userMessage*)0)->messageContent));
} while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
}
// Recieves a message from a given TLS session, wraps the calls to gnutls_read:
void messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToMessage)
{
int returnValue = 0;
do
{
returnValue = gnutls_record_recv(receiveFromSession, receiveToMessage->senderName, sizeof(((userMessage*)0)->senderName));
} while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
do
{
returnValue = gnutls_record_recv(receiveFromSession, receiveToMessage->messageContent, sizeof(((userMessage*)0)->messageContent));
} while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
}

21
src/misc/inputoutput.h Normal file
View File

@ -0,0 +1,21 @@
// inputoutput.h: Header file contatning function prototypes and datastructures
// for dealing with input and output.
// Barry Kane, 2022.
#ifndef INPUTOUTPUt_H
#define INPUTOUTPUT_H
#include <gnutls/gnutls.h>
// A message datastructure containing a user/character name and the content:
typedef struct userMessage
{
char senderName[32];
char messageContent[2048];
} userMessage;
// Sends a message to a given TLS session, wraps the calls to gnutls_write:
void messageSend(gnutls_session_t receivingSession, userMessage * messageToSend);
// Recieves a message from a given TLS session, wraps the calls to gnutls_read:
void messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToMessage);
#endif

View File

@ -1,17 +1,10 @@
// playerdata.h: Header file containing data structures for player data and function
// definitions for interacting with said data.
// prototypes for interacting with said data.
// Barry Kane, 2021.
#ifndef PLAYERDATA_H
#define PLAYERDATA_H
#include <stdlib.h>
typedef struct userMessage
{
char senderName[32];
char messageContent[2048];
} userMessage;
typedef struct playerPath playerPath;
typedef struct playerArea playerArea;

24
src/tests/list-test.c Normal file
View File

@ -0,0 +1,24 @@
#include "../misc/lists.h"
#include "../misc/playerdata.h"
#include <stdio.h>
void main()
{
areaNode * areaList = createAreaList(createArea("Test Area A", "This is Test Area A"));
areaNode * counter = areaList;
addAreaNodeToList(areaList, createArea("Test Area B", "This is Test Area B"));
addAreaNodeToList(areaList, createArea("Test Area C", "This is Test Area C"));
for(int index = 0; index <= 2; index++)
{
printf("%s\n", counter->data->areaName);
counter = counter->next;
}
deleteAreaNodeFromList(areaList, getAreaFromList(areaList, 1));
addAreaNodeToList(areaList, createArea("Test Area D", "This is Test Area D"));
counter = areaList;
for(int index = 0; index <= 2; index++)
{
printf("%s\n", counter->data->areaName);
counter = counter->next;
}
}