317 lines
7.5 KiB
C
317 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 , 17.5.2021
|
||
|
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
|
||
|
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;
|
||
|
|
||
|
if(automatic == 0){
|
||
|
|
||
|
// Load user commands
|
||
|
FILE *fptr;
|
||
|
if ((fptr = fopen("commands.txt", "r")) == NULL) {
|
||
|
printf("Cannot open/create log 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;
|
||
|
}
|