/* 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 #else #include #include #include #include #include #endif #include #include #include #include /* 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 \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; }