summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Kristjansson <dkristjansson@mythtv.org>2009-08-23 03:49:36 (GMT)
committer Daniel Kristjansson <dkristjansson@mythtv.org>2009-08-23 03:49:36 (GMT)
commit2fdeb3fc4acf89989a5db341002ecc5d623f572a (patch)
treeccee11d3189a6a20dfd86f75ac9996ce39bbdd70
parent78ae5553562ae88f29a5dd743779c76204fdc38a (diff)
Refs #6516. One of several patches for the myth socket timeout problem.
This one is the least important, it just handles ANN error conditions and some timeouts better. However, it is the only one of the patches that changes the protocol slightly, so I'm applying this first. The protocol change is simply that ANN handling returns "ERROR" followed by the reason for the error instead of nothing for certain error conditions. Because of the protocol change all backends and frontends must be recompiled. git-svn-id: http://svn.mythtv.org/svn/trunk@21445 7dbf422c-18fa-0310-86e9-fd20926502f2
-rw-r--r--mythtv/bindings/perl/MythTV.pm2
-rwxr-xr-xmythtv/bindings/python/MythTV/MythTV.py2
-rw-r--r--mythtv/libs/libmyth/mythcontext.cpp15
-rw-r--r--mythtv/libs/libmythdb/mythversion.h2
-rw-r--r--mythtv/libs/libmythdb/remotefile.cpp55
-rw-r--r--mythtv/libs/libmythtv/remoteencoder.cpp77
-rw-r--r--mythtv/libs/libmythtv/remoteencoder.h5
-rw-r--r--mythtv/programs/mythbackend/main.cpp32
-rw-r--r--mythtv/programs/mythbackend/mainserver.cpp54
9 files changed, 201 insertions, 43 deletions
diff --git a/mythtv/bindings/perl/MythTV.pm b/mythtv/bindings/perl/MythTV.pm
index 07b5d61..fd47c78 100644
--- a/mythtv/bindings/perl/MythTV.pm
+++ b/mythtv/bindings/perl/MythTV.pm
@@ -101,7 +101,7 @@ package MythTV;
# MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h
# and should be the current MythTV protocol version.
- our $PROTO_VERSION = 47;
+ our $PROTO_VERSION = 48;
# NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
# the number of items in a ProgramInfo QStringList group used by
diff --git a/mythtv/bindings/python/MythTV/MythTV.py b/mythtv/bindings/python/MythTV/MythTV.py
index 2bdc208..0a1580b 100755
--- a/mythtv/bindings/python/MythTV/MythTV.py
+++ b/mythtv/bindings/python/MythTV/MythTV.py
@@ -46,7 +46,7 @@ RECSTATUS = {
}
BACKEND_SEP = '[]:[]'
-PROTO_VERSION = 47
+PROTO_VERSION = 48
PROGRAM_FIELDS = 47
class MythTV:
diff --git a/mythtv/libs/libmyth/mythcontext.cpp b/mythtv/libs/libmyth/mythcontext.cpp
index 9ea86b0..291d07a 100644
--- a/mythtv/libs/libmyth/mythcontext.cpp
+++ b/mythtv/libs/libmyth/mythcontext.cpp
@@ -1452,7 +1452,20 @@ MythSocket *MythContext::ConnectServer(MythSocket *eventSock,
.arg(d->m_localhostname).arg(false);
QStringList strlist(str);
serverSock->writeStringList(strlist);
- serverSock->readStringList(strlist, true);
+ if (!serverSock->readStringList(strlist, true) || strlist.empty() ||
+ (strlist[0] == "ERROR"))
+ {
+ if (strlist[0] == "ERROR")
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Problem connecting "
+ "server socket to master backend");
+ else
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Timeout connecting "
+ "server socket to master backend");
+
+ serverSock->DownRef();
+ serverSock = NULL;
+ return NULL;
+ }
if (eventSock && eventSock->state() == MythSocket::Idle)
{
diff --git a/mythtv/libs/libmythdb/mythversion.h b/mythtv/libs/libmythdb/mythversion.h
index b2d9238..cfbffd5 100644
--- a/mythtv/libs/libmythdb/mythversion.h
+++ b/mythtv/libs/libmythdb/mythversion.h
@@ -27,7 +27,7 @@
* mythtv/bindings/python/MythTV/MythTV.py (version number)
* mythtv/bindings/python/MythTV/MythTV.py (layout)
*/
-#define MYTH_PROTO_VERSION "47"
+#define MYTH_PROTO_VERSION "48"
#endif
diff --git a/mythtv/libs/libmythdb/remotefile.cpp b/mythtv/libs/libmythdb/remotefile.cpp
index 334766b..202ced4 100644
--- a/mythtv/libs/libmythdb/remotefile.cpp
+++ b/mythtv/libs/libmythdb/remotefile.cpp
@@ -65,6 +65,8 @@ MythSocket *RemoteFile::openSocket(bool control)
MythSocket *lsock = new MythSocket();
QString stype = (control) ? "control socket" : "file data socket";
+ QString loc_err = QString("RemoteFile::openSocket(%1), Error: ").arg(stype);
+
if (port <= 0)
{
port = GetMythDB()->GetSettingOnHost("BackendServerPort", host).toInt();
@@ -76,10 +78,9 @@ MythSocket *RemoteFile::openSocket(bool control)
if (!lsock->connect(host, port))
{
- VERBOSE(VB_IMPORTANT,
- QString("RemoteFile::openSocket(%1): \n"
- "\t\t\tCould not connect to server \"%2\" @ port %3")
- .arg(stype).arg(host).arg(port));
+ VERBOSE(VB_IMPORTANT, loc_err +
+ QString("\n\t\t\tCould not connect to server %1:%2")
+ .arg(host).arg(port));
lsock->DownRef();
return NULL;
}
@@ -108,23 +109,43 @@ MythSocket *RemoteFile::openSocket(bool control)
lsock->writeStringList(strlist);
lsock->readStringList(strlist, true);
- if (strlist.size() < 4)
+ if (strlist.size() >= 4)
{
- VERBOSE(VB_IMPORTANT,
- QString("RemoteFile::openSocket(%1): "
- "Did not get proper response from %3:%4")
- .arg(stype).arg(dir).arg(host).arg(port));
-
- return NULL;
+ it = strlist.begin(); ++it;
+ recordernum = (*it).toInt(); ++it;
+ filesize = decodeLongLong(strlist, it);
+ for (; it != strlist.end(); ++it)
+ auxfiles << *it;
+ }
+ else if (0 < strlist.size() && strlist.size() < 4 &&
+ strlist[0] != "ERROR")
+ {
+ VERBOSE(VB_IMPORTANT, loc_err +
+ QString("Did not get proper response from %1:%2")
+ .arg(host).arg(port));
+ strlist.clear();
+ strlist.push_back("ERROR");
+ strlist.push_back("invalid response");
}
+ }
- it = strlist.begin(); ++it;
- recordernum = (*it).toInt(); ++it;
- filesize = decodeLongLong(strlist, it);
- for (; it != strlist.end(); ++it)
- auxfiles << *it;
+ if (strlist.empty() || strlist[0] == "ERROR")
+ {
+ lsock->DownRef();
+ lsock = NULL;
+ if (strlist.empty())
+ {
+ VERBOSE(VB_IMPORTANT, loc_err + "Failed to open socket, timeout");
+ }
+ else
+ {
+ VERBOSE(VB_IMPORTANT, loc_err + "Failed to open socket" +
+ ((strlist.size() >= 2) ?
+ QString(", error was %1").arg(strlist[1]) :
+ QString(", remote error")));
+ }
}
-
+
return lsock;
}
diff --git a/mythtv/libs/libmythtv/remoteencoder.cpp b/mythtv/libs/libmythtv/remoteencoder.cpp
index f7fe701..715ceb9 100644
--- a/mythtv/libs/libmythtv/remoteencoder.cpp
+++ b/mythtv/libs/libmythtv/remoteencoder.cpp
@@ -31,12 +31,34 @@ RemoteEncoder::~RemoteEncoder()
controlSock->DownRef();
}
-void RemoteEncoder::Setup(void)
+bool RemoteEncoder::Setup(void)
{
if (!controlSock)
{
- controlSock = openControlSocket(remotehost, remoteport);
+ VERBOSE(VB_NETWORK|VB_EXTRA, "RemoteEncoder::Setup(): Connecting...");
+
+ QString ann = QString("ANN Playback %1 %2")
+ .arg(gContext->GetHostName()).arg(false);
+
+ controlSock = ConnectCommandSocket(
+ remotehost, remoteport, ann);
+
+ if (controlSock)
+ {
+ VERBOSE(VB_NETWORK|VB_EXTRA, "RemoteEncoder::Setup(): Connected");
+ }
+ else
+ {
+ VERBOSE(VB_IMPORTANT,
+ "RemoteEncoder::Setup(): Failed to connect to backend");
+ }
}
+ else
+ {
+ VERBOSE(VB_NETWORK|VB_EXTRA,
+ "RemoteEncoder::Setup(): Already connected");
+ }
+ return controlSock;
}
bool RemoteEncoder::IsValidRecorder(void)
@@ -54,30 +76,55 @@ bool RemoteEncoder::SendReceiveStringList(
{
QMutexLocker locker(&lock);
if (!controlSock)
- return false;
+ Setup();
backendError = false;
- controlSock->writeStringList(strlist);
- if (!controlSock->readStringList(strlist, true))
+ if (!controlSock)
{
VERBOSE(VB_IMPORTANT,
- "RemoteEncoder::SendReceiveStringList(): No response.");
+ "RemoteEncoder::SendReceiveStringList(): "
+ "Failed to reconnect with backend.");
backendError = true;
return false;
}
- if (min_reply_length && ((uint)strlist.size() < min_reply_length))
+ if (!controlSock->writeStringList(strlist))
+ {
+ VERBOSE(VB_IMPORTANT,
+ "RemoteEncoder::SendReceiveStringList(): "
+ "Failed to write data.");
+ backendError = true;
+ }
+
+ if (!backendError &&
+ !controlSock->readStringList(strlist, true))
+ {
+ VERBOSE(VB_IMPORTANT,
+ "RemoteEncoder::SendReceiveStringList(): No response.");
+ backendError = true;
+ }
+
+ if (!backendError &&
+ min_reply_length && ((uint)strlist.size() < min_reply_length))
{
VERBOSE(VB_IMPORTANT,
"RemoteEncoder::SendReceiveStringList(): Response too short");
+ backendError = true;
+ }
+
+ if (backendError)
+ {
+ controlSock->DownRef();
+ controlSock = NULL;
return false;
}
return true;
}
-MythSocket *RemoteEncoder::openControlSocket(const QString &host, short port)
+MythSocket *RemoteEncoder::ConnectCommandSocket(
+ const QString &host, int port, const QString &ann)
{
MythSocket *sock = new MythSocket();
if (!sock->connect(host, port))
@@ -91,10 +138,16 @@ MythSocket *RemoteEncoder::openControlSocket(const QString &host, short port)
{
if (gContext->CheckProtoVersion(sock))
{
- QString hostname = gContext->GetHostName();
- QStringList strlist( QString("ANN Playback %1 %2").arg(hostname).arg(false) );
- sock->writeStringList(strlist);
- sock->readStringList(strlist, true);
+ QStringList strlist(ann);
+ if (!sock->writeStringList(strlist) ||
+ !sock->readStringList(strlist, true))
+ {
+ VERBOSE(VB_IMPORTANT,
+ "RemoteEncoder::ConnectCommandSocket(): "
+ "Failed to announce ourselves to server");
+ sock->DownRef();
+ sock = NULL;
+ }
}
else
{
diff --git a/mythtv/libs/libmythtv/remoteencoder.h b/mythtv/libs/libmythtv/remoteencoder.h
index 0f977ae..2266b76 100644
--- a/mythtv/libs/libmythtv/remoteencoder.h
+++ b/mythtv/libs/libmythtv/remoteencoder.h
@@ -18,7 +18,7 @@ class MPUBLIC RemoteEncoder
RemoteEncoder(int num, const QString &host, short port);
~RemoteEncoder(void);
- void Setup(void);
+ bool Setup(void);
bool IsValidRecorder(void);
int GetRecorderNumber(void);
@@ -69,7 +69,8 @@ class MPUBLIC RemoteEncoder
return v; }
private:
- MythSocket *openControlSocket(const QString &host, short port);
+ MythSocket *ConnectCommandSocket(
+ const QString &host, int port, const QString &ann);
bool SendReceiveStringList(QStringList &strlist, uint min_reply_length = 0);
int recordernum;
diff --git a/mythtv/programs/mythbackend/main.cpp b/mythtv/programs/mythbackend/main.cpp
index 92dae68..f1e98cb 100644
--- a/mythtv/programs/mythbackend/main.cpp
+++ b/mythtv/programs/mythbackend/main.cpp
@@ -908,10 +908,32 @@ int main(int argc, char **argv)
QStringList tempMonitorAnnounce("ANN Monitor tzcheck 0");
tempMonitorConnection->writeStringList(tempMonitorAnnounce);
tempMonitorConnection->readStringList(tempMonitorAnnounce);
+ if (tempMonitorAnnounce.empty() ||
+ tempMonitorAnnounce[0] == "ERROR")
+ {
+ tempMonitorConnection->DownRef();
+ tempMonitorConnection = NULL;
+ if (tempMonitorAnnounce.empty())
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR +
+ "Failed to open event socket, timeout");
+ }
+ else
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR +
+ "Failed to open event socket" +
+ ((tempMonitorAnnounce.size() >= 2) ?
+ QString(", error was %1").arg(tempMonitorAnnounce[1]) :
+ QString(", remote error")));
+ }
+ }
QStringList tzCheck("QUERY_TIME_ZONE");
- tempMonitorConnection->writeStringList(tzCheck);
- tempMonitorConnection->readStringList(tzCheck);
+ if (tempMonitorConnection)
+ {
+ tempMonitorConnection->writeStringList(tzCheck);
+ tempMonitorConnection->readStringList(tzCheck);
+ }
if (tzCheck.size() && !checkTimeZone(tzCheck))
{
// Check for different time zones, different offsets, different
@@ -933,9 +955,11 @@ int main(int argc, char **argv)
QString("Backend is running in %1 time zone.")
.arg(getTimeZoneID()));
}
- tempMonitorConnection->writeStringList(tempMonitorDone);
+ if (tempMonitorConnection)
+ tempMonitorConnection->writeStringList(tempMonitorDone);
}
- tempMonitorConnection->DownRef();
+ if (tempMonitorConnection)
+ tempMonitorConnection->DownRef();
}
if (!UpgradeTVDatabaseSchema(true, true))
diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp
index 883db51..bcac64c 100644
--- a/mythtv/programs/mythbackend/mainserver.cpp
+++ b/mythtv/programs/mythbackend/mainserver.cpp
@@ -65,6 +65,10 @@ using namespace std;
/** Number of threads in process request thread pool at startup. */
#define PRT_STARTUP_THREAD_COUNT 5
+#define LOC QString("MainServer: ")
+#define LOC_WARN QString("MainServer, Warning: ")
+#define LOC_ERR QString("MainServer, Error: ")
+
namespace {
int delete_file_immediately(const QString &filename,
@@ -968,6 +972,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
MythSocket *socket)
{
QStringList retlist( "OK" );
+ QStringList errlist( "ERROR" );
if (commands.size() < 3 || commands.size() > 6)
{
@@ -978,6 +983,9 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
VERBOSE(VB_IMPORTANT,
QString("Received malformed ANN%1 query")
.arg(info));
+
+ errlist << "malformed_ann_query";
+ socket->writeStringList(errlist);
return;
}
@@ -989,9 +997,10 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
if (pbs->getSocket() == socket)
{
sockListLock.unlock();
- VERBOSE(VB_IMPORTANT, QString("Client %1 is trying to announce a socket "
- "multiple times.")
- .arg(commands[2]));
+ VERBOSE(VB_IMPORTANT,
+ QString("Client %1 is trying to announce a socket "
+ "multiple times.")
+ .arg(commands[2]));
socket->writeStringList(retlist);
return;
}
@@ -1005,6 +1014,9 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
VERBOSE(VB_IMPORTANT,
QString("Received malformed ANN %1 query")
.arg(commands[1]));
+
+ errlist << "malformed_ann_query";
+ socket->writeStringList(errlist);
return;
}
// Monitor connections are same as Playback but they don't
@@ -1027,6 +1039,8 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
{
VERBOSE(VB_IMPORTANT, QString("Received malformed ANN %1 query")
.arg(commands[1]));
+ errlist << "malformed_ann_query";
+ socket->writeStringList(errlist);
return;
}
@@ -1084,6 +1098,8 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
if (slist.size() < 3)
{
VERBOSE(VB_IMPORTANT, "Received malformed FileTransfer command");
+ errlist << "malformed_filetransfer_command";
+ socket->writeStringList(errlist);
return;
}
@@ -1122,6 +1138,8 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
{
VERBOSE(VB_IMPORTANT, "Unable to determine directory "
"to write to in FileTransfer write command");
+ errlist << "filetransfer_directory_not_found";
+ socket->writeStringList(errlist);
return;
}
@@ -1131,6 +1149,8 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
VERBOSE(VB_IMPORTANT, QString("ERROR: FileTransfer write "
"filename is empty in url '%1'.")
.arg(qurl.toString()));
+ errlist << "filetransfer_filename_empty";
+ socket->writeStringList(errlist);
return;
}
@@ -1140,6 +1160,8 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands,
VERBOSE(VB_IMPORTANT, QString("ERROR: FileTransfer write "
"filename '%1' does not pass sanity checks.")
.arg(basename));
+ errlist << "filetransfer_filename_dangerous";
+ socket->writeStringList(errlist);
return;
}
@@ -4646,7 +4668,9 @@ void MainServer::connectionClosed(MythSocket *socket)
sockListLock.unlock();
- VERBOSE(VB_IMPORTANT, "Unknown socket closing");
+ VERBOSE(VB_IMPORTANT, LOC_WARN +
+ QString("Unknown socket closing MythSocket(0x%1)")
+ .arg((uint64_t)socket,0,16));
}
PlaybackSock *MainServer::getSlaveByHostname(QString &hostname)
@@ -4968,6 +4992,28 @@ void MainServer::reconnectTimeout(void)
masterServerSock->writeStringList(strlist);
masterServerSock->readStringList(strlist);
+ if (strlist.empty() || strlist[0] == "ERROR")
+ {
+ masterServerSock->DownRef();
+ masterServerSock->Unlock();
+ masterServerSock = NULL;
+ if (strlist.empty())
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR +
+ "Failed to open master server socket, timeout");
+ }
+ else
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR +
+ "Failed to open master server socket" +
+ ((strlist.size() >= 2) ?
+ QString(", error was %1").arg(strlist[1]) :
+ QString(", remote error")));
+ }
+ masterServerReconnect->start(1000);
+ return;
+ }
+
masterServerSock->setCallbacks(this);
masterServer = new PlaybackSock(this, masterServerSock, server, true);