MythSocket *MythCoreContext::ConnectEventSocket(const QString &hostname, int port) { MythSocket *eventSock = new MythSocket(); while (eventSock->state() != MythSocket::Idle) { usleep(5000); } // Assume that since we _just_ connected the command socket, // this one won't need multiple retries to work... if (!eventSock->connect(hostname, port)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to connect event " "socket to master backend"); eventSock->DecrRef(); return NULL; } eventSock->Lock(); QString str = QString("ANN Monitor %1 %2") .arg(d->m_localHostname).arg(true); QStringList strlist(str); eventSock->writeStringList(strlist); bool ok = true; if (!eventSock->readStringList(strlist) || strlist.empty() || (strlist[0] == "ERROR")) { if (!strlist.empty()) { LOG(VB_GENERAL, LOG_ERR, LOC + "Problem connecting event socket to master backend"); } else { LOG(VB_GENERAL, LOG_ERR, LOC + "Timeout connecting event socket to master backend"); } ok = false; } eventSock->Unlock(); if (ok) { eventSock->setCallbacks(this); } else { eventSock->DecrRef(); eventSock = NULL; } return eventSock; }
static bool RemoteSendReceiveStringList(const QString &host, QStringList &strlist) { bool ok = false; if (gCoreContext->IsMasterBackend()) { // since the master backend cannot connect back around to // itself, and the libraries do not have access to the list // of connected slave backends to query an existing connection // start up a new temporary connection directly to the slave // backend to query the file list QString ann = QString("ANN Playback %1 0") .arg(gCoreContext->GetHostName()); QString addr = gCoreContext->GetBackendServerIP(host); int port = gCoreContext->GetBackendServerPort(host); bool mismatch = false; MythSocket *sock = gCoreContext->ConnectCommandSocket( addr, port, ann, &mismatch); if (sock) { ok = sock->SendReceiveStringList(strlist); sock->DecrRef(); } else strlist.clear(); } else ok = gCoreContext->SendReceiveStringList(strlist); return ok; }
bool RemoteGetFileList(QString host, QString path, QStringList* list, QString sgroup, bool fileNamesOnly) { // Make sure the list is empty when we get started list->clear(); if (sgroup.isEmpty()) sgroup = "Videos"; *list << "QUERY_SG_GETFILELIST"; *list << host; *list << StorageGroup::GetGroupToUse(host, sgroup); *list << path; *list << QString::number(fileNamesOnly); bool ok = false; if (gCoreContext->IsMasterBackend()) { // since the master backend cannot connect back around to // itself, and the libraries do not have access to the list // of connected slave backends to query an existing connection // start up a new temporary connection directly to the slave // backend to query the file list QString ann = QString("ANN Playback %1 0") .arg(gCoreContext->GetHostName()); QString addr = gCoreContext->GetBackendServerIP(host); int port = gCoreContext->GetBackendServerPort(host); bool mismatch = false; MythSocket *sock = gCoreContext->ConnectCommandSocket( addr, port, ann, &mismatch); if (sock) { ok = sock->SendReceiveStringList(*list); sock->DecrRef(); } else list->clear(); } else ok = gCoreContext->SendReceiveStringList(*list); // Should the SLAVE UNREACH test be here ? return ok; }
MythSocket *RemoteFile::openSocket(bool control) { QUrl qurl(path); QString dir; QString host = qurl.host(); int port = qurl.port(); dir = qurl.path(); if (qurl.hasQuery()) #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) dir += "?" + QUrl::fromPercentEncoding( qurl.query(QUrl::FullyEncoded).toLocal8Bit()); #else dir += "?" + QUrl::fromPercentEncoding(qurl.encodedQuery()); #endif if (qurl.hasFragment()) dir += "#" + qurl.fragment(); QString sgroup = qurl.userName(); MythSocket *lsock = new MythSocket(); QString stype = (control) ? "control socket" : "file data socket"; QString loc = QString("RemoteFile::openSocket(%1): ").arg(stype); if (port <= 0) { port = GetMythDB()->GetSettingOnHost("BackendServerPort", host).toInt(); // if we still have no port use the default if (port <= 0) port = 6543; } if (!lsock->ConnectToHost(host, port)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Could not connect to server %1:%2") .arg(host).arg(port)); lsock->DecrRef(); return NULL; } QString hostname = GetMythDB()->GetHostName(); QStringList strlist; #ifndef IGNORE_PROTO_VER_MISMATCH if (!gCoreContext->CheckProtoVersion(lsock)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Failed validation to server %1:%2").arg(host).arg(port)); lsock->DecrRef(); return NULL; } #endif if (control) { strlist.append(QString("ANN Playback %1 %2").arg(hostname).arg(false)); if (!lsock->SendReceiveStringList(strlist)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Could not read string list from server %1:%2") .arg(host).arg(port)); lsock->DecrRef(); return NULL; } } else { strlist.push_back(QString("ANN FileTransfer %1 %2 %3 %4") .arg(hostname).arg(writemode) .arg(usereadahead).arg(timeout_ms)); strlist << QString("%1").arg(dir); strlist << sgroup; QStringList::const_iterator it = possibleauxfiles.begin(); for (; it != possibleauxfiles.end(); ++it) strlist << *it; if (!lsock->SendReceiveStringList(strlist)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Did not get proper response from %1:%2") .arg(host).arg(port)); strlist.clear(); strlist.push_back("ERROR"); strlist.push_back("invalid response"); } if (strlist.size() >= 3) { it = strlist.begin(); ++it; recordernum = (*it).toInt(); ++it; filesize = (*(it)).toLongLong(); ++it; for (; it != strlist.end(); ++it) auxfiles << *it; } else if (0 < strlist.size() && strlist.size() < 3 && strlist[0] != "ERROR") { LOG(VB_GENERAL, LOG_ERR, loc + QString("Did not get proper response from %1:%2") .arg(host).arg(port)); strlist.clear(); strlist.push_back("ERROR"); strlist.push_back("invalid response"); } } if (strlist.empty() || strlist[0] == "ERROR") { lsock->DecrRef(); lsock = NULL; if (strlist.empty()) { LOG(VB_GENERAL, LOG_ERR, loc + "Failed to open socket, timeout"); } else { LOG(VB_GENERAL, LOG_ERR, loc + "Failed to open socket" + ((strlist.size() >= 2) ? QString(", error was %1").arg(strlist[1]) : QString(", remote error"))); } } return lsock; }
int connect_to_master(void) { MythSocket *tempMonitorConnection = new MythSocket(); if (tempMonitorConnection->ConnectToHost( gCoreContext->GetMasterServerIP(), gCoreContext->GetMasterServerPort())) { if (!gCoreContext->CheckProtoVersion(tempMonitorConnection)) { LOG(VB_GENERAL, LOG_ERR, "Master backend is incompatible with " "this backend.\nCannot become a slave."); tempMonitorConnection->DecrRef(); return GENERIC_EXIT_CONNECT_ERROR; } QStringList tempMonitorDone("DONE"); QStringList tempMonitorAnnounce(QString("ANN Monitor %1 0") .arg(gCoreContext->GetHostName())); tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce); if (tempMonitorAnnounce.empty() || tempMonitorAnnounce[0] == "ERROR") { tempMonitorConnection->DecrRef(); tempMonitorConnection = NULL; if (tempMonitorAnnounce.empty()) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open event socket, timeout"); } else { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open event socket" + ((tempMonitorAnnounce.size() >= 2) ? QString(", error was %1").arg(tempMonitorAnnounce[1]) : QString(", remote error"))); } } QStringList timeCheck; if (tempMonitorConnection) { timeCheck.push_back("QUERY_TIME_ZONE"); tempMonitorConnection->SendReceiveStringList(timeCheck); tempMonitorConnection->WriteStringList(tempMonitorDone); } if (timeCheck.size() < 3) { if (tempMonitorConnection) tempMonitorConnection->DecrRef(); return GENERIC_EXIT_SOCKET_ERROR; } QDateTime our_time = MythDate::current(); QDateTime master_time = MythDate::fromString(timeCheck[2]); int timediff = abs(our_time.secsTo(master_time)); if (timediff > 300) { LOG(VB_GENERAL, LOG_ERR, QString("Current time on the master backend differs by " "%1 seconds from time on this system. Exiting.") .arg(timediff)); if (tempMonitorConnection) tempMonitorConnection->DecrRef(); return GENERIC_EXIT_INVALID_TIME; } if (timediff > 20) { LOG(VB_GENERAL, LOG_WARNING, QString("Time difference between the master " "backend and this system is %1 seconds.") .arg(timediff)); } } if (tempMonitorConnection) tempMonitorConnection->DecrRef(); return GENERIC_EXIT_OK; }
MythSocket *MythCoreContext::ConnectCommandSocket( const QString &hostname, int port, const QString &announce, bool *p_proto_mismatch, bool gui, int maxConnTry, int setup_timeout) { MythSocket *serverSock = NULL; { QMutexLocker locker(&d->m_WOLInProgressLock); d->WaitForWOL(); } QString WOLcmd = GetSetting("WOLbackendCommand", ""); if (maxConnTry < 1) maxConnTry = max(GetNumSetting("BackendConnectRetry", 1), 1); int WOLsleepTime = 0, WOLmaxConnTry = 0; if (!WOLcmd.isEmpty()) { WOLsleepTime = GetNumSetting("WOLbackendReconnectWaitTime", 0); WOLmaxConnTry = max(GetNumSetting("WOLbackendConnectRetry", 1), 1); maxConnTry = max(maxConnTry, WOLmaxConnTry); } bool we_attempted_wol = false; if (setup_timeout <= 0) setup_timeout = MythSocket::kShortTimeout; bool proto_mismatch = false; for (int cnt = 1; cnt <= maxConnTry; cnt++) { LOG(VB_GENERAL, LOG_INFO, LOC + QString("Connecting to backend server: %1:%2 (try %3 of %4)") .arg(hostname).arg(port).arg(cnt).arg(maxConnTry)); serverSock = new MythSocket(); int sleepms = 0; if (serverSock->connect(hostname, port)) { if (SetupCommandSocket( serverSock, announce, setup_timeout, proto_mismatch)) { break; } if (proto_mismatch) { if (p_proto_mismatch) *p_proto_mismatch = true; serverSock->DecrRef(); serverSock = NULL; break; } setup_timeout = (int)(setup_timeout * 1.5f); } else if (!WOLcmd.isEmpty() && (cnt < maxConnTry)) { if (!we_attempted_wol) { QMutexLocker locker(&d->m_WOLInProgressLock); if (d->m_WOLInProgress) { d->WaitForWOL(); continue; } d->m_WOLInProgress = we_attempted_wol = true; } myth_system(WOLcmd, kMSDontDisableDrawing | kMSDontBlockInputDevs | kMSProcessEvents); sleepms = WOLsleepTime * 1000; } serverSock->DecrRef(); serverSock = NULL; if (!serverSock && (cnt == 1)) { QCoreApplication::postEvent( d->m_GUIcontext, new MythEvent("CONNECTION_FAILURE")); } if (sleepms) usleep(sleepms * 1000); } if (we_attempted_wol) { QMutexLocker locker(&d->m_WOLInProgressLock); d->m_WOLInProgress = false; d->m_WOLInProgressWaitCondition.wakeAll(); } if (!serverSock && !proto_mismatch) { LOG(VB_GENERAL, LOG_ERR, "Connection to master server timed out.\n\t\t\t" "Either the server is down or the master server settings" "\n\t\t\t" "in mythtv-settings does not contain the proper IP address\n"); } else { QCoreApplication::postEvent( d->m_GUIcontext, new MythEvent("CONNECTION_RESTABLISHED")); } return serverSock; }