SEND command

This commit is contained in:
Benedikt Galbavy 2023-10-17 17:18:19 +02:00
parent 8557e32690
commit 8021d7c6cb
6 changed files with 129 additions and 58 deletions

View File

@ -1,7 +1,7 @@
CC = g++ CC = g++
ASAN_FLAGS = -fsanitize=address -fno-omit-frame-pointer -Wno-format-security ASAN_FLAGS = -fsanitize=address -fno-omit-frame-pointer -Wno-format-security
CFLAGS := -std=c++20 -Wall -lssl -lcrypto CFLAGS := -g -std=c++20 -Wall -lssl -lcrypto
LDFLAGS += -lpthread LDFLAGS += -fsanitize=address -lpthread
TARGET = client server TARGET = client server
BUILD_DIR = build BUILD_DIR = build
@ -9,7 +9,7 @@ BUILD_DIR = build
SOURCES_CLIENT = client.cpp SOURCES_CLIENT = client.cpp
OBJS_CLIENT = $(addprefix $(BUILD_DIR)/,$(SOURCES_CLIENT:.cpp=.o)) 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)) OBJS_SERVER = $(addprefix $(BUILD_DIR)/,$(SOURCES_SERVER:.cpp=.o))
all: $(BUILD_DIR) $(TARGET) all: $(BUILD_DIR) $(TARGET)
@ -18,10 +18,10 @@ $(BUILD_DIR):
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
client: $(OBJS_CLIENT) client: $(OBJS_CLIENT)
$(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-client $^ $(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-client $^ $(LDFLAGS)
server: $(OBJS_SERVER) server: $(OBJS_SERVER)
$(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-server $^ $(CC) $(CFLAGS) $(ASAN_FLAGS) -o twmailer-server $^ $(LDFLAGS)
$(BUILD_DIR)/%.o: %.cpp $(BUILD_DIR)/%.o: %.cpp
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@

24
mail.cpp Normal file
View File

@ -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 = "";
}

16
mail.h
View File

@ -19,6 +19,8 @@ struct mail {
std::vector<std::string> recipients; std::vector<std::string> recipients;
std::string subject; std::string subject;
mail(std::string filename, int64_t timestamp, std::string subject);
bool operator()(const u_int& id) const { bool operator()(const u_int& id) const {
return id == this->id; return id == this->id;
} }
@ -27,17 +29,7 @@ struct mail {
return this->timestamp < left.timestamp; return this->timestamp < left.timestamp;
} }
fs::path getPath() { fs::path getPath() { return this->filename; };
if (this->filename.empty())
return fs::path();
return fs::path(this->filename.insert(2, "/"));
};
void remove() { void remove();
if (this->filename.empty())
return;
std::remove((user_handler::getInstance()->getSpoolDir()/"objects"/fs::path(this->filename.insert(2, "/"))).c_str());
this->filename = "";
};
}; };

View File

@ -1,16 +1,19 @@
#include "user.h" #include "user.h"
#include "user_handler.h" #include "user_handler.h"
#include "readline.h" #include "mail.h"
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <ctime>
#include <exception>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <locale>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/compute/detail/sha1.hpp> #include <boost/compute/detail/sha1.hpp>
@ -41,11 +44,12 @@ int new_socket = -1;
void printUsage(); void printUsage();
inline bool isInteger(const std::string & s); 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); std::string get_sha1(const std::string& p_arg);
// from myserver.c // from myserver.c
void *clientCommunication(void *data); void *clientCommunication(void *data);
inline std::string recvToStr(int __fd, size_t __n, int __flags);
void signalHandler(int sig); void signalHandler(int sig);
user_handler* user_handler::instancePtr = nullptr; user_handler* user_handler::instancePtr = nullptr;
@ -185,56 +189,61 @@ void *clientCommunication(void *data)
} }
do { do {
size = recv(*current_socket, buffer, BUF - 1, 0); std::string message;
if (size == -1) { try {
if (abortRequested) { message = recvToStr(*current_socket, BUF - 1, 0);
perror("recv error after aborted"); }
} else { catch(...) {
perror("recv error");
}
break; break;
} }
if (size == 0) { std::stringstream ss(message.c_str());
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::string line; std::string line;
std::vector<std::string> message; std::vector<std::string> lines;
while (std::getline(ss, line, '\n')) { while (std::getline(ss, line, '\n')) {
message.push_back(line); lines.push_back(line);
} }
enum commands cmd; enum commands cmd;
// can't wait for reflections (maybe c++26?) // can't wait for reflections (maybe c++26?)
if (boost::iequals(message.at(0), "SEND")) cmd = SEND; if (boost::iequals(lines.at(0), "SEND")) cmd = SEND;
else if (boost::iequals(message.at(0), "LIST")) cmd = LIST; else if (boost::iequals(lines.at(0), "LIST")) cmd = LIST;
else if (boost::iequals(message.at(0), "READ")) cmd = READ; else if (boost::iequals(lines.at(0), "READ")) cmd = READ;
else if (boost::iequals(message.at(0), "DEL")) cmd = DEL; else if (boost::iequals(lines.at(0), "DEL")) cmd = DEL;
else if (boost::iequals(message.at(0), "QUIT")) cmd = QUIT; 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) { switch (cmd) {
case SEND: 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 LIST:
case READ: case READ:
case DEL: case DEL:
@ -246,6 +255,7 @@ void *clientCommunication(void *data)
perror("send answer failed"); perror("send answer failed");
return NULL; return NULL;
} }
} while (strcmp(buffer, "quit") != 0 && !abortRequested); } while (strcmp(buffer, "quit") != 0 && !abortRequested);
// closes/frees the descriptor if not already // closes/frees the descriptor if not already
@ -262,6 +272,38 @@ void *clientCommunication(void *data)
return NULL; 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) void signalHandler(int sig)
{ {
if (sig == SIGINT) { 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::string sha1 = get_sha1(message);
std::ofstream ofs(object_dir/sha1); // possible issues with path length or file length limitations std::ofstream ofs(object_dir/sha1); // possible issues with path length or file length limitations
ofs << message; ofs << message;
return sha1;
} }
// https://stackoverflow.com/questions/28489153/how-to-portably-compute-a-sha1-hash-in-c // https://stackoverflow.com/questions/28489153/how-to-portably-compute-a-sha1-hash-in-c

View File

@ -1,5 +1,7 @@
#include "user_handler.h" #include "user_handler.h"
#include "user.h"
#include <filesystem>
#include <string> #include <string>
user_handler::user_handler() user_handler::user_handler()
@ -9,4 +11,14 @@ user_handler::user_handler()
this->users.insert(std::pair<std::string, user*>(fs::path(entry.path()).replace_extension(), new user(entry))); this->users.insert(std::pair<std::string, user*>(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];
} }

View File

@ -26,7 +26,7 @@ public:
void setSpoolDir(fs::path p) { this->spool_dir = p; }; void setSpoolDir(fs::path p) { this->spool_dir = p; };
fs::path getSpoolDir() { return this->spool_dir; }; fs::path getSpoolDir() { return this->spool_dir; };
user* getUser(std::string name) { return this->users[name]; }; user* getUser(std::string name);
private: private: