From 6889e2d66b710c241b3884fc28610a9e6be4e610 Mon Sep 17 00:00:00 2001 From: Matt Strapp Date: Mon, 25 Apr 2022 17:48:52 -0500 Subject: A --- src/util.cpp | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 src/util.cpp (limited to 'src/util.cpp') diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..142fcbd --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,398 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "util.hpp" + +#define VALID_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +enum Command parse_command(char* line){ + /* Find a valid command in the first word of the line (case sensitive) + args: + line (char*): string of characters from the input file + + returns: + (command): Returns the found command. Returns else if first word is invalid. + */ + if (line == NULL){ + return INVALID; + } + + char* rest; + char* tok = strtok_r(line, " ", &rest); + + if (tok == NULL){ + return INVALID; + } + + // REGISTER [username] [password] + if (strcmp(tok, "REGISTER") == 0){ + char* username = strtok_r(rest, " ", &rest); + if(!isValidUsername(username)) return INVALID; + + char* password = strtok_r(rest, " ", &rest); + if(password == NULL) return INVALID; + if(!isValidPassword(password)) return INVALID; + + char* misc = strtok_r(rest, " ", &rest); + if(misc != NULL) return INVALID; + + return REGISTER; + } + + // LOGIN [username] [password] + if (strcmp(tok, "LOGIN") == 0){ + char* username = strtok_r(rest, " ", &rest); + if(!isValidUsername(username)) return INVALID; + + char* password = strtok_r(rest, " ", &rest); + if(password == NULL) return INVALID; + if(!isValidPassword(password)) return INVALID; + + char* misc = strtok_r(rest, " ", &rest); + if(misc != NULL) return INVALID; + + return LOGIN; + } + + // LOGOUT + if (strcmp(tok, "LOGOUT") == 0){ + char* misc = strtok_r(rest, " ", &rest); + if(misc != NULL) return INVALID; + + return LOGOUT; + } + + // SEND [msg] + if (strcmp(tok, "SEND") == 0){ + if (int(strlen(rest) == 0)) return INVALID; + + return SEND; + } + + // SEND2 [username] [msg] + if (strcmp(tok, "SEND2") == 0){ + char* username = strtok_r(rest, " ", &rest); + if(!isValidUsername(username)) return INVALID; + + if (int(strlen(rest) == 0)) return INVALID; + + return SEND2; + } + + // SENDA [msg] + if (strcmp(tok, "SENDA") == 0){ + if (int(strlen(rest) == 0)) return INVALID; + + return SENDA; + } + + // SENDA2 [username] [msg] + if (strcmp(tok, "SENDA2") == 0){ + char* username = strtok_r(rest, " ", &rest); + if(!isValidUsername(username)) return INVALID; + + if (int(strlen(rest) == 0)) return INVALID; + + return SENDA2; + } + + // SENDF [local file] + if (strcmp(tok, "SENDF") == 0){ + char* file_name = strtok_r(rest, " ", &rest); + if(file_name == NULL) return INVALID; + + if (int(strlen(rest) != 0)) return INVALID; + + return SENDF; + } + + // SENDF2 [username] [local file] + if (strcmp(tok, "SENDF2") == 0){ + char* username = strtok_r(rest, " ", &rest); + if(!isValidUsername(username)) return INVALID; + + char* file_name = strtok_r(rest, " ", &rest); + if(file_name == NULL) return INVALID; + + if (int(strlen(rest) != 0)) return INVALID; + + return SENDF2; + } + + // LIST + if (strcmp(tok, "LIST") == 0){ + char* misc = strtok_r(rest, " ", &rest); + if(misc != NULL) return INVALID; + + return LIST; + } + + // DELAY + if (strcmp(tok, "DELAY") == 0){ + char* delay_time = strtok_r(rest, " ", &rest); + if(delay_time == NULL) return INVALID; + + std::string str(delay_time); + std::size_t found = str.find_first_not_of("0123456789"); + if(found != std::string::npos) return INVALID; + + if (int(strlen(rest) != 0)) return INVALID; + + return DELAY; + } + + // default + return INVALID; +} + + +bool isValidUsername(char* username){ + /* Helper function to check if a username string is valid + args: + username (char*): Username to be tested. + + returns: + bool: Username is valid ? true, false + */ + if(username == NULL) return false; + else if ((strlen(username) > MAX_USERNAME_LEN)||(strlen(username) < MIN_USERNAME_LEN)) return false; + else{ + std::string str(username); + std::size_t found = str.find_first_not_of(VALID_CHARACTERS); + if(found != std::string::npos) return false; + } + + return true; +} + + +bool isValidPassword(char* password){ + if(password == NULL) return false; + else if ((strlen(password) > MAX_PASSWORD_LEN)||(strlen(password) < MIN_PASSWORD_LEN)) return false; + else{ + std::string str(password); + std::size_t found = str.find_first_not_of(VALID_CHARACTERS); + if(found != std::string::npos) return false; + } + + return true; +} + + +void Error(const char * format, ...) { + char msg[4096]; + va_list argptr; + va_start(argptr, format); + vsprintf(msg, format, argptr); + va_end(argptr); + fprintf(stderr, "Error: %s\n", msg); + exit(-1); +} + +void Log(const char * format, ...) { + char msg[2048]; + va_list argptr; + va_start(argptr, format); + vsprintf(msg, format, argptr); + va_end(argptr); + fprintf(stderr, "%s\n", msg); +} + +// convert buf[0:3] to int +void buf2i(BYTE * buf, int &i){ + // No way to avoid Segmentation fault. Some bytes may be 0 + i = 0; + i += buf[3]; + i += ((int)(buf[2])) << 8; + i += ((int)(buf[1])) << 16; + i += ((int)(buf[0])) << 24; +} + +// convert int to buf[4] where buf[0] contains MSB's and buf[3] contains LSB's +void i2buf(int &i, BYTE * buf){ + // No way to avoid Segmentation fault. Some bytes may be 0 + buf[0] = (BYTE)((i & 0xFF000000) >> 24); + buf[1] = (BYTE)((i & 0x00FF0000) >> 16); + buf[2] = (BYTE)((i & 0x0000FF00) >> 8); + buf[3] = (BYTE)(i & 0x000000FF); +} + +const char * com2str(enum Command command){ + const char * com2str[] = {"REGISTER", + "LOGIN", + "LOGOUT", + "SEND", + "SEND2", + "SENDA", + "SENDA2", + "SENDF", + "SENDF2", + "LIST", + "DELAY", + "GETF", + "PING", + "CONNECT", + "", + "INVALID" + }; + return com2str[command]; +} + +// Computes the difference between times a and b in seconds +// a - b = result +double timeDifference(struct timeb a, struct timeb b){ + return (a.time + a.millitm / (double) 1000.0f) - (b.time + b.millitm / (double) 1000.0f); +} + +int getNumEntries(const char* database){ + FILE* fp = fopen(database, "r"); + if (!fp){ + Log("Username check failed to open the file: %s", database); + return -1; + } + + int numEntries = 0; + + char line[LINE_SIZE] = {0}; + while(fgets(line, LINE_SIZE, fp) != NULL){ + char* new_line_pos = strchr(line, '\n'); + if(new_line_pos != NULL) + *new_line_pos = 0; + // Including blank lines as entries. Don't use any blank lines. + numEntries++; + memset(line, 0, LINE_SIZE); + } + + fclose(fp); + return numEntries; +} + +// User/password is in registry: true +// User/password is not in registry: false +bool loginQuery(const char * database, char* username, char* password){ + FILE* fp = fopen(database, "r"); + if (!fp){ + Log("Registry check failed to open the file: %s", database); + return false; + } + + char line[LINE_SIZE] = {0}; + while(fgets(line, LINE_SIZE, fp) != NULL){ + char* new_line_pos = strchr(line, '\n'); + if(new_line_pos != NULL) + *new_line_pos = 0; + + char* rest; + char* usr = strtok_r(line, " ", &rest); + char* pswd = strtok_r(rest, " ", &rest); + + //Log("username: |%s| Password: |%s|", usr, pswd); + + if((strcmp(username, usr) == 0) && (strcmp(password, pswd) == 0)){ + fclose(fp); + return true; + } + + memset(line, 0, LINE_SIZE); + } + + fclose(fp); + return false; +} + +// User is in registry: true +// User is not in registry: false +bool usernameQuery(const char * database, char* username){ + FILE* fp = fopen(database, "r"); + if (!fp){ + Log("Username check failed to open the file: %s", database); + return false; + } + + char line[LINE_SIZE] = {0}; + while(fgets(line, LINE_SIZE, fp) != NULL){ + char* new_line_pos = strchr(line, '\n'); + if(new_line_pos != NULL) + *new_line_pos = 0; + + char* rest; + char* usr = strtok_r(line, " ", &rest); + + //Log("username: |%s|", usr); + + if(strcmp(username, usr) == 0){ + fclose(fp); + return true; + } + + memset(line, 0, LINE_SIZE); + } + + fclose(fp); + return false; +} + +void recordEntry(const char * database, char* key, char* value){ + FILE* fp = fopen(database, "a"); + + if (!fp){ + Log("Registry append failed to open the file: %s", database); + return; + } + + char line[LINE_SIZE] = {0}; + strcat(line, key); + strcat(line, " "); + strcat(line, value); + strcat(line, "\n"); + + fputs(line, fp); + fclose(fp); +} + +void clearDatabase(const char * database){ + FILE* fp = fopen(database, "w"); + fclose(fp); +} + + +int buf2file(BYTE* buf, int nbytes, char* filename){ + FILE* f = fopen(filename, "w"); + if(!f) return -1; + + fwrite(buf, 1, nbytes, f); + fclose(f); + return 0; +} + + +int file2buf(char* filename, BYTE* buf){ + FILE* f = fopen(filename, "r"); + if(!f){ + Log("Error: Cannot open %s", filename); + return -1; + } + + fseek(f, 0, SEEK_END); // jump to end of file + long nbytes = ftell(f); // find current offset on file f + fseek(f, 0, SEEK_SET); // jump to beginning of file + + if(nbytes > MAX_REQUEST_SIZE){ + Log("Error: File %s is too big: %d", filename, nbytes); + return -1; + } + + int nread = fread(buf, 1, nbytes, f); + if(nread != nbytes){ + Log("Error: Byte count mismatch with fread: %d, %d", nbytes, nread); + return -1; + } + + fclose(f); + return nbytes; +} -- cgit v1.2.3