hopefully fix server crash bug with mutex in user and task release and duplicate

This commit is contained in:
Dario 2019-10-10 12:27:18 +02:00
parent ca2cdf80a6
commit 1840f08ca9
10 changed files with 88 additions and 173 deletions

View File

@ -23,11 +23,14 @@ KeyPair::KeyPair()
KeyPair::~KeyPair()
{
printf("[KeyPair::~KeyPair] privkey: %d, soduium privkey: %d \n", mPrivateKey, mSodiumSecret);
if (mPrivateKey) {
delete mPrivateKey;
mPrivateKey = nullptr;
}
if (mSodiumSecret) {
delete mSodiumSecret;
mSodiumSecret = nullptr;
}
}

View File

@ -89,7 +89,7 @@ int Gradido_LoginServer::main(const std::vector<std::string>& args)
ServerConfig::initEMailAccount(config());
// start cpu scheduler
unsigned int worker_count = Poco::Environment::processorCount() * 2;
uint8_t worker_count = Poco::Environment::processorCount() * 2;
ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker");
ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker");

View File

@ -49,7 +49,10 @@ void DashboardPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << "<div class=\"grd_container\">\n";
responseStream << "\t<h1>Willkommen ";
#line 28 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\dashboard.cpsp"
responseStream << ( mSession->getUser()->getName() );
responseStream << ( mSession->getUser()->getFirstName() );
responseStream << "&nbsp;";
#line 28 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\dashboard.cpsp"
responseStream << ( mSession->getUser()->getLastName() );
responseStream << "</h1>\n";
responseStream << "\t";
#line 29 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\dashboard.cpsp"
@ -70,6 +73,14 @@ void DashboardPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::N
responseStream << "\t</form>\n";
responseStream << "\t";
#line 38 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\dashboard.cpsp"
} else if(mSession->getSessionState() == SESSION_STATE_EMAIL_VERIFICATION_WRITTEN) { responseStream << "\n";
responseStream << "\t<p>Hast du schon eine E-Mail mit einem Verification Code erhalten? Wenn ja kannst du ihn hier hinein kopieren:</p>\n";
responseStream << "\t<form method=\"GET\" action=\"checkEmail\">\n";
responseStream << "\t\t<input type=\"number\" name=\"email-verification-code\">\n";
responseStream << "\t\t<input class=\"grd_bn_succeed\" type=\"submit\" value=\"Überprüfe Code\">\n";
responseStream << "\t</form>\n";
responseStream << "\t";
#line 44 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\dashboard.cpsp"
} responseStream << "\n";
responseStream << "\t<a class=\"grd_bn\" href=\"logout\">Abmelden</a>\n";
responseStream << "\t<a class=\"grd_bn\" href=\"user_delete\">Account l&ouml;schen</a>\n";

View File

