Added basic logging support and command-line options to the client.
- Added basic logging support to the client. - Added basic command-line options to the client: -g: Enables a game-log, must have a file-path. -c: Enables a chat-log, must have a file-path. -i: Sets the IP address to connect to. - Removed the C-c handler, appeared to be broken anyways. Consider reimplementation at some point. - Added /EXIT command to allow for leaving the game. - The client now exits gracefully if the server dies.
This commit is contained in:
parent
6c93805d6f
commit
235ff8e74f
|
@ -1,9 +1,9 @@
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
@ -20,17 +20,14 @@
|
||||||
typedef struct threadparameters
|
typedef struct threadparameters
|
||||||
{
|
{
|
||||||
int socketDescriptor;
|
int socketDescriptor;
|
||||||
|
FILE * loggingstream;
|
||||||
|
bool loggingflag;
|
||||||
WINDOW * window;
|
WINDOW * window;
|
||||||
} threadparameters;
|
} threadparameters;
|
||||||
|
|
||||||
// A globally availible exit boolean.
|
// A globally availible exit boolean.
|
||||||
bool shouldExit = false;
|
bool shouldExit = false;
|
||||||
|
|
||||||
void sigintHandler(int signal)
|
|
||||||
{
|
|
||||||
shouldExit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void * messageSender(void * parameters)
|
void * messageSender(void * parameters)
|
||||||
{
|
{
|
||||||
// Takes user input in a window, sanatizes it, and sends it to the server:
|
// Takes user input in a window, sanatizes it, and sends it to the server:
|
||||||
|
@ -50,8 +47,14 @@ void * messageSender(void * parameters)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if(threadParameters->loggingflag == true)
|
||||||
|
{
|
||||||
|
fputs(sendBuffer, threadParameters->loggingstream);
|
||||||
|
fputs("\n", threadParameters->loggingstream);
|
||||||
|
fflush(threadParameters->loggingstream);
|
||||||
|
}
|
||||||
write(threadParameters->socketDescriptor, sendBuffer, MAX);
|
write(threadParameters->socketDescriptor, sendBuffer, MAX);
|
||||||
}
|
}
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,15 +68,26 @@ void * messageReceiver(void * parameters)
|
||||||
{
|
{
|
||||||
read(threadParameters->socketDescriptor, &receiveBuffer.senderName, sizeof(receiveBuffer.senderName));
|
read(threadParameters->socketDescriptor, &receiveBuffer.senderName, sizeof(receiveBuffer.senderName));
|
||||||
read(threadParameters->socketDescriptor, &receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent));
|
read(threadParameters->socketDescriptor, &receiveBuffer.messageContent, sizeof(receiveBuffer.messageContent));
|
||||||
|
|
||||||
if(receiveBuffer.senderName[0] == '\0')
|
if(receiveBuffer.senderName[0] == '\0')
|
||||||
{
|
{
|
||||||
|
if(receiveBuffer.messageContent[0] == '\0')
|
||||||
|
{
|
||||||
|
shouldExit = true;
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window);
|
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window);
|
||||||
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window);
|
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window);
|
||||||
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window);
|
slowPrintNcurses("\n --====<>====-- \n", 8000, threadParameters->window);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if(threadParameters->loggingflag == true)
|
||||||
|
{
|
||||||
|
fputs(receiveBuffer.senderName, threadParameters->loggingstream);
|
||||||
|
fputs(": ", threadParameters->loggingstream);
|
||||||
|
fputs(receiveBuffer.messageContent, threadParameters->loggingstream);
|
||||||
|
fflush(threadParameters->loggingstream);
|
||||||
|
}
|
||||||
slowPrintNcurses(receiveBuffer.senderName, 8000, threadParameters->window);
|
slowPrintNcurses(receiveBuffer.senderName, 8000, threadParameters->window);
|
||||||
slowPrintNcurses(": ", 8000, threadParameters->window);
|
slowPrintNcurses(": ", 8000, threadParameters->window);
|
||||||
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window);
|
slowPrintNcurses(receiveBuffer.messageContent, 8000, threadParameters->window);
|
||||||
|
@ -91,13 +105,63 @@ int main(int argc, char **argv)
|
||||||
struct sockaddr_in servaddr;
|
struct sockaddr_in servaddr;
|
||||||
pthread_t sendingThread;
|
pthread_t sendingThread;
|
||||||
pthread_t receivingThread;
|
pthread_t receivingThread;
|
||||||
|
int port = 5000;
|
||||||
// Set the SIGINT handler.
|
int currentopt = 0;
|
||||||
signal(SIGINT, sigintHandler);
|
char chatlogpath[PATH_MAX + 1];
|
||||||
|
char gamelogpath[PATH_MAX + 1];
|
||||||
|
char ipaddress[32] = "127.0.0.1";
|
||||||
|
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:
|
||||||
|
while((currentopt = getopt(argc, argv, "i:c:g:p:")) != -1)
|
||||||
|
{
|
||||||
|
switch(currentopt)
|
||||||
|
{
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
strncpy(ipaddress, optarg, 32);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c':
|
||||||
|
{
|
||||||
|
strncpy(chatlogpath, optarg, PATH_MAX + 1);
|
||||||
|
chatlog = fopen(chatlogpath, "a+");
|
||||||
|
if(chatlog == NULL)
|
||||||
|
{
|
||||||
|
chatlogging = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chatlogging = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'g':
|
||||||
|
{
|
||||||
|
strncpy(gamelogpath, optarg, PATH_MAX + 1);
|
||||||
|
gamelog = fopen(gamelogpath, "a+");
|
||||||
|
if(gamelog == NULL)
|
||||||
|
{
|
||||||
|
gamelogging = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gamelogging = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '?':
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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);
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd == -1)
|
if (sockfd == -1)
|
||||||
|
@ -113,15 +177,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
// 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;
|
servaddr.sin_family = AF_INET;
|
||||||
if (argc == 1)
|
servaddr.sin_addr.s_addr = inet_addr(ipaddress);
|
||||||
{
|
servaddr.sin_port = htons(port);
|
||||||
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
|
|
||||||
}
|
|
||||||
servaddr.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(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0)
|
||||||
|
@ -148,9 +205,19 @@ 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->socketDescriptor = sockfd;
|
logArea->socketDescriptor = sockfd;
|
||||||
|
logArea->loggingflag = chatlogging;
|
||||||
|
if(chatlog != NULL)
|
||||||
|
{
|
||||||
|
logArea->loggingstream = chatlog;
|
||||||
|
}
|
||||||
messageArea->window = newwin(3, COLS, LINES - 3, 0);
|
messageArea->window = newwin(3, COLS, LINES - 3, 0);
|
||||||
messageArea->socketDescriptor = sockfd;
|
messageArea->socketDescriptor = sockfd;
|
||||||
|
messageArea->loggingflag = gamelogging;
|
||||||
|
if(gamelog != NULL)
|
||||||
|
{
|
||||||
|
messageArea->loggingstream = gamelog;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the two windows to scroll:
|
// Set the two windows to scroll:
|
||||||
scrollok(logArea->window, true);
|
scrollok(logArea->window, true);
|
||||||
scrollok(messageArea->window, true);
|
scrollok(messageArea->window, true);
|
||||||
|
@ -159,15 +226,11 @@ int main(int argc, char **argv)
|
||||||
pthread_create(&sendingThread, NULL, messageSender, messageArea);
|
pthread_create(&sendingThread, NULL, messageSender, messageArea);
|
||||||
pthread_create(&receivingThread, NULL, messageReceiver, logArea);
|
pthread_create(&receivingThread, NULL, messageReceiver, logArea);
|
||||||
|
|
||||||
// Wait for SIGINT to change
|
// Wait for /EXIT:
|
||||||
while(!shouldExit)
|
pthread_join(receivingThread, NULL);
|
||||||
{
|
|
||||||
sleep(250);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the threads:
|
// Close the threads:
|
||||||
pthread_cancel(sendingThread);
|
pthread_cancel(sendingThread);
|
||||||
pthread_cancel(receivingThread);
|
|
||||||
|
|
||||||
// Close the socket:
|
// Close the socket:
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
@ -175,6 +238,16 @@ int main(int argc, char **argv)
|
||||||
// Free the structs:
|
// Free the structs:
|
||||||
free(logArea);
|
free(logArea);
|
||||||
free(messageArea);
|
free(messageArea);
|
||||||
|
|
||||||
|
// Close the files:
|
||||||
|
if(gamelog != NULL)
|
||||||
|
{
|
||||||
|
fclose(gamelog);
|
||||||
|
}
|
||||||
|
if(chatlog != NULL)
|
||||||
|
{
|
||||||
|
fclose(chatlog);
|
||||||
|
}
|
||||||
|
|
||||||
// Unsetup Ncurses:
|
// Unsetup Ncurses:
|
||||||
endwin();
|
endwin();
|
||||||
|
|
|
@ -31,7 +31,7 @@ int main()
|
||||||
playerInfo connectedPlayers[64];
|
playerInfo connectedPlayers[64];
|
||||||
struct sockaddr_in serverAddress, clientAddress;
|
struct sockaddr_in serverAddress, clientAddress;
|
||||||
|
|
||||||
// Initialize areas:
|
// 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."));
|
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("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."));
|
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."));
|
||||||
|
@ -98,7 +98,7 @@ int main()
|
||||||
}
|
}
|
||||||
length = sizeof(clientAddress);
|
length = sizeof(clientAddress);
|
||||||
|
|
||||||
// Accept the data packet from client and verification
|
// Accept the data packet from client and verify it:
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
FD_ZERO(&connectedClients);
|
FD_ZERO(&connectedClients);
|
||||||
|
@ -134,8 +134,7 @@ int main()
|
||||||
// If it's the master socket selected, there is a new connection:
|
// If it's the master socket selected, there is a new connection:
|
||||||
if (FD_ISSET(socketFileDesc, &connectedClients))
|
if (FD_ISSET(socketFileDesc, &connectedClients))
|
||||||
{
|
{
|
||||||
if ((connectionFileDesc = accept(socketFileDesc,
|
if ((connectionFileDesc = accept(socketFileDesc, (struct sockaddr *)&clientAddress, (socklen_t*)&length))<0)
|
||||||
(struct sockaddr *)&clientAddress, (socklen_t*)&length))<0)
|
|
||||||
{
|
{
|
||||||
perror("Failed to accept connection. Aborting.\n");
|
perror("Failed to accept connection. Aborting.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -181,7 +180,7 @@ int main()
|
||||||
// Close the socket and mark as 0 in list for reuse:
|
// Close the socket and mark as 0 in list for reuse:
|
||||||
close(socketCheck);
|
close(socketCheck);
|
||||||
clientSockets[i] = 0;
|
clientSockets[i] = 0;
|
||||||
}
|
}
|
||||||
// Name change command: Move logic to a command interpreter later:
|
// Name change command: Move logic to a command interpreter later:
|
||||||
else if (receiveBuffer[0] == '/')
|
else if (receiveBuffer[0] == '/')
|
||||||
{
|
{
|
||||||
|
@ -209,6 +208,18 @@ int main()
|
||||||
strncpy(connectedPlayers[i].playerName, newName, 32);
|
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)
|
else if(strncmp(receiveBuffer, "/LOOK", 5) == 0)
|
||||||
{
|
{
|
||||||
strcat(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaDescription);
|
strcat(messageBuffer.messageContent, connectedPlayers[i].currentArea->areaDescription);
|
||||||
|
|
Loading…
Reference in New Issue