BachelorThesis/client.c
2022-06-07 17:33:54 +00:00

318 lines
7.5 KiB
C

/*
Author: Jozef Simko
School year: 3., Bachelor study, 2021/22
Study program: Computer Networks
Organization: Technical University of Kosice (TUKE), Faculty of Electrical Engineering and Informatics (FEI),
Compiler: Winlibs GCC -- MinGW-W64 x86_64-posix-seh version 11.2.0, built by Brecht Sanders (OS Win)
-- gcc version 9.3.0 (OS Linux)
compile: WIN -- gcc client.c -Wall -Wextra -lwsock32 -o client
LINUX -- gcc server.c -Wall -Wextra -o server
version: 1.2.1 , 7.6.2022
Usage: Program can communicate with second program (server) using sockets.
It works in active or passive mode according to settings of server.
*/
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Defines lenght of user input and output send to server
Should not be less than longest user command in commands.txt file */
#define MESSAGE_SIZE 16
/* Defines lenght of buffer for server's messages
It's better to use higher values, it's helpful in case of hardware/network overload */
#define REPLY_MSG_SIZE 2048
/* Defines exact amount of user commands in commands.txt file and works as safety feature
Should not be less than number of lines in commands.txt file */
#define CMD_BUF_SIZE 13
/* Defines lenght of buffer used to read line from commands.txt file
Should not be less than the longest line in file commands.txt */
#define LINE_SIZE 256
/*###########################################
DEFINED FUNCTIONS
#############################################*/
/*
Writes input to log file with time stamp
*/
void write_log(FILE *log, char *mess){
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
mess[strcspn(mess, "\r")] = 0;
fprintf (log, "%02d/%02d/%d - %02d:%02d:%02d: %s\n", timeinfo->tm_mday, timeinfo->tm_mon+1, timeinfo->tm_year+1900,
timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, mess);
return;
}
/*
Closes socket (with dependency on used OS)
*/
void cleanUP(int sock){
#ifdef WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
return;
}
/*
Frees allocated memory of pointer to array of chars
*/
void freeCMD(char *commands[], char *ls_commands[], char *description[], int i){
for(int f=0; f < i; f++){
free(commands[f]);
free(ls_commands[f]);
free(description[f]);
}
return;
}
/* ######################################### */
int main(int argc , char *argv[]){
if (argc != 3){
fprintf(stderr, "Usage:\n");
fprintf(stderr, "- %s <Server IP> <Server Port>\n", argv[0]);
return 1;
}
int sock;
struct sockaddr_in server;
char message[MESSAGE_SIZE];
char server_reply[REPLY_MSG_SIZE];
#ifdef WIN32
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0){
printf("WSASturtup() failed %d\n", iResult);
return 1;
}
#endif
// Create socket
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("socket() failed\n");
cleanUP(sock);
return 1;
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port = htons(atoi(argv[2]));
// Connect to remote server
if (connect(sock, (struct sockaddr *) &server, sizeof(server)) != 0){
printf("Cannot connect to server - please check IP, port and status of server before trying again!\n");
cleanUP(sock);
return 1;
}
memset(server_reply, 0, REPLY_MSG_SIZE);
if(recv(sock, server_reply, 2, 0) <= 0){
printf("Connection interrupted! Check server status!\n");
cleanUP(sock);
return 1;
}
// Check server's mode and set control variable
int automatic = 0;
if(strcmp(server_reply, "0") == 0){
printf("Connected - manual mode.\n");
}
else{
printf("Connected - automatic mode.\n");
automatic = 1;
}
char *commands[CMD_BUF_SIZE];
char *ls_commands[CMD_BUF_SIZE];
char *description[CMD_BUF_SIZE];
int i = 0;
// Manual mode
if(automatic == 0){
// Load user commands
FILE *fptr;
if ((fptr = fopen("commands.txt", "r")) == NULL) {
printf("Cannot open command file!\n");
cleanUP(sock);
return 1;
}
char line[LINE_SIZE];
memset(line, 0, LINE_SIZE);
while(fgets(line, sizeof(line), fptr) != NULL) {
char *rest = line;
char *cmd = strtok_r(line, ":", &rest);
char *ls_cmd = strtok_r(rest, ":", &rest);
char *des = strtok_r(rest, ":", &rest);
commands[i] = (char *)calloc(strlen(cmd)+2, sizeof(char));
strcpy(commands[i], cmd);
ls_commands[i] = (char *)calloc(strlen(ls_cmd)+2, sizeof(char));
strcpy(ls_commands[i], ls_cmd);
description[i] = (char *)calloc(strlen(des)+2, sizeof(char));
strcpy(description[i], des);
i++;
}
fclose(fptr);
puts("Commands loaded. Type 'show' or 'show info' to see more. Use 'close' for client shutdown.");
}
FILE *logs;
// Communication with server
while(1){
memset(server_reply, 0, REPLY_MSG_SIZE);
if(automatic == 0){
logs = fopen("logy.txt", "a");
if(logs == NULL){
printf("Cannot open/create log file!\n");
cleanUP(sock);
return 1;
}
// Wait for, read and compare user input
char message_lsm[MESSAGE_SIZE];
memset(message_lsm, 0, MESSAGE_SIZE);
printf(">> Enter command: ");
memset(message, 0, MESSAGE_SIZE);
char* r = fgets(message, MESSAGE_SIZE, stdin);
if (r == NULL){
printf("Input failed.\n");
break;
}
if(strcmp(message, "\n") == 0){
continue;
}
message[strcspn(message, "\n")] = 0;
if(strcmp(message, "close") == 0){
break;
}
if(strcmp(message, "show") == 0){
for(int cmd = 0; cmd < i; cmd++){
printf("%s\n", commands[cmd]);
}
printf("\n");
continue;
}
else if(strcmp(message, "show info") == 0){
for(int cmds = 0; cmds < i; cmds++){
printf("%s - %s", commands[cmds], description[cmds]);
}
printf("\n");
continue;
}
else{
int check = 0;
for(int y=0; y < i; y++){
if(strcmp(message, commands[y]) == 0){
strcpy(message_lsm, ls_commands[y]);
write_log(logs, message_lsm);
check = 1;
fclose(logs);
}
}
if(check == 0){
printf("Invalid input. Try commands 'show' or 'show info' to check all avaible commands.\n");
continue;
}
}
// Send data
if(send(sock, message_lsm, strlen(message_lsm), 0) < (ssize_t)strlen(message_lsm)){
printf("send() failed");
cleanUP(sock);
freeCMD(commands, ls_commands, description, i);
return 1;
}
}
// Receive a reply from the server
if(recv(sock, server_reply, REPLY_MSG_SIZE, 0) <= 0){
printf("Server crashed or disconnected!\n");
cleanUP(sock);
if(automatic == 0){
freeCMD(commands, ls_commands, description, i);
}
return 0;
}
// Write received data to logs and to terminal
if(automatic == 0){
logs = fopen("logy.txt", "a");
if(logs == NULL){
printf("Cannot create/write to log file!\n");
cleanUP(sock);
return 1;
}
puts("Server reply: ");
write_log(logs, server_reply);
printf("%s\n", server_reply);
printf("\n");
fprintf(logs, "\n");
fclose(logs);
}
else{
// Char % indicates end of measurement
if(strcmp(server_reply, "%") == 0){
break;
}
logs = fopen("auto-logy.txt", "a");
if(logs == NULL){
printf("Cannot open auto-log file!\n");
cleanUP(sock);
return 1;
}
fprintf(logs, "%s", server_reply);
printf("%s", server_reply);
fclose(logs);
}
}
cleanUP(sock);
return 0;
}