@ -1,138 +0,0 @@
#include "EmailOptInPage.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/DeflatingStream.h"
#line 4 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
#include "../SingletonManager/SessionManager.h"
#include "Poco/Net/HTTPCookie.h"
void EmailOptInPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
bool _compressResponse(request.hasToken("Accept-Encoding", "gzip"));
if (_compressResponse) response.set("Content-Encoding", "gzip");
Poco::Net::HTMLForm form(request, request.stream());
#line 8 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
auto session = SessionManager::getInstance()->getNewSession();
bool userReturned = false;
if(!form.empty()) {
userReturned = session->createUser(
form.get("register-name"),
form.get("register-email"),
form.get("register-password")
);
if(userReturned) {
auto cookie_id = session->getHandle();
auto user_host = request.clientAddress().toString();
printf("cookie: %d, user_host: %s\n", cookie_id, user_host.data());
response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id)));
}
}
std::ostream& _responseStream = response.send();
Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1);
std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;
responseStream << "\n";
responseStream << "<!DOCTYPE html>\n";
responseStream << "<html>\n";
responseStream << "<head>\n";
responseStream << "<meta charset=\"UTF-8\">\n";
responseStream << "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
responseStream << "<title>Gradido Login Server: Email OptIn</title>\n";
responseStream << "<!--<link rel=\"stylesheet\" type=\"text/css\" href=\"css/styles.min.css\">-->\n";
responseStream << "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gradido2.dario-rekowski.de/css/styles.css\">\n";
responseStream << "<style type=\"text/css\" >\n";
responseStream << "input:not([type='radio']) {\n";
responseStream << "\twidth:200px;\n";
responseStream << "}\n";
responseStream << "label:not(.grd_radio_label) {\n";
responseStream << "\twidth:80px;\n";
responseStream << "\tdisplay:inline-block;\n";
responseStream << "}\n";
responseStream << "</style>\n";
responseStream << "</head>\n";
responseStream << "<body>\n";
responseStream << "<div class=\"grd_container\">\n";
responseStream << "\t<h1>Einen neuen Account anlegen</h1>\n";
responseStream << "\t";
#line 46 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
if(!form.empty() && userReturned) { responseStream << "\n";
responseStream << "\t\t<div class=\"grd_text-max-width\">\n";
responseStream << "\t\t\t<div class=\"grd_text\">\n";
responseStream << "\t\t\t\tSchreibe dir den Merkspruch auf und packe ihn gut weg. Du brauchst ihn um deine Adresse wiederherzustellen. Wenn du ihn verlierst, sind auch deine Gradidos verloren.\n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t\t\t<div class=\"grd_textarea\">\n";
responseStream << "\t\t\t\t";
#line 52 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
responseStream << ( session->getPassphrase() );
responseStream << "\n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t\t</div>\n";
responseStream << "\t";
#line 55 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
} else { responseStream << "\n";
responseStream << "\t<form method=\"POST\">\n";
responseStream << "\t\n";
responseStream << "\t\t";
#line 58 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
if(!form.empty() && !userReturned) { responseStream << "\n";
responseStream << "\t\t\t";
#line 59 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
responseStream << ( session->getErrorsHtml() );
responseStream << "\n";
responseStream << "\t\t";
#line 60 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
} responseStream << "\n";
responseStream << "\t\t<fieldset class=\"grd_container_small\">\n";
responseStream << "\t\t\t<legend>Account anlegen</legend>\n";
responseStream << "\t\t\t<p>Bitte gebe deine Daten um einen Account anzulegen</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<label for=\"register-name\">Vorname</label>\n";
responseStream << "\t\t\t\t<input id=\"register-name\" type=\"text\" name=\"register-name\" value=\"";
#line 66 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
responseStream << ( !form.empty() ? form.get("register-name") : "" );
responseStream << "\"/>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<label for=\"register-email\">E-Mail</label>\n";
responseStream << "\t\t\t\t<input id=\"register-email\" type=\"email\" name=\"register-email\" value=\"";
#line 70 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
responseStream << ( !form.empty() ? form.get("register-email") : "" );
responseStream << "\"/>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<label for=\"register-password\">Passwort</label>\n";
responseStream << "\t\t\t\t<input id=\"register-password\" type=\"password\" name=\"register-password\"/>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p>Hast du schonmal ein Gradido Konto besessen?</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<input id=\"register-key-new-yes\" type=\"radio\" name=\"register-key\" value=\"yes\" checked/>\n";
responseStream << "\t\t\t\t<label class=\"grd_radio_label\" for=\"register-key-new-yes\">Nein, bitte ein neues erstellen!</label>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<input id=\"register-key-new-no\" type=\"radio\" name=\"register-key\" value=\"no\"/>\n";
responseStream << "\t\t\t\t<label class=\"grd_radio_label\" for=\"register-key-new-no\">Ja, bitte wiederherstellen!</label>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<textarea style=\"width:100%;height:100px\" name=\"register-key-existing\">";
#line 85 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
responseStream << ( !form.empty() ? form.get("register-key-existing") : "" );
responseStream << "</textarea>\n";
responseStream << "\t\t</fieldset>\n";
responseStream << "\t\t<input class=\"grd_bn_succeed\" type=\"submit\" name=\"submit\" value=\"Anmelden\">\n";
responseStream << "\t\t\n";
responseStream << "\t</form>\n";
responseStream << "\t";
#line 90 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\emailOptIn.cpsp"
} responseStream << "\n";
responseStream << "</div>\n";
responseStream << "</body>\n";
responseStream << "</html>\n";
if (_compressResponse) _gzipStream.close();
}

View File

