# include <termios.h>
#endif /* Q_OS_WIN */
-#ifdef HAVE_UMASK
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif /* HAVE_UMASK */
-
// ==============================
// Custom Events
// ==============================
// ==============================
// 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");
}
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) {
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("change-userpass")) {
- exit(changeUserPass(Quassel::optionValue("change-userpass")) ?
- EXIT_SUCCESS : EXIT_FAILURE);
+ if (Quassel::isOptionSet("oidentd")) {
+ _oidentdConfigGenerator = new OidentdConfigGenerator(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;
+ });
+
+ 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<UserId>(user);
- instance()->_storage->setCoreState(activeSessions);
+ if (_storage) {
+ QVariantList activeSessions;
+ for (auto &&user : instance()->_sessions.keys())
+ activeSessions << QVariant::fromValue<UserId>(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();
if (activeSessions.count() > 0) {
quInfo() << "Restoring previous core state...";
- foreach(QVariant v, activeSessions) {
+ for(auto &&v : activeSessions) {
UserId user = v.value<UserId>();
- instance()->sessionForUser(user, true);
+ sessionForUser(user, true);
}
}
}
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:
// 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:
// 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:
bool Core::reloadCerts()
{
#ifdef HAVE_SSL
- SslServer *sslServerv4 = qobject_cast<SslServer *>(&instance()->_server);
+ SslServer *sslServerv4 = qobject_cast<SslServer *>(&_server);
bool retv4 = sslServerv4->reloadCerts();
- SslServer *sslServerv6 = qobject_cast<SslServer *>(&instance()->_v6server);
+ SslServer *sslServerv6 = qobject_cast<SslServer *>(&_v6server);
bool retv6 = sslServerv6->reloadCerts();
return retv4 && retv6;
void Core::cacheSysIdent()
{
if (isConfigured()) {
- instance()->_authUserNames = instance()->_storage->getAllAuthUserNames();
+ _authUserNames = _storage->getAllAuthUserNames();
}
}
// 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];
}
-void Core::setupInternalClientSession(InternalPeer *clientPeer)
+void Core::connectInternalPeer(QPointer<InternalPeer> peer)
+{
+ if (_initialized && peer) {
+ setupInternalClientSession(peer);
+ }
+ else {
+ _pendingInternalConnection = peer;
+ }
+}
+
+
+void Core::setupInternalClientSession(QPointer<InternalPeer> clientPeer)
{
if (!_configured) {
stopListening();
}
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;
}