|
MythTV
0.26-pre
|
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" // for CONFIG_DARWIN 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 // This has already been run in the MythContext dtor. Do we need it here 00139 // too? 00140 #if 0 00141 logStop(); // need to shutdown db logger before we kill db 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 // try fallback to environment variables for non-glibc systems 00212 // LC_ALL, then LC_CTYPE 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 // Assumes that either m_sockLock is held, or the app is still single 00286 // threaded (i.e. during startup). 00287 bool MythCoreContext::ConnectToMasterServer(bool blockingClient, 00288 bool openEventSocket) 00289 { 00290 if (IsMasterBackend()) 00291 { 00292 // Should never get here unless there is a bug in the code somewhere. 00293 // If this happens, it can cause endless event loops. 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 // Assume that since we _just_ connected the command socket, 00463 // this one won't need multiple retries to work... 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 // find out if a backend runs on this host... 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 // Basically if it appears to be an IPv6 IP surround the IP with [] otherwise don't bother 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 // we have IPv6 addresses, assume we can connect to them 00862 return saddr; 00863 else if (!d->m_IPv4.empty() && 00864 (addr.protocol() == QAbstractSocket::IPv4Protocol)) 00865 // we have IPv4 addresses, assume we can connect to them 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 // we have IPv6 addresses, assume we can connect to them 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 // IPv6 is empty, so return this regardless 00897 return addr4; 00898 } 00899 else if ((QHostAddress(addr6) == QHostAddress::LocalHostIPv6) && 00900 !addr4.isEmpty() && 00901 (QHostAddress(addr4) != QHostAddress::LocalHost)) 00902 // IPv6 set to localhost, but IPv4 address if network accessible 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 // this should not happen 00981 while (ok && strlist[0] == "BACKEND_MESSAGE") 00982 { 00983 // oops, not for us 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 // No need to dispatch this message to ourself, so handle it 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 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1