thread safety

This commit is contained in:
Benedikt Galbavy 2023-11-15 18:06:42 +01:00
parent 97fc3605ce
commit 90d338f0a0
7 changed files with 47 additions and 16 deletions

View File

@ -1,17 +1,20 @@
#include "mail.h"
#include <mutex>
mail::mail(std::string filename, std::string subject) :
filename(filename),
timestamp(std::time(NULL)),
subject(subject),
deleted(false)
deleted(false),
m_file()
{}
mail::mail(std::string filename, int64_t timestamp, std::string subject) :
filename(filename),
timestamp(timestamp),
subject(subject),
deleted(false)
deleted(false),
m_file()
{}
/*

View File

@ -37,4 +37,6 @@ struct mail {
json mailToJson();
void remove();
std::mutex m_file;
};

View File

@ -14,6 +14,7 @@
#include <cctype>
#include <algorithm>
#include <future>
#include <mutex>
#include <pthread.h>
#include <string_view>
#include <sstream>
@ -43,10 +44,12 @@ enum commands {
namespace fs = std::filesystem;
int abortRequested = 0;
bool abortRequested = false;
int create_socket = -1;
int new_socket = -1;
std::vector<std::thread> threads;
void printUsage();
inline bool isInteger(const std::string & s);
bool ichar_equals(char a, char b);
@ -166,8 +169,7 @@ int main (int argc, char* argv[])
inet_ntoa(cliaddress.sin_addr),
ntohs(cliaddress.sin_port));
// clientCommunication(&new_socket); // returnValue can be ignored
std::thread th(clientCommunication, new_socket);
th.detach();
threads.emplace_back(clientCommunication, new_socket);
new_socket = -1;
}
@ -305,7 +307,7 @@ void signalHandler(int sig)
{
if (sig == SIGINT) {
printf("abort Requested... "); // ignore error
abortRequested = 1;
abortRequested = true;
if (new_socket != -1)
{
if (shutdown(new_socket, SHUT_RDWR) == -1)
@ -363,6 +365,10 @@ std::string getSha1(const std::string& str)
inline void exiting()
{
for (auto& thread : threads) {
thread.join();
}
user_handler::getInstance().saveAll();
printf("Saving... \n");
}
@ -420,13 +426,14 @@ std::string cmdREAD(std::vector<std::string>& received)
mail->deleted)
return "ERR\n";
try {
/*try */{
std::string path_str = user_handler::getInstance().getSpoolDir()/"messages"/mail->filename;
std::lock_guard<std::mutex> guard(mail->m_file);
response.append(read_file(path_str)).append("\n");
}
catch (...) { // TODO: more specific error handling - then again, it will respond with ERR either way
/*catch (...) { // TODO: more specific error handling - then again, it will respond with ERR either way
return "ERR\n";
}
}*/
return response;
}

View File

@ -4,6 +4,7 @@
#include <cstdio>
#include <fstream>
#include <mutex>
#include <ostream>
#include <string>
#include <vector>
@ -11,7 +12,7 @@
using json = nlohmann::json;
user::user(fs::path user_data_json)
user::user(fs::path user_data_json) : m()
{
std::ifstream ifs(user_data_json);
json user_data = json::parse(ifs);
@ -50,7 +51,8 @@ user::user(fs::path user_data_json)
}
user::user(std::string name, fs::path user_dir)
: name(name)
: name(name),
m()
{
json user;
user["mails"]["sent"] = json::object();
@ -69,6 +71,8 @@ user::~user() {
void user::addMail(mail* mail)
{
std::lock_guard<std::mutex> guard(this->m);
mail->id = this->inbox.size();
this->inbox.insert(mail);
@ -77,6 +81,8 @@ void user::addMail(mail* mail)
void user::sendMail(mail* mail, std::vector<std::string> recipients)
{
std::lock_guard<std::mutex> guard(this->m);
std::vector<user*> users;
for ( auto& name : recipients) {
// TODO: error handling for non existing user
@ -104,6 +110,8 @@ mail* user::getMail(u_int id)
bool user::delMail(u_int id)
{
std::lock_guard<std::mutex> guard(this->m);
maillist::iterator it = std::find_if(this->inbox.begin(), this->inbox.end(), [id](auto& i){ return (*i)(id); });
bool success = true;

View File

@ -2,6 +2,7 @@
#include "mail.h"
#include <mutex>
#include <string>
#include <set>
#include <vector>
@ -37,4 +38,6 @@ private:
std::string name;
maillist inbox;
maillist sent;
std::mutex m;
};

View File

@ -4,7 +4,7 @@
#include <filesystem>
#include <string>
user_handler::user_handler()
user_handler::user_handler() : m_user()
{
for (const auto& entry : fs::directory_iterator()) {
if (entry.path().extension() == ".json") {
@ -21,26 +21,31 @@ user_handler::~user_handler()
user* user_handler::getUser(std::string name)
{
if (this->users.find(name) == this->users.end()) {
this->m_user.lock(); // avoid race condition of two threads creating the same user
if (!fs::exists(this->spool_dir/"users"/(name+".json")))
return nullptr;
this->users[name] = new user(this->spool_dir/"users"/(name+".json"));
this->users.insert({name, new user(this->spool_dir/"users"/(name+".json"))});
this->m_user.unlock();
}
return this->users[name];
return (*this->users.find(name)).second;
}
user* user_handler::getOrCreateUser(std::string name)
{
if (this->users.find(name) == this->users.end()) {
this->users[name] = fs::exists(this->spool_dir/"users"/(name+".json")) ?
this->m_user.lock();
this->users.insert({name, fs::exists(this->spool_dir/"users"/(name+".json")) ?
new user(this->spool_dir/"users"/(name+".json")) :
new user(name, this->spool_dir/"users");
new user(name, this->spool_dir/"users")});
this->m_user.unlock();
}
return this->users[name];
}
void user_handler::saveAll()
{
// will only be called from main
for ( auto& user : this->users ) {
user.second->saveToFile();
}

View File

@ -2,6 +2,7 @@
#include <filesystem>
#include <map>
#include <mutex>
#include <string>
class user;
@ -37,5 +38,7 @@ protected:
fs::path spool_dir;
std::map<std::string, user*> users;
std::mutex m_user;
};