@ -1,15 +0,0 @@
#ifndef EmailOptInPage_INCLUDED
#define EmailOptInPage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
class EmailOptInPage: public Poco::Net::HTTPRequestHandler
{
public:
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // EmailOptInPage_INCLUDED

View File

@ -214,7 +214,7 @@ bool Session::createUser(const std::string& first_name, const std::string& last_
message->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, email));
message->setSubject("Gradido: E-Mail Verification");
std::stringstream ss;
ss << "Hallo " << name << "," << std::endl << std::endl;
ss << "Hallo " << first_name << " " << last_name << "," << std::endl << std::endl;
ss << "Du oder jemand anderes hat sich soeben mit dieser E-Mail Adresse bei Gradido registriert. " << std::endl;
ss << "Wenn du es warst, klicke bitte auf den Link: https://gradido2.dario-rekowski.de/account/checkEmail/" << mEmailVerificationCode << std::endl;
ss << "oder kopiere den Code: " << mEmailVerificationCode << " selbst dort hinein." << std::endl << std::endl;
@ -356,10 +356,25 @@ void Session::detectSessionState()
return;
}
if (!mSessionUser->isEmailChecked()) {
if (mEmailVerificationCode == 0)
updateState(SESSION_STATE_USER_WRITTEN);
else
updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN);
if (mEmailVerificationCode == 0) {
auto dbConnection = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement select(dbConnection);
auto user_id = mSessionUser->getDBId();
select << "SELECT verification_code from email_opt_in where user_id = ?",
into(mEmailVerificationCode), use(user_id);
try {
if (select.execute() == 1) {
updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN);
return;
}
}
catch (Poco::Exception& ex) {
printf("[Session::detectSessionState] mysql exception: %s\n", ex.displayText().data());
}
}
updateState(SESSION_STATE_USER_WRITTEN);
return;
}
@ -378,7 +393,7 @@ void Session::detectSessionState()
}
}
catch (Poco::Exception& exc) {
printf("mysql exception: %s\n", exc.displayText().data());
printf("[Session::detectSessionState] 2 mysql exception: %s\n", exc.displayText().data());
}
if (mPassphrase != "") {
updateState(SESSION_STATE_PASSPHRASE_GENERATED);
@ -425,10 +440,10 @@ bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode)
return false;
}*/
Poco::Data::Statement select(dbConnection);
std::string email, name;
std::string email, first_name, last_name;
select.reset(dbConnection);
select << "SELECT email, name FROM users where id = (SELECT user_id FROM email_opt_in WHERE verification_code=?)",
into(email), into(name), use(emailVerificationCode);
select << "SELECT email, first_name, last_name FROM users where id = (SELECT user_id FROM email_opt_in WHERE verification_code=?)",
into(email), into(first_name), into(last_name), use(emailVerificationCode);
try {
size_t rowCount = select.execute();
if (rowCount != 1) {
@ -440,7 +455,7 @@ bool Session::loadFromEmailVerificationCode(Poco::UInt64 emailVerificationCode)
return false;
}
mSessionUser = new User(email.data(), name.data());
mSessionUser = new User(email.data(), first_name.data(), last_name.data());
mSessionUser->loadEntryDBId(ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER));
mEmailVerificationCode = emailVerificationCode;
updateState(SESSION_STATE_EMAIL_VERIFICATION_WRITTEN);

View File

@ -64,7 +64,9 @@ public:
Poco::Net::HTTPCookie getLoginCookie();
inline Poco::AutoPtr<User> getUser() { return mSessionUser; }
Poco::AutoPtr<User> getUser() {
return mSessionUser;
}
inline int getHandle() { return mHandleId; }

View File

