From 8021d7c6cb4fc632351d0dcbb607c87916386a55 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Tue, 17 Oct 2023 17:18:19 +0200 Subject: [PATCH] SEND command --- Makefile | 10 ++-- mail.cpp | 24 +++++++++ mail.h | 16 ++---- server.cpp | 123 ++++++++++++++++++++++++++++++++--------------- user_handler.cpp | 12 +++++ user_handler.h | 2 +- 6 files changed, 129 insertions(+), 58 deletions(-) create mode 100644 mail.cpp diff --git a/Makefile b/Makefile index f956835..67d12f6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = g++ ASAN_FLAGS = -fsanitize=address -fno-omit-frame-pointer -Wno-format-security -CFLAGS := -std=c++20 -Wall -lssl -lcrypto -LDFLAGS += -lpthread +CFLAGS := -g -std=c++20 -Wall -lssl -lcrypto +LDFLAGS += -fsanitize=address -lpthread TARGET = client server BUILD_DIR = build @@ -9,7 +9,7 @@ BUILD_DIR = build SOURCES_CLIENT = client.cpp OBJS_CLIENT = $(addprefix $(BUILD_DIR)/,$(SOURCES_CLIENT:.cpp=.o)) -SOURCES_SERVER = server.cpp user.cpp user_handler.cpp +SOURCES_SERVER = server.cpp user.cpp user_handler.cpp mail.cpp OBJS_SERVER = $(addprefix $(BUILD_DIR)/,$(SOURCES_SERVER:.cpp=.o)) all: $(BUILD_DIR) $(TARGET) @@ -18,10 +18,10 @@ $(BUILD_DIR): mkdir -p $(BUILD_DIR) client: $(OBJS_CLIENT) - $(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-client $^ + $(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-client $^ $(LDFLAGS) server: $(OBJS_SERVER) - $(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-server $^ + $(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-server $^ $(LDFLAGS) $(BUILD_DIR)/%.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ diff --git a/mail.cpp b/mail.cpp new file mode 100644 index 0000000..19e3d00 --- /dev/null +++ b/mail.cpp @@ -0,0 +1,24 @@ +#include "mail.h" + +mail::mail(std::string filename, int64_t timestamp, std::string subject) : + filename(filename), + timestamp(timestamp), + subject(subject) +{} + +/* +fs::path mail::getPath() { + if (this->filename.empty()) + return fs::path(); + return fs::path(this->filename.insert(2, "/")); +} +*/ + +void mail::remove() +{ + if (this->filename.empty()) + return; + std::remove((user_handler::getInstance()->getSpoolDir()/"objects"/fs::path(this->filename.insert(2, "/"))).c_str()); + + this->filename = ""; +} \ No newline at end of file diff --git a/mail.h b/mail.h index 48f19e1..7920941 100644 --- a/mail.h +++ b/mail.h @@ -19,6 +19,8 @@ struct mail { std::vector recipients; std::string subject; + mail(std::string filename, int64_t timestamp, std::string subject); + bool operator()(const u_int& id) const { return id == this->id; } @@ -27,17 +29,7 @@ struct mail { return this->timestamp < left.timestamp; } - fs::path getPath() { - if (this->filename.empty()) - return fs::path(); - return fs::path(this->filename.insert(2, "/")); - }; + fs::path getPath() { return this->filename; }; - void remove() { - if (this->filename.empty()) - return; - std::remove((user_handler::getInstance()->getSpoolDir()/"objects"/fs::path(this->filename.insert(2, "/"))).c_str()); - - this->filename = ""; - }; + void remove(); }; \ No newline at end of file diff --git a/server.cpp b/server.cpp index faf3518..9697bc3 100644 --- a/server.cpp +++ b/server.cpp @@ -1,16 +1,19 @@ #include "user.h" #include "user_handler.h" -#include "readline.h" +#include "mail.h" #include #include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -41,11 +44,12 @@ int new_socket = -1; void printUsage(); inline bool isInteger(const std::string & s); -void saveToFile(fs::path object_dir, std::string message); +std::string saveToFile(fs::path object_dir, std::string message); std::string get_sha1(const std::string& p_arg); // from myserver.c void *clientCommunication(void *data); +inline std::string recvToStr(int __fd, size_t __n, int __flags); void signalHandler(int sig); user_handler* user_handler::instancePtr = nullptr; @@ -185,56 +189,61 @@ void *clientCommunication(void *data) } do { - size = recv(*current_socket, buffer, BUF - 1, 0); - if (size == -1) { - if (abortRequested) { - perror("recv error after aborted"); - } else { - perror("recv error"); - } + std::string message; + try { + message = recvToStr(*current_socket, BUF - 1, 0); + } + catch(...) { break; - } + } - if (size == 0) { - printf("Client closed remote socket\n"); // ignore error - break; - } - - // remove ugly debug message, because of the sent newline of client - if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n') { - size -= 2; - } else if (buffer[size - 1] == '\n') { - --size; - } - - buffer[size] = '\0'; - - - - - /* New code here for handling requests */ - - - std::stringstream ss(buffer); + std::stringstream ss(message.c_str()); std::string line; - std::vector message; - + std::vector lines; while (std::getline(ss, line, '\n')) { - message.push_back(line); + lines.push_back(line); } + enum commands cmd; // can't wait for reflections (maybe c++26?) - if (boost::iequals(message.at(0), "SEND")) cmd = SEND; - else if (boost::iequals(message.at(0), "LIST")) cmd = LIST; - else if (boost::iequals(message.at(0), "READ")) cmd = READ; - else if (boost::iequals(message.at(0), "DEL")) cmd = DEL; - else if (boost::iequals(message.at(0), "QUIT")) cmd = QUIT; + if (boost::iequals(lines.at(0), "SEND")) cmd = SEND; + else if (boost::iequals(lines.at(0), "LIST")) cmd = LIST; + else if (boost::iequals(lines.at(0), "READ")) cmd = READ; + else if (boost::iequals(lines.at(0), "DEL")) cmd = DEL; + else if (boost::iequals(lines.at(0), "QUIT")) cmd = QUIT; + + if (cmd == SEND && !boost::equals(lines.back(), ".\n")) { + try { + message.append(recvToStr(*current_socket, BUF - 1, 0)); + std::stringstream ss(message.c_str()); // inefficient to repeat + std::string line; + + lines.clear(); + while (std::getline(ss, line, '\n')) { + lines.push_back(line); + } + } + catch(...) { + break; + } + } switch (cmd) { case SEND: + if (lines.at(3).length() > 80) { + // send error + break; + } + + user_handler::getInstance()->getUser(lines.at(1))->sendMail( + new struct mail(saveToFile(user_handler::getInstance()->getSpoolDir()/"messages", lines.at(4)), std::time(0), lines.at(3)), + {lines.at(2)} + ); + + break; case LIST: case READ: case DEL: @@ -246,6 +255,7 @@ void *clientCommunication(void *data) perror("send answer failed"); return NULL; } + } while (strcmp(buffer, "quit") != 0 && !abortRequested); // closes/frees the descriptor if not already @@ -262,6 +272,38 @@ void *clientCommunication(void *data) return NULL; } +inline std::string recvToStr(int __fd, size_t __n, int __flags) +{ + char buffer[BUF]; + int size; + + size = recv(__fd, buffer, __n, __flags); + if (size == -1) { + if (abortRequested) { + perror("recv error after aborted"); + } else { + perror("recv error"); + } + throw std::exception().what(); + } + + if (size == 0) { + printf("Client closed remote socket\n"); // ignore error + throw std::exception().what(); + } + + // remove ugly debug message, because of the sent newline of client + if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n') { + size -= 2; + } else if (buffer[size - 1] == '\n') { + --size; + } + + buffer[size] = '\0'; + + return buffer; +} + void signalHandler(int sig) { if (sig == SIGINT) { @@ -294,11 +336,12 @@ void signalHandler(int sig) } } -void saveToFile(fs::path object_dir, std::string message) +std::string saveToFile(fs::path object_dir, std::string message) { std::string sha1 = get_sha1(message); std::ofstream ofs(object_dir/sha1); // possible issues with path length or file length limitations ofs << message; + return sha1; } // https://stackoverflow.com/questions/28489153/how-to-portably-compute-a-sha1-hash-in-c diff --git a/user_handler.cpp b/user_handler.cpp index 9c2708c..cc84aa4 100644 --- a/user_handler.cpp +++ b/user_handler.cpp @@ -1,5 +1,7 @@ #include "user_handler.h" +#include "user.h" +#include #include user_handler::user_handler() @@ -9,4 +11,14 @@ user_handler::user_handler() this->users.insert(std::pair(fs::path(entry.path()).replace_extension(), new user(entry))); } } +} + +user* user_handler::getUser(std::string name) +{ + if (this->users.find(name) == this->users.end()) { + this->users[name] = fs::exists(this->spool_dir/"users"/(name+".json")) ? + new user(this->spool_dir/"users"/(name+".json")) : + new user(name, this->spool_dir/"users"); + } + return this->users[name]; } \ No newline at end of file diff --git a/user_handler.h b/user_handler.h index 691edb4..0d856b0 100644 --- a/user_handler.h +++ b/user_handler.h @@ -26,7 +26,7 @@ public: void setSpoolDir(fs::path p) { this->spool_dir = p; }; fs::path getSpoolDir() { return this->spool_dir; }; - user* getUser(std::string name) { return this->users[name]; }; + user* getUser(std::string name); private: