Cleaned up client.

- Cleaned up the client codebase.
- Throughly commented SilverMUDClient.c.
- Added a boolean for bolding slowPrintNcurses.
- Added a user-configurable delay for text printing.
- Other small improvements.
This commit is contained in:
Barry 2022-03-15 14:52:49 +00:00
parent 5d772df469
commit e4b8693037
4 changed files with 137 additions and 137 deletions

View File

@ -1,3 +1,6 @@
// Silverkin Industries Comm-Link Client, Public Demonstration Sample Alpha 0.3.
// PROJECT CODENAME: WHAT DO I PAY YOU FOR? | Level-3 Clearance.
// Barry Kane, 2021
#include <netdb.h> #include <netdb.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
@ -14,84 +17,91 @@
#include "misc/texteffects.h" #include "misc/texteffects.h"
#include "misc/inputoutput.h" #include "misc/inputoutput.h"
#include "misc/inputhandling.h" #include "misc/inputhandling.h"
#define PORT 5000
#define SA struct sockaddr
static int MAX = 2048; static int MAX = 2048;
// A struct for passing arguments to our threads containing a file descriptor and a window pointer: // A struct for passing arguments to our threads containing a file descriptor and a window pointer:
typedef struct threadparameters typedef struct threadparameters
{ {
gnutls_session_t tlssession; gnutls_session_t tlsSession;
FILE * loggingstream; FILE * loggingStream;
bool loggingflag; bool loggingFlag;
WINDOW * window; WINDOW * window;
} threadparameters; } threadparameters;
// A globally availible exit boolean. // Use sockaddr as a type:
typedef struct sockaddr sockaddr;
// A globally available exit boolean:
bool shouldExit = false; bool shouldExit = false;
void * messageSender(void * parameters) void * messageSender(void * parameters)
{ {
// Takes user input in a window, sanatizes it, and sends it to the server:
struct threadparameters *threadParameters = parameters; struct threadparameters *threadParameters = parameters;
userMessage sendBuffer; userMessage sendBuffer;
// Repeatedly get input from the user, place it in a userMessage, and send it to the server:
while (!shouldExit) while (!shouldExit)
{ {
// Print the prompt:
wprintw(threadParameters->window, "\n\n\nCOMM-LINK> "); wprintw(threadParameters->window, "\n\n\nCOMM-LINK> ");
if(wgetnstr(threadParameters->window, sendBuffer.messageContent, MAX) == ERR) if (wgetnstr(threadParameters->window, sendBuffer.messageContent, MAX) == ERR)
{ {
// Quit if there's any funny business with getting input: // Quit if there's any funny business with getting input:
pthread_exit(NULL); pthread_exit(NULL);
} }
if(sendBuffer.messageContent[0] == '\n')
// Ignore empty messages:
if (sendBuffer.messageContent[0] == '\n')
{ {
continue; continue;
} }
if(threadParameters->loggingflag == true)
// Send the message to the log if logging is enabled:
if (threadParameters->loggingFlag == true)
{ {
fputs(sendBuffer.messageContent, threadParameters->loggingstream); fputs(sendBuffer.messageContent, threadParameters->loggingStream);
fputs("\n", threadParameters->loggingstream); fputs("\n", threadParameters->loggingStream);
fflush(threadParameters->loggingstream); fflush(threadParameters->loggingStream);
} }
wprintw(threadParameters->window, sendBuffer.messageContent);
messageSend(threadParameters->tlssession, &sendBuffer); // Send the message off to the server:
messageSend(threadParameters->tlsSession, &sendBuffer);
} }
pthread_exit(NULL); pthread_exit(NULL);
} }
void * messageReceiver(void * parameters) void * messageReceiver(void * parameters)
{ {
// Takes messages from the server and prints them to the chat log window:
struct threadparameters *threadParameters = parameters; struct threadparameters *threadParameters = parameters;
userMessage receiveBuffer; userMessage receiveBuffer;
// Repeatedly take messages from the server and print them to the chat log window:
while (!shouldExit) while (!shouldExit)
{ {
messageReceive(threadParameters->tlssession, &receiveBuffer); messageReceive(threadParameters->tlsSession, &receiveBuffer);
if(receiveBuffer.senderName[0] == '\0') if (receiveBuffer.senderName[0] == '\0')
{ {
//if(receiveBuffer.messageContent[0] == '\0') if (receiveBuffer.messageContent[0] == '\0')
//{ {
// shouldExit = true; shouldExit = true;
// pthread_exit(NULL); pthread_exit(NULL);
//} }
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window); slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window, true);
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window); slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window, false);
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window); slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window, true);
} }
else else
{ {
if(threadParameters->loggingflag == true) if (threadParameters->loggingFlag == true)
{ {
fputs(receiveBuffer.senderName, threadParameters->loggingstream); fputs(receiveBuffer.senderName, threadParameters->loggingStream);
fputs(": ", threadParameters->loggingstream); fputs(": ", threadParameters->loggingStream);
fputs(receiveBuffer.messageContent, threadParameters->loggingstream); fputs(receiveBuffer.messageContent, threadParameters->loggingStream);
fflush(threadParameters->loggingstream); fflush(threadParameters->loggingStream);
} }
slowPrintNcurses(receiveBuffer.senderName, 8000, threadParameters->window); slowPrintNcurses(receiveBuffer.senderName, 8000, threadParameters->window, true);
slowPrintNcurses(": ", 8000, threadParameters->window); slowPrintNcurses(": ", 8000, threadParameters->window, true);
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window); slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window, false);
} }
} }
pthread_exit(NULL); pthread_exit(NULL);
@ -99,59 +109,70 @@ void * messageReceiver(void * parameters)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int sockfd; int socketFileDesc;
struct sockaddr_in servaddr; struct sockaddr_in serverAddress;
pthread_t sendingThread; pthread_t sendingThread;
pthread_t receivingThread; pthread_t receivingThread;
int port = 5000; int port = 5000;
int currentopt = 0; int currentopt = 0;
char chatlogpath[PATH_MAX + 1]; int characterDelay = 8000;
char gamelogpath[PATH_MAX + 1]; char chatLogPath[PATH_MAX + 1];
char ipaddress[32] = "127.0.0.1"; char gameLogPath[PATH_MAX + 1];
FILE * chatlog = NULL, * gamelog = NULL; char ipAddress[32] = "127.0.0.1";
bool chatlogging = false, gamelogging = false; FILE * chatLog = NULL, * gameLog = NULL;
bool chatLogging = false, gameLogging = false;
// Print welcome message: // Print welcome message:
slowPrint("\n--==== \033[33;40mSILVERKIN INDUSTRIES\033[0m COMM-LINK CLIENT ====--\nVersion Alpha 0.3\n", 5000); slowPrint("\n--==== \033[33;40mSILVERKIN INDUSTRIES\033[0m COMM-LINK CLIENT ====--\nVersion Alpha 0.3\n", 5000);
// Parse command-line options: // Parse command-line options:
while((currentopt = getopt(argc, argv, "i:c:g:p:")) != -1) while ((currentopt = getopt(argc, argv, "i:c:g:p:d:")) != -1)
{ {
switch(currentopt) switch (currentopt)
{ {
case 'i': case 'i':
{ {
strncpy(ipaddress, optarg, 32); strncpy(ipAddress, optarg, 32);
break; break;
} }
case 'c': case 'c':
{ {
strncpy(chatlogpath, optarg, PATH_MAX + 1); strncpy(chatLogPath, optarg, PATH_MAX + 1);
chatlog = fopen(chatlogpath, "a+"); chatLog = fopen(chatLogPath, "a+");
if(chatlog == NULL) if (chatLog == NULL)
{ {
chatlogging = false; chatLogging = false;
} }
else else
{ {
chatlogging = true; chatLogging = true;
} }
break; break;
} }
case 'g': case 'g':
{ {
strncpy(gamelogpath, optarg, PATH_MAX + 1); strncpy(gameLogPath, optarg, PATH_MAX + 1);
gamelog = fopen(gamelogpath, "a+"); gameLog = fopen(gameLogPath, "a+");
if(gamelog == NULL) if (gameLog == NULL)
{ {
gamelogging = false; gameLogging = false;
} }
else else
{ {
gamelogging = true; gameLogging = true;
} }
break; break;
} }
case 'p':
{
port = atoi(optarg);
break;
}
case 'd':
{
characterDelay = atoi(optarg);
break;
}
case '?': case '?':
{ {
return 1; return 1;
@ -161,57 +182,62 @@ int main(int argc, char **argv)
} }
// Give me a socket, and make sure it's working: // Give me a socket, and make sure it's working:
sockfd = socket(AF_INET, SOCK_STREAM, 0); socketFileDesc = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) if (socketFileDesc == -1)
{ {
printf("Socket creation failed.\n"); printf("Socket creation failed.\n");
exit(0); exit(EXIT_FAILURE);
} }
else else
{ {
slowPrint("Socket successfully created.\n", 8000); slowPrint("Socket successfully created.\n", characterDelay);
} }
bzero(&servaddr, sizeof(servaddr)); bzero(&serverAddress, sizeof(serverAddress));
// Set our IP Address and port. Default to localhost for testing: // Set our IP Address and port. Default to localhost for testing:
servaddr.sin_family = AF_INET; serverAddress.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(ipaddress); serverAddress.sin_addr.s_addr = inet_addr(ipAddress);
servaddr.sin_port = htons(port); serverAddress.sin_port = htons(port);
// Connect the server and client sockets, Kronk: // Connect the server and client sockets, Kronk:
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) if (connect(socketFileDesc, (sockaddr*)&serverAddress, sizeof(serverAddress)) != 0)
{ {
slowPrint("Connection with the Silverkin Industries Comm-Link Server Failed:\nPlease contact your service representative.\n", 8000); slowPrint("Connection with the Silverkin Industries Comm-Link Server Failed:\nPlease contact your service representative.\n", characterDelay);
exit(0); exit(0);
} }
else else
{ {
slowPrint("Connected to the Silverkin Industries Comm-Link Server:\nHave a pleasant day.\n", 8000); slowPrint("Connected to the Silverkin Industries Comm-Link Server:\nHave a pleasant day.\n", characterDelay);
} }
usleep(100000); usleep(100000);
/* TODO: Negotiate TLS
Need to pull in GNU TLS, and do the same on the server-side. */
// Setup a GnuTLS session and initialize it: // Setup a GnuTLS session and initialize it:
gnutls_session_t tlssession = NULL; gnutls_session_t tlsSession = NULL;
if(gnutls_init(&tlssession, GNUTLS_CLIENT) < 0) if (gnutls_init(&tlsSession, GNUTLS_CLIENT) < 0)
{ {
// Failure Case // Failure Case
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Setup the private credentials for our GnuTLS session:
gnutls_anon_client_credentials_t clientkey = NULL; gnutls_anon_client_credentials_t clientkey = NULL;
gnutls_anon_allocate_client_credentials(&clientkey); gnutls_anon_allocate_client_credentials(&clientkey);
gnutls_credentials_set(tlssession, GNUTLS_CRD_ANON, &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. */ // Bind the open socket to the TLS session:
gnutls_handshake_set_timeout(tlssession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); gnutls_transport_set_int(tlsSession, socketFileDesc);
int r = -1; gnutls_priority_set_direct(tlsSession, "PERFORMANCE:+ANON-ECDH:+ANON-DH", NULL);
do {
r = gnutls_handshake(tlssession); // Use the default for the GnuTLS handshake timeout:
} while (r < 0 && gnutls_error_is_fatal(r) == 0); gnutls_handshake_set_timeout(tlsSession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
// Repeatedly attempt to handshake unless we encounter a fatal error:
int returnValue = -1;
do
{
returnValue = gnutls_handshake(tlsSession);
}
while (returnValue < 0 && gnutls_error_is_fatal(returnValue) == 0);
// Setup Ncurses: // Setup Ncurses:
initscr(); initscr();
@ -225,18 +251,18 @@ int main(int argc, char **argv)
// Make the windows for the structs, and pass the socket descriptor: // Make the windows for the structs, and pass the socket descriptor:
logArea->window = newwin(LINES - 5, COLS - 2, 1, 1); logArea->window = newwin(LINES - 5, COLS - 2, 1, 1);
logArea->tlssession = tlssession; logArea->tlsSession = tlsSession;
logArea->loggingflag = chatlogging; logArea->loggingFlag = chatLogging;
if(chatlog != NULL) if (chatLog != NULL)
{ {
logArea->loggingstream = chatlog; logArea->loggingStream = chatLog;
} }
messageArea->window = newwin(3, COLS, LINES - 3, 0); messageArea->window = newwin(3, COLS, LINES - 3, 0);
messageArea->tlssession = tlssession; messageArea->tlsSession = tlsSession;
messageArea->loggingflag = gamelogging; messageArea->loggingFlag = gameLogging;
if(gamelog != NULL) if (gameLog != NULL)
{ {
messageArea->loggingstream = gamelog; messageArea->loggingStream = gameLog;
} }
// Set the two windows to scroll: // Set the two windows to scroll:
@ -253,26 +279,27 @@ int main(int argc, char **argv)
// Close the threads: // Close the threads:
pthread_cancel(sendingThread); pthread_cancel(sendingThread);
// Close the socket: // Close the session and socket:
close(sockfd); gnutls_bye(tlsSession, GNUTLS_SHUT_RDWR);
close(socketFileDesc);
// Free the structs: // Free the structs:
free(logArea); free(logArea);
free(messageArea); free(messageArea);
// Close the files: // Close the log files:
if(gamelog != NULL) if (gameLog != NULL)
{ {
fclose(gamelog); fclose(gameLog);
} }
if(chatlog != NULL) if (chatLog != NULL)
{ {
fclose(chatlog); fclose(chatLog);
} }
// Unsetup Ncurses: // Unsetup Ncurses:
endwin(); endwin();
// Say Goodbye: // Say goodbye:
slowPrint("\nThank you for choosing Silverkin Industries, valued customer!\n", 8000); slowPrint("\nThank you for choosing Silverkin Industries, valued customer!\n", characterDelay);
} }

View File

@ -35,18 +35,10 @@ int main()
char testString[32] = "Hehe."; char testString[32] = "Hehe.";
struct sockaddr_in serverAddress, clientAddress; struct sockaddr_in serverAddress, clientAddress;
// Initialize areas:
areaNode * areas = createAreaList(createArea("Spawn - North", "A large area, mostly empty, as if the designer hadn't bothered to put anything in it, just yet."));
addAreaNodeToList(areas, createArea("Spawn - South", "A strange, white void. You feel rather uncomfortable."));
addAreaNodeToList(areas, createArea("Temple of Emacs", "A beautifully ornate statue of GNU is above you on a pedestal. Inscribed into the pillar, over and over, is the phrase \"M-x exalt\", in delicate gold letters. You can't help but be awestruck."));
createPath(getAreaFromList(areas, 0), getAreaFromList(areas, 1), "To South Spawn", "To North Spawn");
createPath(getAreaFromList(areas, 2), getAreaFromList(areas, 1), "Back to South Spawn", "Path to Enlightenment.");
// Initialize playerdata: // Initialize playerdata:
for (int index = 0; index < PLAYERCOUNT; index++) for (int index = 0; index < PLAYERCOUNT; index++)
{ {
strcpy(connectedPlayers[index].playerName, "UNNAMED"); strcpy(connectedPlayers[index].playerName, "UNNAMED");
connectedPlayers[index].currentArea = getAreaFromList(areas, 0);
} }
// Give an intro: Display the Silverkin Industries logo and splash text. // Give an intro: Display the Silverkin Industries logo and splash text.
@ -208,33 +200,6 @@ int main()
} }
} }
} }
/* // 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; return 0;
} }

View File

@ -17,9 +17,13 @@ void slowPrint(char * stringToPrint, int delay)
} }
} }
void slowPrintNcurses(char * stringToPrint, int delay, WINDOW * window) void slowPrintNcurses(char * stringToPrint, int delay, WINDOW * window, bool bolded)
{ {
int characterIndex = 0; int characterIndex = 0;
if(bolded)
{
wattron(window, A_BOLD);
}
while(stringToPrint[characterIndex] != '\0') while(stringToPrint[characterIndex] != '\0')
{ {
waddch(window, stringToPrint[characterIndex]); waddch(window, stringToPrint[characterIndex]);
@ -28,5 +32,9 @@ void slowPrintNcurses(char * stringToPrint, int delay, WINDOW * window)
usleep(delay); usleep(delay);
characterIndex++; characterIndex++;
} }
if(bolded)
{
wattroff(window, A_BOLD);
}
wrefresh(window); wrefresh(window);
} }

View File

@ -9,7 +9,7 @@
void slowPrint(char * stringToPrint, int delay); void slowPrint(char * stringToPrint, int delay);
// The same, altered to work with Ncurses. // The same, altered to work with Ncurses.
void slowPrintNcurses(char * stringToPrint, int delay, WINDOW * window); void slowPrintNcurses(char * stringToPrint, int delay, WINDOW * window, bool bolded);
// A string containing an ASCII art version of the Silverkin Industries logo. // A string containing an ASCII art version of the Silverkin Industries logo.
char * logostring = " ///////\n //////////////////////////////////////////\n ///////////////////////////////////////////////////////////\n ////////// ////////////////////////////\n ### # # # # ##### ### # # # # # /////////////////\n ### # # # # ## # # ## # ## # //////////////\n ## # # # # # ### # # # # # # /////////\n #### # ### # ##### # # # # # # ## ///////\n # ## # ##### # # ### ### ### # ##### ### ////// \n # # # # # # # # ## # # # # ## ## ////\n # # # # # # # # ## # ### # # ## //\n # # ### ##### ##### ### # # # # #### ### //\n"; char * logostring = " ///////\n //////////////////////////////////////////\n ///////////////////////////////////////////////////////////\n ////////// ////////////////////////////\n ### # # # # ##### ### # # # # # /////////////////\n ### # # # # ## # # ## # ## # //////////////\n ## # # # # # ### # # # # # # /////////\n #### # ### # ##### # # # # # # ## ///////\n # ## # ##### # # ### ### ### # ##### ### ////// \n # # # # # # # # ## # # # # ## ## ////\n # # # # # # # # ## # ### # # ## //\n # # ### ##### ##### ### # # # # #### ### //\n";