@ -32,6 +32,9 @@ int UserCreateCryptoKey::run()
mUser->setPwdHashed(pwdHashed);
printf("crypto key created\n");
setTaskFinished();
// must poke cpu scheduler manually because another task is waiting for this task, but in the other scheduler
ServerConfig::g_CPUScheduler->checkPendingTasks();
return 0;
}
@ -145,13 +148,14 @@ int UserWriteKeysIntoDB::run()
// *******************************************************************************
// new user
User::User(const char* email, const char* first_name, const char* last_name)
: mDBId(0), mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr)
: mDBId(0), mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr),
mReferenceCount(1)
{
}
// load from db
User::User(const char* email)
: mDBId(0), mEmail(email), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr)
: mDBId(0), mEmail(email), mPasswordHashed(0), mEmailChecked(false), mCryptoKey(nullptr), mReferenceCount(1)
{
//crypto_shorthash(mPasswordHashed, (const unsigned char*)password, strlen(password), *ServerConfig::g_ServerCryptoKey);
//memset(mPasswordHashed, 0, crypto_shorthash_BYTES);
@ -188,7 +192,7 @@ User::User(const char* email)
User::~User()
{
printf("[User::~User]\n");
// printf("[User::~User]\n");
if (mCryptoKey) {
delete mCryptoKey;
mCryptoKey = nullptr;
@ -292,8 +296,13 @@ bool User::deleteFromDB()
use(mDBId), use(mDBId), use(mDBId);
*/
for (int i = 0; i < 3; i++) {
if (i > 0) deleteFromDB.reset(session);
deleteFromDB << "DELETE from " << tables[i] << " where id = ?", use(mDBId);
if (i > 0) {
deleteFromDB.reset(session);
deleteFromDB << "DELETE from " << tables[i] << " where user_id = ?", use(mDBId);
}
else {
deleteFromDB << "DELETE from " << tables[i] << " where id = ?", use(mDBId);
}
try {
auto result = deleteFromDB.execute();
@ -312,15 +321,23 @@ bool User::deleteFromDB()
void User::duplicate()
{
mWorkingMutex.lock();
mReferenceCount++;
//printf("[User::duplicate] new value: %d\n", mReferenceCount);
mWorkingMutex.unlock();
}
void User::release()
{
mWorkingMutex.lock();
mReferenceCount--;
//printf("[User::release] new value: %d\n", mReferenceCount);
if (0 == mReferenceCount) {
mWorkingMutex.unlock();
delete this;
return;
}
mWorkingMutex.unlock();
}
@ -368,6 +385,7 @@ bool User::generateKeys(bool savePrivkey, const std::string& passphrase, Session
{
Profiler timeUsed;
duplicate();
UniLib::controller::TaskPtr generateKeysTask(new UserGenerateKeys(this, passphrase));
//generateKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_GENERATED, session));
//generateKeysTask->scheduleTask(generateKeysTask);
@ -386,6 +404,7 @@ bool User::generateKeys(bool savePrivkey, const std::string& passphrase, Session
return false;
}
duplicate();
UniLib::controller::TaskPtr saveKeysTask(new UserWriteKeysIntoDB(generateKeysTask, this, savePrivkey));
saveKeysTask->setFinishCommand(new SessionStateUpdateCommand(SESSION_STATE_KEY_PAIR_WRITTEN, session));
saveKeysTask->scheduleTask(saveKeysTask);

View File

@ -17,6 +17,8 @@ namespace UniLib {
Task::~Task()
{
mWorkingMutex.lock();
//printf("[Task::~Task]\n");
if (mParentTaskPtrArraySize) {
delete[] mParentTaskPtrArray;
}
@ -24,9 +26,11 @@ namespace UniLib {
delete mFinishCommand;
}
mParentTaskPtrArraySize = 0;
mWorkingMutex.lock();
mDeleted = true;
//printf("[Task::~Task] finished\n");
mWorkingMutex.unlock();
}
bool Task::isAllParentsReady()
@ -55,15 +59,23 @@ namespace UniLib {
void Task::duplicate()
{
lock();
mReferenceCount++;
//printf("[Task::duplicate] new value: %d\n", mReferenceCount);
unlock();
}
void Task::release()
{
lock();
mReferenceCount--;
//printf("[Task::release] new value: %d\n", mReferenceCount);
if (0 == mReferenceCount) {
unlock();
delete this;
return;
}
unlock();
}

View File

@ -25,7 +25,7 @@
</head>
<body>
<div class="grd_container">
<h1>Willkommen <%= mSession->getUser()->getName() %></h1>
<h1>Willkommen <%= mSession->getUser()->getFirstName() %>&nbsp;<%= mSession->getUser()->getLastName() %></h1>
<%= mSession->getErrorsHtml() %>
<h3>Status</h3>
<p><%= mSession->getSessionStateString() %></p>
@ -35,6 +35,12 @@
<input type="number" name="email-verification-code">
<input class="grd_bn_succeed" type="submit" value="Überprüfe Code">
</form>
<% } else if(mSession->getSessionState() == SESSION_STATE_EMAIL_VERIFICATION_WRITTEN) { %>
<p>Hast du schon eine E-Mail mit einem Verification Code erhalten? Wenn ja kannst du ihn hier hinein kopieren:</p>
<form method="GET" action="checkEmail">
<input type="number" name="email-verification-code">
<input class="grd_bn_succeed" type="submit" value="Überprüfe Code">
</form>
<% } %>
<a class="grd_bn" href="logout">Abmelden</a>
<a class="grd_bn" href="user_delete">Account l&ouml;schen</a>