X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcore.cpp;h=d596344ca83d560d9c26fca79ac8b105d74c17a0;hp=f793855151eb55b36ee2778f085b05c3c3a22c40;hb=5fc6f7e2d63b45770574260afd6ce535e9548d23;hpb=a49af6149b21e0aaf717fc827c55a2c43a2fd778 diff --git a/src/core/core.cpp b/src/core/core.cpp index f7938551..d596344c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -49,11 +49,6 @@ # include #endif /* Q_OS_WIN */ -#ifdef HAVE_UMASK -# include -# include -#endif /* HAVE_UMASK */ - // ============================== // Custom Events // ============================== @@ -71,52 +66,61 @@ public: // ============================== // Core // ============================== -Core *Core::instanceptr = 0; +Core *Core::_instance{nullptr}; Core *Core::instance() { - if (instanceptr) return instanceptr; - instanceptr = new Core(); - instanceptr->init(); - return instanceptr; + return _instance; } -void Core::destroy() +Core::Core() { - delete instanceptr; - instanceptr = 0; + if (_instance) { + qWarning() << "Recreating core instance!"; + delete _instance; + } + _instance = this; + + // Parent all QObject-derived attributes, so when the Core instance gets moved into another + // thread, they get moved with it + _server.setParent(this); + _v6server.setParent(this); + _storageSyncTimer.setParent(this); } -Core::Core() +Core::~Core() +{ + saveState(); + qDeleteAll(_connectingClients); + qDeleteAll(_sessions); + syncStorage(); + _instance = nullptr; +} + + +bool Core::init() { -#ifdef HAVE_UMASK - umask(S_IRWXG | S_IRWXO); -#endif _startTime = QDateTime::currentDateTime().toUTC(); // for uptime :) - Quassel::loadTranslation(QLocale::system()); + if (Quassel::runMode() == Quassel::RunMode::CoreOnly) { + Quassel::loadTranslation(QLocale::system()); + } // check settings version // so far, we only have 1 CoreSettings s; if (s.version() != 1) { qCritical() << "Invalid core settings version, terminating!"; - exit(EXIT_FAILURE); + QCoreApplication::exit(EXIT_FAILURE); + return false; } // Set up storage and authentication backends registerStorageBackends(); registerAuthenticators(); - connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage())); - _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes -} - - -void Core::init() -{ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); bool config_from_environment = Quassel::isOptionSet("config-from-environment"); @@ -154,13 +158,15 @@ void Core::init() } if (Quassel::isOptionSet("select-backend") || Quassel::isOptionSet("select-authenticator")) { + bool success{true}; if (Quassel::isOptionSet("select-backend")) { - selectBackend(Quassel::optionValue("select-backend")); + success &= selectBackend(Quassel::optionValue("select-backend")); } if (Quassel::isOptionSet("select-authenticator")) { - selectAuthenticator(Quassel::optionValue("select-authenticator")); + success &= selectAuthenticator(Quassel::optionValue("select-authenticator")); } - exit(EXIT_SUCCESS); + QCoreApplication::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); + return success; } if (!_configured) { @@ -170,82 +176,117 @@ void Core::init() if (!_configured) { qWarning() << "Cannot configure from environment"; - exit(EXIT_FAILURE); + QCoreApplication::exit(EXIT_FAILURE); + return false; } - } else { + } + else { if (_registeredStorageBackends.empty()) { quWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting...")); quWarning() << qPrintable(tr("Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n" "Qt library with the sqlite or postgres plugin enabled in order for quasselcore\n" "to work.")); - exit(EXIT_FAILURE); // TODO make this less brutal (especially for mono client -> popup) + QCoreApplication::exit(EXIT_FAILURE); // TODO make this less brutal (especially for mono client -> popup) + return false; } - quWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup."; if (writeError) { qWarning() << "Cannot write quasselcore configuration; probably a permission problem."; - exit(EXIT_FAILURE); + QCoreApplication::exit(EXIT_FAILURE); + return false; } + + quInfo() << "Core is currently not configured! Please connect with a Quassel Client for basic setup."; } } + else { + if (Quassel::isOptionSet("add-user")) { + bool success = createUser(); + QCoreApplication::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); + return success; + } - if (Quassel::isOptionSet("add-user")) { - exit(createUser() ? EXIT_SUCCESS : EXIT_FAILURE); + if (Quassel::isOptionSet("change-userpass")) { + bool success = changeUserPass(Quassel::optionValue("change-userpass")); + QCoreApplication::exit(success ? EXIT_SUCCESS : EXIT_FAILURE); + return success; + } - } + _strictIdentEnabled = Quassel::isOptionSet("strict-ident"); + if (_strictIdentEnabled) { + cacheSysIdent(); + } + + if (Quassel::isOptionSet("oidentd")) { + _oidentdConfigGenerator = new OidentdConfigGenerator(this); + } + + + if (Quassel::isOptionSet("ident-daemon")) { + _identServer = new IdentServer(this); + } + + Quassel::registerReloadHandler([]() { + // Currently, only reloading SSL certificates and the sysident cache is supported + if (Core::instance()) { + Core::instance()->cacheSysIdent(); + Core::instance()->reloadCerts(); + return true; + } + return false; + }); - if (Quassel::isOptionSet("change-userpass")) { - exit(changeUserPass(Quassel::optionValue("change-userpass")) ? - EXIT_SUCCESS : EXIT_FAILURE); + connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage())); + _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes } connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); - if (!startListening()) exit(1); // TODO make this less brutal - _strictIdentEnabled = Quassel::isOptionSet("strict-ident"); - if (_strictIdentEnabled) { - cacheSysIdent(); + if (!startListening()) { + QCoreApplication::exit(EXIT_FAILURE); // TODO make this less brutal + return false; } - if (Quassel::isOptionSet("oidentd")) { - _oidentdConfigGenerator = new OidentdConfigGenerator(this); + if (_configured && !Quassel::isOptionSet("norestore")) { + Core::restoreState(); } -} + _initialized = true; -Core::~Core() -{ - // FIXME do we need more cleanup for handlers? - foreach(CoreAuthHandler *handler, _connectingClients) { - handler->deleteLater(); // disconnect non authed clients + if (_pendingInternalConnection) { + connectInternalPeer(_pendingInternalConnection); + _pendingInternalConnection = {}; } - qDeleteAll(_sessions); -} + return true; +} /*** Session Restore ***/ void Core::saveState() { - QVariantList activeSessions; - foreach(UserId user, instance()->_sessions.keys()) - activeSessions << QVariant::fromValue(user); - instance()->_storage->setCoreState(activeSessions); + if (_storage) { + QVariantList activeSessions; + for (auto &&user : instance()->_sessions.keys()) + activeSessions << QVariant::fromValue(user); + _storage->setCoreState(activeSessions); + } } void Core::restoreState() { - if (!instance()->_configured) { - // quWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!")); + if (!_configured) { + quWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!")); return; } - if (instance()->_sessions.count()) { + if (_sessions.count()) { quWarning() << qPrintable(tr("Calling restoreState() even though active sessions exist!")); return; } + CoreSettings s; /* We don't check, since we are at the first version since switching to Git uint statever = s.coreState().toMap()["CoreStateVersion"].toUInt(); @@ -260,9 +301,9 @@ void Core::restoreState() if (activeSessions.count() > 0) { quInfo() << "Restoring previous core state..."; - foreach(QVariant v, activeSessions) { + for(auto &&v : activeSessions) { UserId user = v.value(); - instance()->sessionForUser(user, true); + sessionForUser(user, true); } } } @@ -370,6 +411,8 @@ bool Core::initStorage(const QString &backend, const QVariantMap &settings, return false; } + connect(storage.get(), SIGNAL(dbUpgradeInProgress(bool)), this, SIGNAL(dbUpgradeInProgress(bool))); + Storage::State storageState = storage->init(settings, environment, loadFromEnvironment); switch (storageState) { case Storage::NeedsSetup: @@ -382,8 +425,9 @@ bool Core::initStorage(const QString &backend, const QVariantMap &settings, // if initialization wasn't successful, we quit to keep from coming up unconfigured case Storage::NotAvailable: qCritical() << "FATAL: Selected storage backend is not available:" << backend; - if (!setup) - exit(EXIT_FAILURE); + if (!setup) { + QCoreApplication::exit(EXIT_FAILURE); + } return false; case Storage::IsReady: @@ -481,8 +525,9 @@ bool Core::initAuthenticator(const QString &backend, const QVariantMap &settings // if initialization wasn't successful, we quit to keep from coming up unconfigured case Authenticator::NotAvailable: qCritical() << "FATAL: Selected auth backend is not available:" << backend; - if (!setup) - exit(EXIT_FAILURE); + if (!setup) { + QCoreApplication::exit(EXIT_FAILURE); + } return false; case Authenticator::IsReady: @@ -511,10 +556,10 @@ bool Core::sslSupported() bool Core::reloadCerts() { #ifdef HAVE_SSL - SslServer *sslServerv4 = qobject_cast(&instance()->_server); + SslServer *sslServerv4 = qobject_cast(&_server); bool retv4 = sslServerv4->reloadCerts(); - SslServer *sslServerv6 = qobject_cast(&instance()->_v6server); + SslServer *sslServerv6 = qobject_cast(&_v6server); bool retv6 = sslServerv6->reloadCerts(); return retv4 && retv6; @@ -528,7 +573,7 @@ bool Core::reloadCerts() void Core::cacheSysIdent() { if (isConfigured()) { - instance()->_authUserNames = instance()->_storage->getAllAuthUserNames(); + _authUserNames = _storage->getAllAuthUserNames(); } } @@ -541,7 +586,7 @@ QString Core::strictSysIdent(UserId user) const // A new user got added since we last pulled our cache from the database. // There's no way to avoid a database hit - we don't even know the authname! - cacheSysIdent(); + instance()->cacheSysIdent(); if (_authUserNames.contains(user)) { return _authUserNames[user]; @@ -625,12 +670,20 @@ bool Core::startListening() if (!success) quError() << qPrintable(tr("Could not open any network interfaces to listen on!")); + if (_identServer) { + _identServer->startListening(); + } + return success; } void Core::stopListening(const QString &reason) { + if (_identServer) { + _identServer->stopListening(reason); + } + bool wasListening = false; if (_server.isListening()) { wasListening = true; @@ -729,7 +782,18 @@ void Core::addClientHelper(RemotePeer *peer, UserId uid) } -void Core::setupInternalClientSession(InternalPeer *clientPeer) +void Core::connectInternalPeer(QPointer peer) +{ + if (_initialized && peer) { + setupInternalClientSession(peer); + } + else { + _pendingInternalConnection = peer; + } +} + + +void Core::setupInternalClientSession(QPointer clientPeer) { if (!_configured) { stopListening(); @@ -742,6 +806,12 @@ void Core::setupInternalClientSession(InternalPeer *clientPeer) } else { quWarning() << "Core::setupInternalClientSession(): You're trying to run monolithic Quassel with an unusable Backend! Go fix it!"; + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + if (!clientPeer) { + quWarning() << "Client peer went away, not starting a session"; return; }