00001 #include <QCoreApplication>
00002 #include <QUrl>
00003 #include <QDir>
00004 #include <QFileInfo>
00005 #include <QDebug>
00006 #include <QMutex>
00007 #include <QWaitCondition>
00008 #include <QNetworkInterface>
00009 #include <QAbstractSocket>
00010 #include <QHostAddress>
00011 #include <QNetworkInterface>
00012 #include <QNetworkAddressEntry>
00013 #include <QLocale>
00014
00015 #include <cmath>
00016
00017 #include <queue>
00018 #include <algorithm>
00019 using namespace std;
00020
00021 #ifdef USING_MINGW
00022 #include <winsock2.h>
00023 #include <unistd.h>
00024 #else
00025 #include <locale.h>
00026 #endif
00027
00028 #include "compat.h"
00029 #include "mythconfig.h"
00030 #include "mythdownloadmanager.h"
00031 #include "mythsocketthread.h"
00032 #include "mythcorecontext.h"
00033 #include "mythsocket.h"
00034 #include "mythsystem.h"
00035 #include "mthreadpool.h"
00036 #include "exitcodes.h"
00037 #include "mythlogging.h"
00038 #include "mythversion.h"
00039 #include "logging.h"
00040 #include "mthread.h"
00041 #include "serverpool.h"
00042
00043 #define LOC QString("MythCoreContext: ")
00044
00045 MythCoreContext *gCoreContext = NULL;
00046 QMutex *avcodeclock = new QMutex(QMutex::Recursive);
00047
00048 class MythCoreContextPrivate : public QObject
00049 {
00050 public:
00051 MythCoreContextPrivate(MythCoreContext *lparent, QString binversion,
00052 QObject *guicontext);
00053 ~MythCoreContextPrivate();
00054
00055 bool WaitForWOL(int timeout_ms = INT_MAX);
00056
00057 public:
00058 MythCoreContext *m_parent;
00059 QObject *m_GUIcontext;
00060 QObject *m_GUIobject;
00061 QString m_appBinaryVersion;
00062
00063 QMutex m_localHostLock;
00064 QString m_localHostname;
00065 QMutex m_masterHostLock;
00066 QString m_masterHostname;
00067
00068 QMutex m_sockLock;
00069 MythSocket *m_serverSock;
00070 MythSocket *m_eventSock;
00071
00072 QMutex m_WOLInProgressLock;
00073 QWaitCondition m_WOLInProgressWaitCondition;
00074 bool m_WOLInProgress;
00075
00076 bool m_backend;
00077
00078 MythDB *m_database;
00079
00080 QThread *m_UIThread;
00081
00082 MythLocale *m_locale;
00083 QString language;
00084
00085 MythScheduler *m_scheduler;
00086
00087 bool m_blockingClient;
00088 };
00089
00090 MythCoreContextPrivate::MythCoreContextPrivate(MythCoreContext *lparent,
00091 QString binversion,
00092 QObject *guicontext)
00093 : m_parent(lparent),
00094 m_GUIcontext(guicontext), m_GUIobject(NULL),
00095 m_appBinaryVersion(binversion),
00096 m_localHostname(QString::null),
00097 m_masterHostname(QString::null),
00098 m_sockLock(QMutex::NonRecursive),
00099 m_serverSock(NULL), m_eventSock(NULL),
00100 m_WOLInProgress(false),
00101 m_backend(false),
00102 m_database(GetMythDB()),
00103 m_UIThread(QThread::currentThread()),
00104 m_locale(NULL),
00105 m_scheduler(NULL),
00106 m_blockingClient(false)
00107 {
00108 MThread::ThreadSetup("CoreContext");
00109 srandom(QDateTime::currentDateTime().toTime_t() ^
00110 QTime::currentTime().msec());
00111 }
00112
00113 MythCoreContextPrivate::~MythCoreContextPrivate()
00114 {
00115 MThreadPool::StopAllPools();
00116 ShutdownRRT();
00117
00118 QMutexLocker locker(&m_sockLock);
00119 if (m_serverSock)
00120 {
00121 m_serverSock->DownRef();
00122 m_serverSock = NULL;
00123 }
00124 if (m_eventSock)
00125 {
00126 m_eventSock->DownRef();
00127 m_eventSock = NULL;
00128 }
00129
00130 delete m_locale;
00131
00132 MThreadPool::ShutdownAllPools();
00133
00134 ShutdownMythSystem();
00135
00136 ShutdownMythDownloadManager();
00137
00138
00139
00140 #if 0
00141 logStop();
00142 #endif
00143
00144 MThread::Cleanup();
00145
00146 GetMythDB()->GetDBManager()->CloseDatabases();
00147
00148 if (m_database) {
00149 DestroyMythDB();
00150 m_database = NULL;
00151 }
00152
00153 loggingDeregisterThread();
00154 }
00155
00159 bool MythCoreContextPrivate::WaitForWOL(int timeout_in_ms)
00160 {
00161 int timeout_remaining = timeout_in_ms;
00162 while (m_WOLInProgress && (timeout_remaining > 0))
00163 {
00164 LOG(VB_GENERAL, LOG_INFO, LOC + "Wake-On-LAN in progress, waiting...");
00165
00166 int max_wait = min(1000, timeout_remaining);
00167 m_WOLInProgressWaitCondition.wait(
00168 &m_WOLInProgressLock, max_wait);
00169 timeout_remaining -= max_wait;
00170 }
00171
00172 return !m_WOLInProgress;
00173 }
00174
00175 MythCoreContext::MythCoreContext(const QString &binversion,
00176 QObject *guiContext)
00177 : d(NULL)
00178 {
00179 d = new MythCoreContextPrivate(this, binversion, guiContext);
00180 }
00181
00182 bool MythCoreContext::Init(void)
00183 {
00184 if (!d)
00185 {
00186 LOG(VB_GENERAL, LOG_EMERG, LOC + "Init() Out-of-memory");
00187 return false;
00188 }
00189
00190 if (d->m_appBinaryVersion != MYTH_BINARY_VERSION)
00191 {
00192 LOG(VB_GENERAL, LOG_CRIT,
00193 QString("Application binary version (%1) does not "
00194 "match libraries (%2)")
00195 .arg(d->m_appBinaryVersion) .arg(MYTH_BINARY_VERSION));
00196
00197 QString warning = QObject::tr(
00198 "This application is not compatible "
00199 "with the installed MythTV libraries. "
00200 "Please recompile after a make distclean");
00201 LOG(VB_GENERAL, LOG_WARNING, warning);
00202
00203 return false;
00204 }
00205
00206 #ifndef _WIN32
00207 QString lang_variables("");
00208 QString lc_value = setlocale(LC_CTYPE, NULL);
00209 if (lc_value.isEmpty())
00210 {
00211
00212
00213 lc_value = getenv("LC_ALL");
00214 if (lc_value.isEmpty())
00215 lc_value = getenv("LC_CTYPE");
00216 }
00217 if (!lc_value.contains("UTF-8", Qt::CaseInsensitive))
00218 lang_variables.append("LC_ALL or LC_CTYPE");
00219 lc_value = getenv("LANG");
00220 if (!lc_value.contains("UTF-8", Qt::CaseInsensitive))
00221 {
00222 if (!lang_variables.isEmpty())
00223 lang_variables.append(", and ");
00224 lang_variables.append("LANG");
00225 }
00226 LOG(VB_GENERAL, LOG_INFO, QString("Assumed character encoding: %1")
00227 .arg(lc_value));
00228 if (!lang_variables.isEmpty())
00229 LOG(VB_GENERAL, LOG_WARNING, QString("This application expects to "
00230 "be running a locale that specifies a UTF-8 codeset, and many "
00231 "features may behave improperly with your current language "
00232 "settings. Please set the %1 variable(s) in the environment "
00233 "in which this program is executed to include a UTF-8 codeset "
00234 "(such as 'en_US.UTF-8').").arg(lang_variables));
00235 #endif
00236
00237 return true;
00238 }
00239
00240 MythCoreContext::~MythCoreContext()
00241 {
00242 delete d;
00243 d = NULL;
00244 }
00245
00246 bool MythCoreContext::SetupCommandSocket(MythSocket *serverSock,
00247 const QString &announcement,
00248 uint timeout_in_ms,
00249 bool &proto_mismatch)
00250 {
00251 proto_mismatch = false;
00252
00253 #ifndef IGNORE_PROTO_VER_MISMATCH
00254 if (!CheckProtoVersion(serverSock, timeout_in_ms, true))
00255 {
00256 proto_mismatch = true;
00257 return false;
00258 }
00259 #endif
00260
00261 QStringList strlist(announcement);
00262
00263 if (!serverSock->writeStringList(strlist))
00264 {
00265 LOG(VB_GENERAL, LOG_ERR, LOC + "Connecting server socket to "
00266 "master backend, socket write failed");
00267 return false;
00268 }
00269
00270 if (!serverSock->readStringList(strlist, true) || strlist.empty() ||
00271 (strlist[0] == "ERROR"))
00272 {
00273 if (!strlist.empty())
00274 LOG(VB_GENERAL, LOG_ERR, LOC + "Problem connecting "
00275 "server socket to master backend");
00276 else
00277 LOG(VB_GENERAL, LOG_ERR, LOC + "Timeout connecting "
00278 "server socket to master backend");
00279 return false;
00280 }
00281
00282 return true;
00283 }
00284
00285
00286
00287 bool MythCoreContext::ConnectToMasterServer(bool blockingClient,
00288 bool openEventSocket)
00289 {
00290 if (IsMasterBackend())
00291 {
00292
00293
00294 LOG(VB_GENERAL, LOG_ERR, "ERROR: Master backend tried to connect back "
00295 "to itself!");
00296 return false;
00297 }
00298
00299 QString server = GetSetting("MasterServerIP", "localhost");
00300 int port = GetNumSetting("MasterServerPort", 6543);
00301 bool proto_mismatch = false;
00302
00303 if (!d->m_serverSock)
00304 {
00305 QString ann = QString("ANN %1 %2 %3")
00306 .arg(blockingClient ? "Playback" : "Monitor")
00307 .arg(d->m_localHostname).arg(false);
00308 d->m_serverSock = ConnectCommandSocket(
00309 server, port, ann, &proto_mismatch);
00310 }
00311
00312 if (!d->m_serverSock)
00313 return false;
00314
00315 d->m_blockingClient = blockingClient;
00316
00317 if (!openEventSocket)
00318 return true;
00319
00320 if (!IsBackend() && !d->m_eventSock)
00321 d->m_eventSock = ConnectEventSocket(server, port);
00322
00323 if (!IsBackend() && !d->m_eventSock)
00324 {
00325 d->m_serverSock->DownRef();
00326 d->m_serverSock = NULL;
00327
00328 QCoreApplication::postEvent(
00329 d->m_GUIcontext, new MythEvent("CONNECTION_FAILURE"));
00330
00331 return false;
00332 }
00333
00334 return true;
00335 }
00336
00337 MythSocket *MythCoreContext::ConnectCommandSocket(
00338 const QString &hostname, int port, const QString &announce,
00339 bool *p_proto_mismatch, bool gui, int maxConnTry, int setup_timeout)
00340 {
00341 MythSocket *serverSock = NULL;
00342
00343 {
00344 QMutexLocker locker(&d->m_WOLInProgressLock);
00345 d->WaitForWOL();
00346 }
00347
00348 QString WOLcmd = GetSetting("WOLbackendCommand", "");
00349
00350 if (maxConnTry < 1)
00351 maxConnTry = max(GetNumSetting("BackendConnectRetry", 1), 1);
00352
00353 int WOLsleepTime = 0, WOLmaxConnTry = 0;
00354 if (!WOLcmd.isEmpty())
00355 {
00356 WOLsleepTime = GetNumSetting("WOLbackendReconnectWaitTime", 0);
00357 WOLmaxConnTry = max(GetNumSetting("WOLbackendConnectRetry", 1), 1);
00358 maxConnTry = max(maxConnTry, WOLmaxConnTry);
00359 }
00360
00361 bool we_attempted_wol = false;
00362
00363 if (setup_timeout <= 0)
00364 setup_timeout = MythSocket::kShortTimeout;
00365
00366 bool proto_mismatch = false;
00367 for (int cnt = 1; cnt <= maxConnTry; cnt++)
00368 {
00369 LOG(VB_GENERAL, LOG_INFO, LOC +
00370 QString("Connecting to backend server: %1:%2 (try %3 of %4)")
00371 .arg(hostname).arg(port).arg(cnt).arg(maxConnTry));
00372
00373 serverSock = new MythSocket();
00374
00375 int sleepms = 0;
00376 if (serverSock->connect(hostname, port))
00377 {
00378 if (SetupCommandSocket(
00379 serverSock, announce, setup_timeout, proto_mismatch))
00380 {
00381 break;
00382 }
00383
00384 if (proto_mismatch)
00385 {
00386 if (p_proto_mismatch)
00387 *p_proto_mismatch = true;
00388
00389 serverSock->DownRef();
00390 serverSock = NULL;
00391 break;
00392 }
00393
00394 setup_timeout = (int)(setup_timeout * 1.5f);
00395 }
00396 else if (!WOLcmd.isEmpty() && (cnt < maxConnTry))
00397 {
00398 if (!we_attempted_wol)
00399 {
00400 QMutexLocker locker(&d->m_WOLInProgressLock);
00401 if (d->m_WOLInProgress)
00402 {
00403 d->WaitForWOL();
00404 continue;
00405 }
00406
00407 d->m_WOLInProgress = we_attempted_wol = true;
00408 }
00409
00410 myth_system(WOLcmd, kMSDontDisableDrawing | kMSDontBlockInputDevs |
00411 kMSProcessEvents);
00412 sleepms = WOLsleepTime * 1000;
00413 }
00414
00415 serverSock->DownRef();
00416 serverSock = NULL;
00417
00418 if (!serverSock && (cnt == 1))
00419 {
00420 QCoreApplication::postEvent(
00421 d->m_GUIcontext, new MythEvent("CONNECTION_FAILURE"));
00422 }
00423
00424 if (sleepms)
00425 usleep(sleepms * 1000);
00426 }
00427
00428 if (we_attempted_wol)
00429 {
00430 QMutexLocker locker(&d->m_WOLInProgressLock);
00431 d->m_WOLInProgress = false;
00432 d->m_WOLInProgressWaitCondition.wakeAll();
00433 }
00434
00435 if (!serverSock && !proto_mismatch)
00436 {
00437 LOG(VB_GENERAL, LOG_ERR,
00438 "Connection to master server timed out.\n\t\t\t"
00439 "Either the server is down or the master server settings"
00440 "\n\t\t\t"
00441 "in mythtv-settings does not contain the proper IP address\n");
00442 }
00443 else
00444 {
00445 QCoreApplication::postEvent(
00446 d->m_GUIcontext, new MythEvent("CONNECTION_RESTABLISHED"));
00447 }
00448
00449 return serverSock;
00450 }
00451
00452 MythSocket *MythCoreContext::ConnectEventSocket(const QString &hostname,
00453 int port)
00454 {
00455 MythSocket *m_eventSock = new MythSocket();
00456
00457 while (m_eventSock->state() != MythSocket::Idle)
00458 {
00459 usleep(5000);
00460 }
00461
00462
00463
00464 if (!m_eventSock->connect(hostname, port))
00465 {
00466 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to connect event "
00467 "socket to master backend");
00468 m_eventSock->DownRef();
00469 m_eventSock = NULL;
00470 return NULL;
00471 }
00472
00473 m_eventSock->Lock();
00474
00475 QString str = QString("ANN Monitor %1 %2")
00476 .arg(d->m_localHostname).arg(true);
00477 QStringList strlist(str);
00478 m_eventSock->writeStringList(strlist);
00479 if (!m_eventSock->readStringList(strlist) || strlist.empty() ||
00480 (strlist[0] == "ERROR"))
00481 {
00482 if (!strlist.empty())
00483 LOG(VB_GENERAL, LOG_ERR, LOC + "Problem connecting "
00484 "event socket to master backend");
00485 else
00486 LOG(VB_GENERAL, LOG_ERR, LOC + "Timeout connecting "
00487 "event socket to master backend");
00488
00489 m_eventSock->DownRef();
00490 m_eventSock->Unlock();
00491 m_eventSock = NULL;
00492 return NULL;
00493 }
00494
00495 m_eventSock->Unlock();
00496 m_eventSock->setCallbacks(this);
00497
00498 return m_eventSock;
00499 }
00500
00501 bool MythCoreContext::IsConnectedToMaster(void)
00502 {
00503 QMutexLocker locker(&d->m_sockLock);
00504 return d->m_serverSock;
00505 }
00506
00507 void MythCoreContext::BlockShutdown(void)
00508 {
00509 QStringList strlist;
00510
00511 QMutexLocker locker(&d->m_sockLock);
00512 if (d->m_serverSock == NULL)
00513 return;
00514
00515 strlist << "BLOCK_SHUTDOWN";
00516 d->m_serverSock->writeStringList(strlist);
00517 d->m_serverSock->readStringList(strlist);
00518
00519 if ((d->m_eventSock == NULL) ||
00520 (d->m_eventSock->state() != MythSocket::Connected))
00521 return;
00522
00523 d->m_blockingClient = true;
00524
00525 strlist.clear();
00526 strlist << "BLOCK_SHUTDOWN";
00527
00528 d->m_eventSock->Lock();
00529
00530 d->m_eventSock->writeStringList(strlist);
00531 d->m_eventSock->readStringList(strlist);
00532
00533 d->m_eventSock->Unlock();
00534 }
00535
00536 void MythCoreContext::AllowShutdown(void)
00537 {
00538 QStringList strlist;
00539
00540 QMutexLocker locker(&d->m_sockLock);
00541 if (d->m_serverSock == NULL)
00542 return;
00543
00544 strlist << "ALLOW_SHUTDOWN";
00545 d->m_serverSock->writeStringList(strlist);
00546 d->m_serverSock->readStringList(strlist);
00547
00548 if ((d->m_eventSock == NULL) ||
00549 (d->m_eventSock->state() != MythSocket::Connected))
00550 return;
00551
00552 d->m_blockingClient = false;
00553
00554 strlist.clear();
00555 strlist << "ALLOW_SHUTDOWN";
00556
00557 d->m_eventSock->Lock();
00558
00559 d->m_eventSock->writeStringList(strlist);
00560 d->m_eventSock->readStringList(strlist);
00561
00562 d->m_eventSock->Unlock();
00563 }
00564
00565 bool MythCoreContext::IsBlockingClient(void) const
00566 {
00567 return d->m_blockingClient;
00568 }
00569
00570 void MythCoreContext::SetBackend(bool backend)
00571 {
00572 d->m_backend = backend;
00573 }
00574
00575 bool MythCoreContext::IsBackend(void) const
00576 {
00577 return d->m_backend;
00578 }
00579
00580 bool MythCoreContext::IsMasterHost(void)
00581 {
00582 QString host = GetHostName();
00583 return IsMasterHost(host);
00584 }
00585
00586 bool MythCoreContext::IsMasterHost(const QString &host)
00587 {
00588 return IsThisHost(GetSetting("MasterServerIP"), host);
00589 }
00590
00591 bool MythCoreContext::IsMasterBackend(void)
00592 {
00593 return (IsBackend() && IsMasterHost());
00594 }
00595
00596 bool MythCoreContext::BackendIsRunning(void)
00597 {
00598 #if CONFIG_DARWIN || (__FreeBSD__) || defined(__OpenBSD__)
00599 const char *command = "ps -axc | grep -i mythbackend | grep -v grep > /dev/null";
00600 #elif defined USING_MINGW
00601 const char *command = "%systemroot%\\system32\\tasklist.exe "
00602 " | %systemroot%\\system32\\find.exe /i \"mythbackend.exe\" ";
00603 #else
00604 const char *command = "ps ch -C mythbackend -o pid > /dev/null";
00605 #endif
00606 uint res = myth_system(command, kMSDontBlockInputDevs |
00607 kMSDontDisableDrawing |
00608 kMSProcessEvents);
00609 return (res == GENERIC_EXIT_OK);
00610 }
00611
00612 bool MythCoreContext::IsThisHost(const QString &addr)
00613 {
00614 return IsThisHost(addr, GetHostName());
00615 }
00616
00617 bool MythCoreContext::IsThisHost(const QString &addr, const QString &host)
00618 {
00619 QString thisip = GetSettingOnHost("BackendServerIP", host);
00620 QString thisip6 = GetSettingOnHost("BackendServerIP6", host);
00621
00622 return ((addr == thisip) || (addr == thisip6));
00623 }
00624
00625 bool MythCoreContext::IsFrontendOnly(void)
00626 {
00627
00628 bool backendOnLocalhost = false;
00629
00630 QStringList strlist("QUERY_IS_ACTIVE_BACKEND");
00631 strlist << GetHostName();
00632
00633 SendReceiveStringList(strlist);
00634
00635 if (QString(strlist[0]) == "FALSE")
00636 backendOnLocalhost = false;
00637 else
00638 backendOnLocalhost = true;
00639
00640 return !backendOnLocalhost;
00641 }
00642
00643 QString MythCoreContext::GenMythURL(QString host, QString port, QString path, QString storageGroup)
00644 {
00645 return GenMythURL(host,port.toInt(),path,storageGroup);
00646 }
00647
00648 QString MythCoreContext::GenMythURL(QString host, int port, QString path, QString storageGroup)
00649 {
00650 QString ret;
00651
00652 QString m_storageGroup;
00653 QString m_host;
00654 QString m_port;
00655
00656 QHostAddress addr(host);
00657
00658 if (!storageGroup.isEmpty())
00659 m_storageGroup = storageGroup + "@";
00660
00661 m_host = host;
00662
00663 #if !defined(QT_NO_IPV6)
00664
00665 if (( addr.protocol() == QAbstractSocket::IPv6Protocol ) || (host.contains(":")))
00666 m_host = "[" + host + "]";
00667 #endif
00668
00669 if (port > 0)
00670 m_port = QString(":%1").arg(port);
00671 else
00672 m_port = "";
00673
00674 QString seperator = "/";
00675 if (path.startsWith("/"))
00676 seperator = "";
00677
00678 ret = QString("myth://%1%2%3%4%5").arg(m_storageGroup).arg(m_host).arg(m_port).arg(seperator).arg(path);
00679
00680 #if 0
00681 LOG(VB_GENERAL, LOG_DEBUG, LOC +
00682 QString("GenMythURL returning %1").arg(ret));
00683 #endif
00684
00685 return ret;
00686 }
00687
00688 QString MythCoreContext::GetMasterHostPrefix(const QString &storageGroup,
00689 const QString &path)
00690 {
00691 QString ret;
00692
00693 if (IsMasterHost())
00694 {
00695 return GenMythURL(GetSetting("MasterServerIP"),
00696 GetNumSetting("MasterServerPort", 6543),
00697 path,
00698 storageGroup);
00699 }
00700
00701 QMutexLocker locker(&d->m_sockLock);
00702 if (!d->m_serverSock)
00703 {
00704 bool blockingClient = GetNumSetting("idleTimeoutSecs",0) > 0;
00705 ConnectToMasterServer(blockingClient);
00706 }
00707
00708 if (d->m_serverSock)
00709 {
00710
00711 ret = GenMythURL(d->m_serverSock->peerAddress().toString(),
00712 d->m_serverSock->peerPort(),
00713 path,
00714 storageGroup);
00715 }
00716
00717 return ret;
00718 }
00719
00720 QString MythCoreContext::GetMasterHostName(void)
00721 {
00722 QMutexLocker locker(&d->m_masterHostLock);
00723
00724 if (d->m_masterHostname.isEmpty())
00725 {
00726
00727 if (IsMasterBackend())
00728 d->m_masterHostname = d->m_localHostname;
00729 else
00730 {
00731 QStringList strlist("QUERY_HOSTNAME");
00732
00733 if (SendReceiveStringList(strlist))
00734 d->m_masterHostname = strlist[0];
00735 }
00736 }
00737
00738 QString ret = d->m_masterHostname;
00739 ret.detach();
00740
00741 return ret;
00742 }
00743
00744 void MythCoreContext::ClearSettingsCache(const QString &myKey)
00745 {
00746 d->m_database->ClearSettingsCache(myKey);
00747 }
00748
00749 void MythCoreContext::ActivateSettingsCache(bool activate)
00750 {
00751 d->m_database->ActivateSettingsCache(activate);
00752 }
00753
00754 QString MythCoreContext::GetHostName(void)
00755 {
00756 QMutexLocker (&d->m_localHostLock);
00757 QString tmp = d->m_localHostname;
00758 tmp.detach();
00759 return tmp;
00760 }
00761
00762 QString MythCoreContext::GetFilePrefix(void)
00763 {
00764 return GetSetting("RecordFilePrefix");
00765 }
00766
00767 void MythCoreContext::GetResolutionSetting(const QString &type,
00768 int &width, int &height,
00769 double &forced_aspect,
00770 double &refresh_rate,
00771 int index)
00772 {
00773 d->m_database->GetResolutionSetting(type, width, height, forced_aspect,
00774 refresh_rate, index);
00775 }
00776
00777 void MythCoreContext::GetResolutionSetting(const QString &t, int &w,
00778 int &h, int i)
00779 {
00780 d->m_database->GetResolutionSetting(t, w, h, i);
00781 }
00782
00783 MDBManager *MythCoreContext::GetDBManager(void)
00784 {
00785 return d->m_database->GetDBManager();
00786 }
00787
00794 bool MythCoreContext::IsDatabaseIgnored(void) const
00795 {
00796 return d->m_database->IsDatabaseIgnored();
00797 }
00798
00799 void MythCoreContext::SaveSetting(const QString &key, int newValue)
00800 {
00801 d->m_database->SaveSetting(key, newValue);
00802 }
00803
00804 void MythCoreContext::SaveSetting(const QString &key, const QString &newValue)
00805 {
00806 d->m_database->SaveSetting(key, newValue);
00807 }
00808
00809 bool MythCoreContext::SaveSettingOnHost(const QString &key,
00810 const QString &newValue,
00811 const QString &host)
00812 {
00813 return d->m_database->SaveSettingOnHost(key, newValue, host);
00814 }
00815
00816 QString MythCoreContext::GetSetting(const QString &key,
00817 const QString &defaultval)
00818 {
00819 return d->m_database->GetSetting(key, defaultval);
00820 }
00821
00822 int MythCoreContext::GetNumSetting(const QString &key, int defaultval)
00823 {
00824 return d->m_database->GetNumSetting(key, defaultval);
00825 }
00826
00827 double MythCoreContext::GetFloatSetting(const QString &key, double defaultval)
00828 {
00829 return d->m_database->GetFloatSetting(key, defaultval);
00830 }
00831
00832 QString MythCoreContext::GetSettingOnHost(const QString &key,
00833 const QString &host,
00834 const QString &defaultval)
00835 {
00836 return d->m_database->GetSettingOnHost(key, host, defaultval);
00837 }
00838
00839 int MythCoreContext::GetNumSettingOnHost(const QString &key,
00840 const QString &host,
00841 int defaultval)
00842 {
00843 return d->m_database->GetNumSettingOnHost(key, host, defaultval);
00844 }
00845
00846 double MythCoreContext::GetFloatSettingOnHost(const QString &key,
00847 const QString &host,
00848 double defaultval)
00849 {
00850 return d->m_database->GetFloatSettingOnHost(key, host, defaultval);
00851 }
00852
00853 #if 0
00854 QString MythCoreContext::GetMasterServerIP(void)
00855 {
00856 QString saddr = GetSetting("MasterServerIP");
00857 QHostAddress addr(saddr);
00858
00859 if (!d->m_IPv6.empty() &&
00860 (addr.protocol() == QAbstractSocket::IPv6Protocol))
00861
00862 return saddr;
00863 else if (!d->m_IPv4.empty() &&
00864 (addr.protocol() == QAbstractSocket::IPv4Protocol))
00865
00866 return saddr;
00867 else
00868 return GetBackendServerIP(GetMasterHostName());
00869 }
00870 #endif
00871
00872 QString MythCoreContext::GetBackendServerIP(void)
00873 {
00874 return GetBackendServerIP(d->m_localHostname);
00875 }
00876
00877 QString MythCoreContext::GetBackendServerIP(const QString &host)
00878 {
00879 QString addr4, addr6;
00880 #if !defined(QT_NO_IPV6)
00881 if (!ServerPool::DefaultListenIPv6().isEmpty())
00882
00883 addr6 = GetSettingOnHost("BackendServerIP6", host, "");
00884 #endif
00885 if (!ServerPool::DefaultListenIPv4().isEmpty())
00886 addr4 = GetSettingOnHost("BackendServerIP", host, "");
00887
00888 if (addr6.isEmpty())
00889 {
00890 if (addr4.isEmpty())
00891 {
00892 LOG(VB_GENERAL, LOG_ERR, "No address defined for host: "+host);
00893 return "";
00894 }
00895
00896
00897 return addr4;
00898 }
00899 else if ((QHostAddress(addr6) == QHostAddress::LocalHostIPv6) &&
00900 !addr4.isEmpty() &&
00901 (QHostAddress(addr4) != QHostAddress::LocalHost))
00902
00903 return addr4;
00904 else
00905 return addr6;
00906 }
00907
00908 void MythCoreContext::OverrideSettingForSession(const QString &key,
00909 const QString &value)
00910 {
00911 d->m_database->OverrideSettingForSession(key, value);
00912 }
00913
00914 void MythCoreContext::ClearOverrideSettingForSession(const QString &key)
00915 {
00916 d->m_database->ClearOverrideSettingForSession(key);
00917 }
00918
00919 bool MythCoreContext::IsUIThread(void)
00920 {
00921 return is_current_thread(d->m_UIThread);
00922 }
00923
00924 bool MythCoreContext::SendReceiveStringList(QStringList &strlist,
00925 bool quickTimeout, bool block)
00926 {
00927 if (HasGUI() && IsUIThread())
00928 {
00929 QString msg = "SendReceiveStringList(";
00930 for (uint i=0; i<(uint)strlist.size() && i<2; i++)
00931 msg += (i?",":"") + strlist[i];
00932 msg += (strlist.size() > 2) ? "...)" : ")";
00933 msg += " called from UI thread";
00934 LOG(VB_GENERAL, LOG_DEBUG, msg);
00935 }
00936
00937 QString query_type = "UNKNOWN";
00938
00939 if (!strlist.isEmpty())
00940 query_type = strlist[0];
00941
00942 QMutexLocker locker(&d->m_sockLock);
00943 if (!d->m_serverSock)
00944 {
00945 bool blockingClient = GetNumSetting("idleTimeoutSecs",0) > 0;
00946 ConnectToMasterServer(blockingClient);
00947 }
00948
00949 bool ok = false;
00950
00951 if (d->m_serverSock)
00952 {
00953 QStringList sendstrlist = strlist;
00954 d->m_serverSock->writeStringList(sendstrlist);
00955 ok = d->m_serverSock->readStringList(strlist, quickTimeout);
00956
00957 if (!ok)
00958 {
00959 LOG(VB_GENERAL, LOG_NOTICE,
00960 QString("Connection to backend server lost"));
00961 d->m_serverSock->DownRef();
00962 d->m_serverSock = NULL;
00963
00964 if (d->m_eventSock)
00965 {
00966 d->m_eventSock->DownRef();
00967 d->m_eventSock = NULL;
00968 }
00969
00970 bool blockingClient = GetNumSetting("idleTimeoutSecs",0);
00971 ConnectToMasterServer(blockingClient);
00972
00973 if (d->m_serverSock)
00974 {
00975 d->m_serverSock->writeStringList(sendstrlist);
00976 ok = d->m_serverSock->readStringList(strlist, quickTimeout);
00977 }
00978 }
00979
00980
00981 while (ok && strlist[0] == "BACKEND_MESSAGE")
00982 {
00983
00984 LOG(VB_GENERAL, LOG_EMERG, "SRSL you shouldn't see this!!");
00985 QString message = strlist[1];
00986 strlist.pop_front(); strlist.pop_front();
00987
00988 MythEvent me(message, strlist);
00989 dispatch(me);
00990
00991 ok = d->m_serverSock->readStringList(strlist, quickTimeout);
00992 }
00993
00994 if (!ok)
00995 {
00996 if (d->m_serverSock)
00997 {
00998 d->m_serverSock->DownRef();
00999 d->m_serverSock = NULL;
01000 }
01001
01002 LOG(VB_GENERAL, LOG_CRIT,
01003 QString("Reconnection to backend server failed"));
01004
01005 QCoreApplication::postEvent(d->m_GUIcontext,
01006 new MythEvent("PERSISTENT_CONNECTION_FAILURE"));
01007 }
01008 }
01009
01010 if (ok)
01011 {
01012 if (strlist.isEmpty())
01013 ok = false;
01014 else if (strlist[0] == "ERROR")
01015 {
01016 if (strlist.size() == 2)
01017 LOG(VB_GENERAL, LOG_INFO,
01018 QString("Protocol query '%1' responded with the error '%2'")
01019 .arg(query_type).arg(strlist[1]));
01020 else
01021 LOG(VB_GENERAL, LOG_INFO,
01022 QString("Protocol query '%1' responded with an error, but "
01023 "no error message.") .arg(query_type));
01024
01025 ok = false;
01026 }
01027 }
01028
01029 return ok;
01030 }
01031
01032 void MythCoreContext::SendMessage(const QString &message)
01033 {
01034 if (IsBackend())
01035 {
01036 dispatch(MythEvent(message));
01037 return;
01038 }
01039
01040 QStringList strlist( "MESSAGE" );
01041 strlist << message;
01042
01043 SendReceiveStringList(strlist);
01044 }
01045
01046 void MythCoreContext::SendEvent(const MythEvent &event)
01047 {
01048 if (IsBackend())
01049 {
01050 dispatch(event);
01051 return;
01052 }
01053
01054 QStringList strlist( "MESSAGE" );
01055 strlist << event.Message();
01056 strlist << event.ExtraDataList();
01057
01058 SendReceiveStringList(strlist);
01059 }
01060
01061 void MythCoreContext::SendSystemEvent(const QString &msg)
01062 {
01063 if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHTV_SETUP)
01064 return;
01065
01066 SendMessage(QString("SYSTEM_EVENT %1 SENDER %2")
01067 .arg(msg).arg(GetHostName()));
01068 }
01069
01070 void MythCoreContext::SendHostSystemEvent(const QString &msg,
01071 const QString &hostname,
01072 const QString &args)
01073 {
01074 SendSystemEvent(QString("%1 HOST %2 %3").arg(msg).arg(hostname).arg(args));
01075 }
01076
01077
01078 void MythCoreContext::readyRead(MythSocket *sock)
01079 {
01080 while (sock->state() == MythSocket::Connected &&
01081 sock->bytesAvailable() > 0)
01082 {
01083 QStringList strlist;
01084 if (!sock->readStringList(strlist))
01085 continue;
01086
01087 QString prefix = strlist[0];
01088 QString message = strlist[1];
01089
01090 if (prefix == "OK")
01091 {
01092 }
01093 else if (prefix != "BACKEND_MESSAGE")
01094 {
01095 LOG(VB_GENERAL, LOG_ERR,
01096 QString("Received a: %1 message from the backend "
01097 "but I don't know what to do with it.")
01098 .arg(prefix));
01099 }
01100 else if (message == "CLEAR_SETTINGS_CACHE")
01101 {
01102
01103 LOG(VB_GENERAL, LOG_INFO, "Received remote 'Clear Cache' request");
01104 ClearSettingsCache();
01105 }
01106 else
01107 {
01108 strlist.pop_front();
01109 strlist.pop_front();
01110 MythEvent me(message, strlist);
01111 dispatch(me);
01112 }
01113 }
01114 }
01115
01116 void MythCoreContext::connectionClosed(MythSocket *sock)
01117 {
01118 (void)sock;
01119
01120 LOG(VB_GENERAL, LOG_NOTICE,
01121 "Event socket closed. No connection to the backend.");
01122
01123 QMutexLocker locker(&d->m_sockLock);
01124 if (d->m_serverSock)
01125 {
01126 d->m_serverSock->DownRef();
01127 d->m_serverSock = NULL;
01128 }
01129
01130 if (d->m_eventSock)
01131 {
01132 d->m_eventSock->DownRef();
01133 d->m_eventSock = NULL;
01134 }
01135
01136 dispatch(MythEvent(QString("BACKEND_SOCKETS_CLOSED")));
01137 }
01138
01139 bool MythCoreContext::CheckProtoVersion(MythSocket *socket, uint timeout_ms,
01140 bool error_dialog_desired)
01141 {
01142 if (!socket)
01143 return false;
01144
01145 QStringList strlist(QString("MYTH_PROTO_VERSION %1 %2")
01146 .arg(MYTH_PROTO_VERSION).arg(MYTH_PROTO_TOKEN));
01147 socket->writeStringList(strlist);
01148
01149 if (!socket->readStringList(strlist, timeout_ms) || strlist.empty())
01150 {
01151 LOG(VB_GENERAL, LOG_CRIT, "Protocol version check failure.\n\t\t\t"
01152 "The response to MYTH_PROTO_VERSION was empty.\n\t\t\t"
01153 "This happens when the backend is too busy to respond,\n\t\t\t"
01154 "or has deadlocked due to bugs or hardware failure.");
01155
01156 return false;
01157 }
01158 else if (strlist[0] == "REJECT" && strlist.size() >= 2)
01159 {
01160 LOG(VB_GENERAL, LOG_CRIT, QString("Protocol version or token mismatch "
01161 "(frontend=%1/%2,backend=%3/\?\?)\n")
01162 .arg(MYTH_PROTO_VERSION)
01163 .arg(MYTH_PROTO_TOKEN)
01164 .arg(strlist[1]));
01165
01166 if (error_dialog_desired && d->m_GUIcontext)
01167 {
01168 QStringList list(strlist[1]);
01169 QCoreApplication::postEvent(
01170 d->m_GUIcontext, new MythEvent("VERSION_MISMATCH", list));
01171 }
01172
01173 return false;
01174 }
01175 else if (strlist[0] == "ACCEPT")
01176 {
01177 LOG(VB_GENERAL, LOG_INFO, QString("Using protocol version %1")
01178 .arg(MYTH_PROTO_VERSION));
01179 return true;
01180 }
01181
01182 LOG(VB_GENERAL, LOG_ERR,
01183 QString("Unexpected response to MYTH_PROTO_VERSION: %1")
01184 .arg(strlist[0]));
01185 return false;
01186 }
01187
01188 void MythCoreContext::dispatch(const MythEvent &event)
01189 {
01190 LOG(VB_NETWORK, LOG_INFO, QString("MythEvent: %1").arg(event.Message()));
01191
01192 MythObservable::dispatch(event);
01193 }
01194
01195 void MythCoreContext::dispatchNow(const MythEvent &event)
01196 {
01197 LOG(VB_NETWORK, LOG_INFO, QString("MythEvent: %1").arg(event.Message()));
01198
01199 MythObservable::dispatchNow(event);
01200 }
01201
01202 void MythCoreContext::SetLocalHostname(const QString &hostname)
01203 {
01204 QMutexLocker locker(&d->m_localHostLock);
01205 d->m_localHostname = hostname;
01206 d->m_database->SetLocalHostname(hostname);
01207 }
01208
01209 void MythCoreContext::SetGUIObject(QObject *gui)
01210 {
01211 d->m_GUIobject = gui;
01212 }
01213
01214 bool MythCoreContext::HasGUI(void) const
01215 {
01216 return d->m_GUIobject;
01217 }
01218
01219 QObject *MythCoreContext::GetGUIObject(void)
01220 {
01221 return d->m_GUIobject;
01222 }
01223
01224 MythDB *MythCoreContext::GetDB(void)
01225 {
01226 return d->m_database;
01227 }
01228
01229 MythLocale *MythCoreContext::GetLocale(void) const
01230 {
01231 return d->m_locale;
01232 }
01233
01238 QString MythCoreContext::GetLanguage(void)
01239 {
01240 return GetLanguageAndVariant().left(2);
01241 }
01242
01250 QString MythCoreContext::GetLanguageAndVariant(void)
01251 {
01252 if (d->language.isEmpty())
01253 d->language = GetSetting("Language", "en_US").toLower();
01254
01255 return d->language;
01256 }
01257
01258 void MythCoreContext::ResetLanguage(void)
01259 {
01260 d->language.clear();
01261 }
01262
01263 void MythCoreContext::InitLocale(void )
01264 {
01265 if (!d->m_locale)
01266 d->m_locale = new MythLocale();
01267
01268 QString localeCode = d->m_locale->GetLocaleCode();
01269 LOG(VB_GENERAL, LOG_NOTICE, QString("Setting QT default locale to %1")
01270 .arg(localeCode));
01271 QLocale::setDefault(d->m_locale->ToQLocale());
01272 }
01273
01274 void MythCoreContext::ReInitLocale(void)
01275 {
01276 if (!d->m_locale)
01277 d->m_locale = new MythLocale();
01278 else
01279 d->m_locale->ReInit();
01280
01281 QString localeCode = d->m_locale->GetLocaleCode();
01282 LOG(VB_GENERAL, LOG_NOTICE, QString("Setting QT default locale to %1")
01283 .arg(localeCode));
01284 QLocale::setDefault(d->m_locale->ToQLocale());
01285 }
01286
01287 const QLocale MythCoreContext::GetQLocale(void)
01288 {
01289 if (!d->m_locale)
01290 InitLocale();
01291
01292 return d->m_locale->ToQLocale();
01293 }
01294
01295 void MythCoreContext::SaveLocaleDefaults(void)
01296 {
01297 if (!d->m_locale)
01298 InitLocale();
01299
01300 if (!d->m_locale->GetLocaleCode().isEmpty())
01301 {
01302 LOG(VB_GENERAL, LOG_INFO,
01303 QString("Current locale %1") .arg(d->m_locale->GetLocaleCode()));
01304
01305 d->m_locale->SaveLocaleDefaults();
01306 return;
01307 }
01308
01309 LOG(VB_GENERAL, LOG_ERR,
01310 "No locale defined! We weren't able to set locale defaults.");
01311 }
01312
01313 void MythCoreContext::SetScheduler(MythScheduler *sched)
01314 {
01315 d->m_scheduler = sched;
01316 }
01317
01318 MythScheduler *MythCoreContext::GetScheduler(void)
01319 {
01320 return d->m_scheduler;
01321 }
01322
01323