From 0b106b10692ed7efd5eae81b498f591ad39b6222 Mon Sep 17 00:00:00 2001 From: Daniel Thor Kristjansson Date: Thu, 11 Oct 2012 17:47:59 -0400 Subject: [PATCH] Converts MythSocket from Qt3 based MSocketDevice to Qt4 QTcpSocket. --- .../mythzoneminder/zmclient.cpp | 38 +- mythtv/libs/libmyth/mythcontext.cpp | 2 - mythtv/libs/libmythbase/libmythbase.pro | 9 +- mythtv/libs/libmythbase/mythcorecontext.cpp | 169 +-- mythtv/libs/libmythbase/mythmiscutil.cpp | 2 +- mythtv/libs/libmythbase/mythsocket.cpp | 1240 ++++++++--------- mythtv/libs/libmythbase/mythsocket.h | 193 +-- mythtv/libs/libmythbase/mythsocket_cb.h | 1 + mythtv/libs/libmythbase/mythsocketthread.cpp | 389 ------ mythtv/libs/libmythbase/mythsocketthread.h | 49 - mythtv/libs/libmythbase/remotefile.cpp | 160 +-- mythtv/libs/libmythbase/remotefile.h | 5 - .../libmythprotoserver/mythsocketmanager.cpp | 68 +- .../libmythprotoserver/mythsocketmanager.h | 10 +- .../requesthandler/basehandler.cpp | 15 +- .../requesthandler/fileserverhandler.cpp | 67 +- .../requesthandler/messagehandler.cpp | 4 +- .../requesthandler/outboundhandler.cpp | 16 +- .../libs/libmythprotoserver/sockethandler.cpp | 10 +- .../libs/libmythprotoserver/sockethandler.h | 2 +- .../sockethandler/filetransfer.cpp | 8 +- mythtv/libs/libmythtv/remoteencoder.cpp | 4 +- mythtv/libs/libmythupnp/libmythupnp.pro | 4 + .../msocketdevice.cpp | 0 .../msocketdevice.h | 0 .../msocketdevice_unix.cpp | 0 .../msocketdevice_win.cpp | 0 mythtv/programs/mythbackend/encoderlink.cpp | 1 + mythtv/programs/mythbackend/filetransfer.cpp | 6 +- mythtv/programs/mythbackend/main_helpers.cpp | 11 +- mythtv/programs/mythbackend/mainserver.cpp | 181 ++- mythtv/programs/mythbackend/mainserver.h | 4 +- mythtv/programs/mythbackend/playbacksock.cpp | 22 +- mythtv/programs/mythbackend/server.cpp | 5 +- mythtv/programs/mythbackend/server.h | 2 +- 35 files changed, 1100 insertions(+), 1597 deletions(-) delete mode 100644 mythtv/libs/libmythbase/mythsocketthread.cpp delete mode 100644 mythtv/libs/libmythbase/mythsocketthread.h rename mythtv/libs/{libmythbase => libmythupnp}/msocketdevice.cpp (100%) rename mythtv/libs/{libmythbase => libmythupnp}/msocketdevice.h (100%) rename mythtv/libs/{libmythbase => libmythupnp}/msocketdevice_unix.cpp (100%) rename mythtv/libs/{libmythbase => libmythupnp}/msocketdevice_win.cpp (100%) diff --git a/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp b/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp index 0cab2718279..bdfc7ba0913 100644 --- a/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp +++ b/mythplugins/mythzoneminder/mythzoneminder/zmclient.cpp @@ -97,7 +97,7 @@ bool ZMClient::connectToHost(const QString &lhostname, unsigned int lport) m_socket = new MythSocket(); //m_socket->setCallbacks(this); - if (!m_socket->connect(m_hostname, m_port)) + if (!m_socket->ConnectToHost(m_hostname, m_port)) { m_socket->DecrRef(); m_socket = NULL; @@ -133,12 +133,11 @@ bool ZMClient::connectToHost(const QString &lhostname, unsigned int lport) bool ZMClient::sendReceiveStringList(QStringList &strList) { + QStringList origStrList = strList; + bool ok = false; if (m_bConnected) - { - m_socket->writeStringList(strList); - ok = m_socket->readStringList(strList, false); - } + ok = m_socket->SendReceiveStringList(strList); if (!ok) { @@ -146,13 +145,13 @@ bool ZMClient::sendReceiveStringList(QStringList &strList) if (!connectToHost(m_hostname, m_port)) { - LOG(VB_GENERAL, LOG_ERR, "Re connection to mythzmserver failed"); + LOG(VB_GENERAL, LOG_ERR, "Re-connection to mythzmserver failed"); return false; } - // try to resend - m_socket->writeStringList(strList); - ok = m_socket->readStringList(strList, false); + // try to resend + strList = origStrList; + ok = m_socket->SendReceiveStringList(strList); if (!ok) { m_bConnected = false; @@ -160,6 +159,9 @@ bool ZMClient::sendReceiveStringList(QStringList &strList) } } + if (strList.empty()) + return false; + // the server sends "UNKNOWN_COMMAND" if it did not recognise the command if (strList[0] == "UNKNOWN_COMMAND") { @@ -231,7 +233,7 @@ void ZMClient::shutdown() QMutexLocker locker(&m_socketLock); if (m_socket) - m_socket->close(); + m_socket->DisconnectFromHost(); m_zmclientReady = false; m_bConnected = false; @@ -456,7 +458,8 @@ bool ZMClient::readData(unsigned char *data, int dataSize) while (dataSize > 0) { - qint64 sret = m_socket->readBlock((char*) data + read, dataSize); + qint64 sret = m_socket->Read( + (char*) data + read, dataSize, 100 /*ms*/); if (sret > 0) { read += sret; @@ -466,18 +469,17 @@ bool ZMClient::readData(unsigned char *data, int dataSize) timer.start(); } } - else if (sret < 0 && m_socket->error() != MSocketDevice::NoError) + else if (sret < 0) { - LOG(VB_GENERAL, LOG_ERR, QString("readData: Error, readBlock %1") - .arg(m_socket->errorToString())); - m_socket->close(); + LOG(VB_GENERAL, LOG_ERR, "readData: Error, readBlock"); + m_socket->DisconnectFromHost(); return false; } - else if (!m_socket->isValid()) + else if (!m_socket->IsConnected()) { LOG(VB_GENERAL, LOG_ERR, "readData: Error, socket went unconnected"); - m_socket->close(); + m_socket->DisconnectFromHost(); return false; } else @@ -499,8 +501,6 @@ bool ZMClient::readData(unsigned char *data, int dataSize) LOG(VB_GENERAL, LOG_ERR, "Error, readData timeout (readBlock)"); return false; } - - usleep(500); } } diff --git a/mythtv/libs/libmyth/mythcontext.cpp b/mythtv/libs/libmyth/mythcontext.cpp index 384846f0647..19aa1863b7e 100644 --- a/mythtv/libs/libmyth/mythcontext.cpp +++ b/mythtv/libs/libmyth/mythcontext.cpp @@ -26,7 +26,6 @@ using namespace std; #include "dbutil.h" #include "DisplayRes.h" #include "mythmediamonitor.h" -#include "mythsocketthread.h" #include "mythdb.h" #include "mythdirs.h" @@ -1168,7 +1167,6 @@ MythContext::~MythContext() if (MThreadPool::globalInstance()->activeThreadCount()) LOG(VB_GENERAL, LOG_INFO, "Waiting for threads to exit."); - ShutdownRRT(); MThreadPool::globalInstance()->waitForDone(); logStop(); diff --git a/mythtv/libs/libmythbase/libmythbase.pro b/mythtv/libs/libmythbase/libmythbase.pro index d582984e5d3..10be6a9baa8 100644 --- a/mythtv/libs/libmythbase/libmythbase.pro +++ b/mythtv/libs/libmythbase/libmythbase.pro @@ -11,7 +11,7 @@ QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2) # Input HEADERS += mthread.h mthreadpool.h -HEADERS += mythsocket.h mythsocket_cb.h mythsocketthread.h msocketdevice.h +HEADERS += mythsocket.h mythsocket_cb.h HEADERS += mythbaseexp.h mythdbcon.h mythdb.h mythdbparams.h oldsettings.h HEADERS += verbosedefs.h mythversion.h compat.h mythconfig.h HEADERS += mythobservable.h mythevent.h httpcomms.h mcodecs.h @@ -28,7 +28,7 @@ HEADERS += plist.h bswap.h signalhandling.h mythtimezone.h mythdate.h HEADERS += ffmpeg-mmx.h SOURCES += mthread.cpp mthreadpool.cpp -SOURCES += mythsocket.cpp mythsocketthread.cpp msocketdevice.cpp +SOURCES += mythsocket.cpp SOURCES += mythdbcon.cpp mythdb.cpp mythdbparams.cpp oldsettings.cpp SOURCES += mythobservable.cpp mythevent.cpp httpcomms.cpp mcodecs.cpp SOURCES += mythdirs.cpp mythsignalingtimer.cpp @@ -42,9 +42,8 @@ SOURCES += referencecounter.cpp mythcommandlineparser.cpp SOURCES += filesysteminfo.cpp hardwareprofile.cpp serverpool.cpp SOURCES += plist.cpp signalhandling.cpp mythtimezone.cpp mythdate.cpp -win32:SOURCES += msocketdevice_win.cpp unix { - SOURCES += msocketdevice_unix.cpp system-unix.cpp + SOURCES += system-unix.cpp HEADERS += system-unix.h QMAKE_CXXFLAGS += -fno-strict-aliasing } @@ -60,7 +59,7 @@ inc.files = mythdbcon.h mythdbparams.h mythbaseexp.h mythdb.h inc.files += compat.h mythversion.h mythconfig.h mythconfig.mak version.h inc.files += mythobservable.h mythevent.h httpcomms.h mcodecs.h verbosedefs.h inc.files += mythtimer.h lcddevice.h exitcodes.h mythdirs.h mythstorage.h -inc.files += mythsocket.h mythsocket_cb.h msocketdevice.h mythlogging.h +inc.files += mythsocket.h mythsocket_cb.h mythlogging.h inc.files += mythcorecontext.h mythsystem.h storagegroup.h loggingserver.h inc.files += mythcoreutil.h mythlocale.h mythdownloadmanager.h inc.files += mythtranslation.h iso639.h iso3166.h mythmedia.h mythmiscutil.h diff --git a/mythtv/libs/libmythbase/mythcorecontext.cpp b/mythtv/libs/libmythbase/mythcorecontext.cpp index 6c7de40a42e..708b1f25afb 100644 --- a/mythtv/libs/libmythbase/mythcorecontext.cpp +++ b/mythtv/libs/libmythbase/mythcorecontext.cpp @@ -29,7 +29,6 @@ using namespace std; #include "compat.h" #include "mythconfig.h" // for CONFIG_DARWIN #include "mythdownloadmanager.h" -#include "mythsocketthread.h" #include "mythcorecontext.h" #include "mythsocket.h" #include "mythsystem.h" @@ -114,21 +113,26 @@ MythCoreContextPrivate::MythCoreContextPrivate(MythCoreContext *lparent, srandom(MythDate::current().toTime_t() ^ QTime::currentTime().msec()); } +static void delete_sock(QMutexLocker &locker, MythSocket **s) +{ + if (*s) + { + MythSocket *tmp = *s; + *s = NULL; + locker.unlock(); + tmp->DecrRef(); + locker.relock(); + } +} + MythCoreContextPrivate::~MythCoreContextPrivate() { MThreadPool::StopAllPools(); - ShutdownRRT(); - QMutexLocker locker(&m_sockLock); - if (m_serverSock) - { - m_serverSock->DecrRef(); - m_serverSock = NULL; - } - if (m_eventSock) { - m_eventSock->DecrRef(); - m_eventSock = NULL; + QMutexLocker locker(&m_sockLock); + delete_sock(locker, &m_serverSock); + delete_sock(locker, &m_eventSock); } delete m_locale; @@ -264,15 +268,15 @@ bool MythCoreContext::SetupCommandSocket(MythSocket *serverSock, QStringList strlist(announcement); - if (!serverSock->writeStringList(strlist)) + if (!serverSock->WriteStringList(strlist)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Connecting server socket to " "master backend, socket write failed"); return false; } - if (!serverSock->readStringList(strlist, true) || strlist.empty() || - (strlist[0] == "ERROR")) + if (!serverSock->ReadStringList(strlist, MythSocket::kShortTimeout) || + strlist.empty() || (strlist[0] == "ERROR")) { if (!strlist.empty()) LOG(VB_GENERAL, LOG_ERR, LOC + "Problem connecting " @@ -304,6 +308,12 @@ bool MythCoreContext::ConnectToMasterServer(bool blockingClient, int port = GetNumSetting("MasterServerPort", 6543); bool proto_mismatch = false; + if (d->m_serverSock && !d->m_serverSock->IsConnected()) + { + d->m_serverSock->DecrRef(); + d->m_serverSock = NULL; + } + if (!d->m_serverSock) { QString ann = QString("ANN %1 %2 %3") @@ -321,18 +331,27 @@ bool MythCoreContext::ConnectToMasterServer(bool blockingClient, if (!openEventSocket) return true; - if (!IsBackend() && !d->m_eventSock) - d->m_eventSock = ConnectEventSocket(server, port); - if (!IsBackend() && !d->m_eventSock) + if (!IsBackend()) { - d->m_serverSock->DecrRef(); - d->m_serverSock = NULL; + if (d->m_eventSock && !d->m_eventSock->IsConnected()) + { + d->m_eventSock->DecrRef(); + d->m_eventSock = NULL; + } + if (!d->m_eventSock) + d->m_eventSock = ConnectEventSocket(server, port); - QCoreApplication::postEvent( - d->m_GUIcontext, new MythEvent("CONNECTION_FAILURE")); + if (!d->m_eventSock) + { + d->m_serverSock->DecrRef(); + d->m_serverSock = NULL; - return false; + QCoreApplication::postEvent( + d->m_GUIcontext, new MythEvent("CONNECTION_FAILURE")); + + return false; + } } return true; @@ -377,7 +396,7 @@ MythSocket *MythCoreContext::ConnectCommandSocket( serverSock = new MythSocket(); int sleepms = 0; - if (serverSock->connect(hostname, port)) + if (serverSock->ConnectToHost(hostname, port)) { if (SetupCommandSocket( serverSock, announce, setup_timeout, proto_mismatch)) @@ -456,16 +475,11 @@ MythSocket *MythCoreContext::ConnectCommandSocket( MythSocket *MythCoreContext::ConnectEventSocket(const QString &hostname, int port) { - MythSocket *eventSock = new MythSocket(); - - while (eventSock->state() != MythSocket::Idle) - { - usleep(5000); - } + MythSocket *eventSock = new MythSocket(-1, this); // Assume that since we _just_ connected the command socket, // this one won't need multiple retries to work... - if (!eventSock->connect(hostname, port)) + if (!eventSock->ConnectToHost(hostname, port)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to connect event " "socket to master backend"); @@ -473,14 +487,12 @@ MythSocket *MythCoreContext::ConnectEventSocket(const QString &hostname, return NULL; } - eventSock->Lock(); - QString str = QString("ANN Monitor %1 %2") .arg(d->m_localHostname).arg(true); QStringList strlist(str); - eventSock->writeStringList(strlist); + eventSock->WriteStringList(strlist); bool ok = true; - if (!eventSock->readStringList(strlist) || strlist.empty() || + if (!eventSock->ReadStringList(strlist) || strlist.empty() || (strlist[0] == "ERROR")) { if (!strlist.empty()) @@ -496,13 +508,7 @@ MythSocket *MythCoreContext::ConnectEventSocket(const QString &hostname, ok = false; } - eventSock->Unlock(); - - if (ok) - { - eventSock->setCallbacks(this); - } - else + if (!ok) { eventSock->DecrRef(); eventSock = NULL; @@ -526,11 +532,9 @@ void MythCoreContext::BlockShutdown(void) return; strlist << "BLOCK_SHUTDOWN"; - d->m_serverSock->writeStringList(strlist); - d->m_serverSock->readStringList(strlist); + d->m_serverSock->SendReceiveStringList(strlist); - if ((d->m_eventSock == NULL) || - (d->m_eventSock->state() != MythSocket::Connected)) + if (!d->m_eventSock || !d->m_eventSock->IsConnected()) return; d->m_blockingClient = true; @@ -538,12 +542,7 @@ void MythCoreContext::BlockShutdown(void) strlist.clear(); strlist << "BLOCK_SHUTDOWN"; - d->m_eventSock->Lock(); - - d->m_eventSock->writeStringList(strlist); - d->m_eventSock->readStringList(strlist); - - d->m_eventSock->Unlock(); + d->m_eventSock->SendReceiveStringList(strlist); } void MythCoreContext::AllowShutdown(void) @@ -555,11 +554,9 @@ void MythCoreContext::AllowShutdown(void) return; strlist << "ALLOW_SHUTDOWN"; - d->m_serverSock->writeStringList(strlist); - d->m_serverSock->readStringList(strlist); + d->m_serverSock->SendReceiveStringList(strlist); - if ((d->m_eventSock == NULL) || - (d->m_eventSock->state() != MythSocket::Connected)) + if (!d->m_eventSock || !d->m_eventSock->IsConnected()) return; d->m_blockingClient = false; @@ -567,12 +564,7 @@ void MythCoreContext::AllowShutdown(void) strlist.clear(); strlist << "ALLOW_SHUTDOWN"; - d->m_eventSock->Lock(); - - d->m_eventSock->writeStringList(strlist); - d->m_eventSock->readStringList(strlist); - - d->m_eventSock->Unlock(); + d->m_eventSock->SendReceiveStringList(strlist); } bool MythCoreContext::IsBlockingClient(void) const @@ -721,12 +713,12 @@ QString MythCoreContext::GetMasterHostPrefix(const QString &storageGroup, if (d->m_serverSock) { - ret = GenMythURL(d->m_serverSock->peerAddress().toString(), - d->m_serverSock->peerPort(), + ret = GenMythURL(d->m_serverSock->GetPeerAddress().toString(), + d->m_serverSock->GetPeerPort(), path, storageGroup); } - + return ret; } @@ -934,17 +926,17 @@ bool MythCoreContext::IsUIThread(void) return is_current_thread(d->m_UIThread); } -bool MythCoreContext::SendReceiveStringList(QStringList &strlist, - bool quickTimeout, bool block) +bool MythCoreContext::SendReceiveStringList( + QStringList &strlist, bool quickTimeout, bool block) { + QString msg; if (HasGUI() && IsUIThread()) { - QString msg = "SendReceiveStringList("; + msg = "SendReceiveStringList("; for (uint i=0; i<(uint)strlist.size() && i<2; i++) msg += (i?",":"") + strlist[i]; msg += (strlist.size() > 2) ? "...)" : ")"; - msg += " called from UI thread"; - LOG(VB_GENERAL, LOG_DEBUG, msg); + LOG(VB_GENERAL, LOG_WARNING, msg + " called from UI thread"); } QString query_type = "UNKNOWN"; @@ -964,8 +956,9 @@ bool MythCoreContext::SendReceiveStringList(QStringList &strlist, if (d->m_serverSock) { QStringList sendstrlist = strlist; - d->m_serverSock->writeStringList(sendstrlist); - ok = d->m_serverSock->readStringList(strlist, quickTimeout); + uint timeout = quickTimeout ? + MythSocket::kShortTimeout : MythSocket::kLongTimeout; + ok = d->m_serverSock->SendReceiveStringList(strlist, 0, timeout); if (!ok) { @@ -985,8 +978,8 @@ bool MythCoreContext::SendReceiveStringList(QStringList &strlist, if (d->m_serverSock) { - d->m_serverSock->writeStringList(sendstrlist); - ok = d->m_serverSock->readStringList(strlist, quickTimeout); + ok = d->m_serverSock->SendReceiveStringList( + strlist, 0, timeout); } } @@ -1001,7 +994,7 @@ bool MythCoreContext::SendReceiveStringList(QStringList &strlist, MythEvent me(message, strlist); dispatch(me); - ok = d->m_serverSock->readStringList(strlist, quickTimeout); + ok = d->m_serverSock->ReadStringList(strlist, timeout); } if (!ok) @@ -1090,11 +1083,13 @@ void MythCoreContext::SendHostSystemEvent(const QString &msg, void MythCoreContext::readyRead(MythSocket *sock) { - while (sock->state() == MythSocket::Connected && - sock->bytesAvailable() > 0) + do { QStringList strlist; - if (!sock->readStringList(strlist)) + if (!sock->ReadStringList(strlist)) + continue; + + if (strlist.size() < 2) continue; QString prefix = strlist[0]; @@ -1124,6 +1119,7 @@ void MythCoreContext::readyRead(MythSocket *sock) dispatch(me); } } + while (sock->IsDataAvailable()); } void MythCoreContext::connectionClosed(MythSocket *sock) @@ -1133,20 +1129,7 @@ void MythCoreContext::connectionClosed(MythSocket *sock) LOG(VB_GENERAL, LOG_NOTICE, "Event socket closed. No connection to the backend."); - QMutexLocker locker(&d->m_sockLock); - if (d->m_serverSock) - { - d->m_serverSock->DecrRef(); - d->m_serverSock = NULL; - } - - if (d->m_eventSock) - { - d->m_eventSock->DecrRef(); - d->m_eventSock = NULL; - } - - dispatch(MythEvent(QString("BACKEND_SOCKETS_CLOSED"))); + dispatch(MythEvent("BACKEND_SOCKETS_CLOSED")); } bool MythCoreContext::CheckProtoVersion(MythSocket *socket, uint timeout_ms, @@ -1157,9 +1140,9 @@ bool MythCoreContext::CheckProtoVersion(MythSocket *socket, uint timeout_ms, QStringList strlist(QString("MYTH_PROTO_VERSION %1 %2") .arg(MYTH_PROTO_VERSION).arg(MYTH_PROTO_TOKEN)); - socket->writeStringList(strlist); + socket->WriteStringList(strlist); - if (!socket->readStringList(strlist, timeout_ms) || strlist.empty()) + if (!socket->ReadStringList(strlist, timeout_ms) || strlist.empty()) { LOG(VB_GENERAL, LOG_CRIT, "Protocol version check failure.\n\t\t\t" "The response to MYTH_PROTO_VERSION was empty.\n\t\t\t" diff --git a/mythtv/libs/libmythbase/mythmiscutil.cpp b/mythtv/libs/libmythbase/mythmiscutil.cpp index 299047ce4c4..e2f569f3d04 100644 --- a/mythtv/libs/libmythbase/mythmiscutil.cpp +++ b/mythtv/libs/libmythbase/mythmiscutil.cpp @@ -265,7 +265,7 @@ bool telnet(const QString &host, int port) { MythSocket *s = new MythSocket(); - bool connected = s->connect(host, port); + bool connected = s->ConnectToHost(host, port); s->DecrRef(); return connected; diff --git a/mythtv/libs/libmythbase/mythsocket.cpp b/mythtv/libs/libmythbase/mythsocket.cpp index 212e3c87da0..566a0bf30ae 100644 --- a/mythtv/libs/libmythbase/mythsocket.cpp +++ b/mythtv/libs/libmythbase/mythsocket.cpp @@ -1,309 +1,623 @@ -// ANSI C -#include -#include -#include - -#include "compat.h" - -// POSIX -#ifndef USING_MINGW -#include // for select -#endif - // Qt -#include -#include #include // for QNetworkInterface::allAddresses () -#include // for QAbstractSocket::NetworkLayerProtocol -#include #include +#include +#include +#include +#include +#include +#include +#include // MythTV -#include "mythsocketthread.h" #include "mythsocket.h" #include "mythtimer.h" -#include "mythsocket.h" #include "mythevent.h" #include "mythversion.h" #include "mythlogging.h" #include "mythcorecontext.h" -#define SLOC(a) QString("MythSocket(%1:%2): ")\ - .arg((uint64_t)a, 0, 16).arg(a->socket()) +#define SLOC(a) QString("MythSocket(%1:%2): ") \ + .arg((intptr_t)(a), 0, 16) \ + .arg(a->GetSocketDescriptor()) #define LOC SLOC(this) -const uint MythSocket::kSocketBufferSize = 128000; +const uint MythSocket::kSocketBufferSize = 128 * 1024; const uint MythSocket::kShortTimeout = kMythSocketShortTimeout; const uint MythSocket::kLongTimeout = kMythSocketLongTimeout; -QMutex MythSocket::s_readyread_thread_lock; -MythSocketThread *MythSocket::s_readyread_thread = NULL; - -QMap MythSocket::s_loopback_cache; +QMutex MythSocket::s_loopbackCacheLock; +QHash MythSocket::s_loopbackCache; + +QMutex MythSocket::s_thread_lock; +MThread *MythSocket::s_thread = NULL; +int MythSocket::s_thread_cnt = 0; + +Q_DECLARE_METATYPE ( const QStringList * ); +Q_DECLARE_METATYPE ( QStringList * ); +Q_DECLARE_METATYPE ( const char * ); +Q_DECLARE_METATYPE ( char * ); +Q_DECLARE_METATYPE ( int * ); +static int x0 = qRegisterMetaType< const QStringList * >(); +static int x1 = qRegisterMetaType< QStringList * >(); +static int x2 = qRegisterMetaType< const char * >(); +static int x3 = qRegisterMetaType< char * >(); +static int x4 = qRegisterMetaType< int * >(); + +static QString to_sample(const QByteArray &payload) +{ + QString sample(""); + for (uint i = 0; (i<60) && (i<(uint)payload.length()); i++) + { + sample += QChar(payload.data()[i]).isPrint() ? + QChar(payload.data()[i]) : QChar('?'); + } + sample += (payload.length() > 60) ? "..." : ""; + return sample; +} -MythSocket::MythSocket(int socket, MythSocketCBs *cb) : - MSocketDevice(MSocketDevice::Stream), +MythSocket::MythSocket(int socket, MythSocketCBs *cb, bool use_shared_thread) : ReferenceCounter(QString("MythSocket(%1)").arg(socket)), - m_cb(cb), m_useReadyReadCallback(true), - m_state(Idle), - m_addr(), m_port(0), - m_notifyread(false), m_expectingreply(false), - m_isValidated(false), m_isAnnounced(false) + m_tcpSocket(new QTcpSocket()), + m_thread(NULL), + m_socketDescriptor(-1), + m_callback(cb), + m_useSharedThread(use_shared_thread), + m_disableReadyReadCallback(false), + m_connected(false), + m_dataAvailable(false), + m_isValidated(false), + m_isAnnounced(false) { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "new socket"); + LOG(VB_SOCKET, LOG_INFO, LOC + QString("MythSocket(%1, 0x%2) ctor") + .arg(socket).arg((intptr_t)(cb),0,16)); + + // Use direct connections so m_tcpSocket can be used + // in the handlers safely since they will be running + // in the same thread as all other m_tcpSocket users. + + connect(m_tcpSocket, SIGNAL(connected()), + this, SLOT(ConnectHandler()), + Qt::DirectConnection); + connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(ErrorHandler(QAbstractSocket::SocketError)), + Qt::DirectConnection); + connect(m_tcpSocket, SIGNAL(aboutToClose()), + this, SLOT(AboutToCloseHandler())); + connect(m_tcpSocket, SIGNAL(disconnected()), + this, SLOT(DisconnectHandler()), + Qt::DirectConnection); + connect(m_tcpSocket, SIGNAL(readyRead()), + this, SLOT(ReadyReadHandler()), + Qt::DirectConnection); + + connect(this, SIGNAL(CallReadyRead()), + this, SLOT(CallReadyReadHandler()), + Qt::QueuedConnection); if (socket > -1) { - setSocket(socket); -#ifdef USING_MINGW - // Windows sockets' default buffersize is too small for streaming - // Could this apply to other platforms, too? - setSendBufferSize(kSocketBufferSize); -#endif + m_tcpSocket->setSocketDescriptor( + socket, QAbstractSocket::ConnectedState, + QAbstractSocket::ReadWrite); + + ConnectHandler(); // already called implicitly above? } - if (!s_readyread_thread) + if (!use_shared_thread) { - QMutexLocker locker(&s_readyread_thread_lock); - if (!s_readyread_thread) - s_readyread_thread = new MythSocketThread(); + m_thread = new MThread(QString("MythSocketThread(%1)").arg(socket)); + m_thread->start(); + } + else + { + QMutexLocker locker(&s_thread_lock); + if (!s_thread) + { + s_thread = new MThread("SharedMythSocketThread"); + s_thread->start(); + } + m_thread = s_thread; + s_thread_cnt++; } - if (m_cb) - s_readyread_thread->AddToReadyRead(this); + m_tcpSocket->moveToThread(m_thread->qthread()); + moveToThread(m_thread->qthread()); } MythSocket::~MythSocket() { - close(); - LOG(VB_SOCKET, LOG_DEBUG, LOC + "delete socket"); + LOG(VB_SOCKET, LOG_INFO, LOC + QString("MythSocket dtor : cb 0x%2") + .arg((intptr_t)(m_callback),0,16)); + + if (IsConnected()) + DisconnectFromHost(); + + if (!m_useSharedThread) + { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + } + else + { + QMutexLocker locker(&s_thread_lock); + s_thread_cnt--; + if (0 == s_thread_cnt) + { + s_thread->quit(); + s_thread->wait(); + delete s_thread; + s_thread = NULL; + } + } + m_thread = NULL; + + delete m_tcpSocket; + m_tcpSocket = NULL; } -void MythSocket::setCallbacks(MythSocketCBs *cb) +void MythSocket::ConnectHandler(void) { - if (m_cb && cb) { - m_cb = cb; - return; + QMutexLocker locker(&m_lock); + m_connected = true; + m_socketDescriptor = m_tcpSocket->socketDescriptor(); + m_peerAddress = m_tcpSocket->peerAddress(); + m_peerPort = m_tcpSocket->peerPort(); } - m_cb = cb; + m_tcpSocket->setSocketOption(QAbstractSocket::LowDelayOption, QVariant(1)); + m_tcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1)); - if (m_cb) - s_readyread_thread->AddToReadyRead(this); - else - s_readyread_thread->RemoveFromReadyRead(this); + if (m_callback) + { + LOG(VB_SOCKET, LOG_DEBUG, LOC + + "calling m_callback->connected()"); + m_callback->connected(this); + } } -int MythSocket::DecrRef(void) +void MythSocket::ErrorHandler(QAbstractSocket::SocketError err) { - int ref = ReferenceCounter::DecrRef(); + // Filter these out, we get them because we call waitForReadyRead with a + // small timeout so we can print our own debugging for long timeouts. + if (err == QAbstractSocket::SocketTimeoutError) + return; + + if (m_callback) + { + LOG(VB_SOCKET, LOG_DEBUG, LOC + + "calling m_callback->error() err: " + m_tcpSocket->errorString()); + m_callback->error(this, (int)err); + } +} - if (m_cb && ref == 1) +void MythSocket::DisconnectHandler(void) +{ { - m_cb = NULL; - s_readyread_thread->RemoveFromReadyRead(this); - // ready read thread will call DecrRef() & delete obj + QMutexLocker locker(&m_lock); + m_connected = false; + m_socketDescriptor = -1; + m_peerAddress.clear(); + m_peerPort = -1; } - return ref; + if (m_callback) + { + LOG(VB_SOCKET, LOG_DEBUG, LOC + + "calling m_callback->connectionClosed()"); + m_callback->connectionClosed(this); + } } -MythSocket::State MythSocket::state(void) const +void MythSocket::AboutToCloseHandler(void) { - return m_state; + LOG(VB_SOCKET, LOG_DEBUG, LOC + "AboutToClose"); } -void MythSocket::setState(const State state) +void MythSocket::ReadyReadHandler(void) { - if (state != m_state) + m_dataAvailable = true; + if (m_callback && !m_disableReadyReadCallback) { - LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("state change %1 -> %2") - .arg(stateToString(m_state)).arg(stateToString(state))); - - m_state = state; + emit CallReadyRead(); } } -QString MythSocket::stateToString(const State state) const +void MythSocket::CallReadyReadHandler(void) +{ + LOG(VB_SOCKET, LOG_DEBUG, LOC + + "calling m_callback->readyRead()"); + m_callback->readyRead(this); +} + +bool MythSocket::ConnectToHost( + const QHostAddress &hadr, quint16 port) +{ + bool ret = false; + QMetaObject::invokeMethod( + this, "ConnectToHostReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection, + Q_ARG(QHostAddress, hadr), + Q_ARG(quint16, port), + Q_ARG(bool*, &ret)); + return ret; +} + +bool MythSocket::WriteStringList(const QStringList &list) +{ + bool ret = false; + QMetaObject::invokeMethod( + this, "WriteStringListReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection, + Q_ARG(const QStringList*, &list), + Q_ARG(bool*, &ret)); + return ret; +} + +bool MythSocket::ReadStringList(QStringList &list, uint timeoutMS) +{ + bool ret = false; + QMetaObject::invokeMethod( + this, "ReadStringListReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection, + Q_ARG(QStringList*, &list), + Q_ARG(uint, timeoutMS), + Q_ARG(bool*, &ret)); + return ret; +} + +bool MythSocket::SendReceiveStringList( + QStringList &strlist, uint min_reply_length, uint timeoutMS) { - switch(state) + if (!WriteStringList(strlist)) { - case Connected: - return "Connected"; - case Connecting: - return "Connecting"; - case HostLookup: - return "HostLookup"; - case Idle: - return "Idle"; - default: - return QString("Invalid State: %1").arg(state); + LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to send command."); + return false; + } + + if (!ReadStringList(strlist, timeoutMS)) + { + LOG(VB_GENERAL, LOG_ERR, LOC + "No response."); + return false; + } + + if (min_reply_length && ((uint)strlist.size() < min_reply_length)) + { + LOG(VB_GENERAL, LOG_ERR, LOC + "Response too short."); + return false; + } + + if (!strlist.empty() && strlist[0] == "BACKEND_MESSAGE") + { + LOG(VB_GENERAL, LOG_ERR, LOC + "Got MythEvent on non-event socket"); + return false; } + + return true; } -QString MythSocket::errorToString(const Error error) const +/** + * \brief connect to host + * \return true on success + */ +bool MythSocket::ConnectToHost(const QString &host, quint16 port) { - switch(error) + QHostAddress hadr; + + // attempt direct assignment + if (!hadr.setAddress(host)) { - case NoError: - return "NoError"; - case AlreadyBound: - return "AlreadyBound"; - case Inaccessible: - return "Inaccessible"; - case NoResources: - return "NoResources"; - case InternalError: - return "InternalError"; - case Impossible: - return "Impossible"; - case NoFiles: - return "NoFiles"; - case ConnectionRefused: - return "ConnectionRefused"; - case NetworkFailure: - return "NetworkFailure"; - case UnknownError: - return "UnknownError"; - default: - return QString("Invalid error: %1").arg(error); + // attempt internal lookup through MythCoreContext + if (!gCoreContext || + !hadr.setAddress(gCoreContext->GetBackendServerIP(host))) + { + // attempt external lookup from hosts/DNS + QHostInfo info = QHostInfo::fromName(host); + if (!info.addresses().isEmpty()) + { + hadr = info.addresses().first(); + } + else + { + LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to lookup: %1") + .arg(host)); + return false; + } + } } + + return MythSocket::ConnectToHost(hadr, port); } -void MythSocket::setSocket(int socket, Type type) +bool MythSocket::Validate(uint timeout_ms, bool error_dialog_desired) { - LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("setSocket: %1").arg(socket)); - if (socket < 0) + if (m_isValidated) + return true; + + QStringList strlist(QString("MYTH_PROTO_VERSION %1 %2") + .arg(MYTH_PROTO_VERSION).arg(MYTH_PROTO_TOKEN)); + + WriteStringList(strlist); + + if (!ReadStringList(strlist, timeout_ms) || strlist.empty()) { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "setSocket called with invalid socket"); - return; + LOG(VB_GENERAL, LOG_ERR, "Protocol version check failure.\n\t\t\t" + "The response to MYTH_PROTO_VERSION was empty.\n\t\t\t" + "This happens when the backend is too busy to respond,\n\t\t\t" + "or has deadlocked due to bugs or hardware failure."); + return m_isValidated; } - if (state() == Connected) + if (strlist[0] == "REJECT" && (strlist.size() >= 2)) { - LOG(VB_SOCKET, LOG_DEBUG, LOC + - "setSocket called while in Connected state, closing"); - close(); + LOG(VB_GENERAL, LOG_ERR, + QString("Protocol version or token mismatch " + "(frontend=%1/%2,backend=%3/\?\?)\n") + .arg(MYTH_PROTO_VERSION).arg(MYTH_PROTO_TOKEN).arg(strlist[1])); + + QObject *GUIcontext = gCoreContext->GetGUIObject(); + if (error_dialog_desired && GUIcontext) + { + QStringList list(strlist[1]); + QCoreApplication::postEvent( + GUIcontext, new MythEvent("VERSION_MISMATCH", list)); + } + } + else if (strlist[0] == "ACCEPT") + { + LOG(VB_GENERAL, LOG_NOTICE, QString("Using protocol version %1") + .arg(MYTH_PROTO_VERSION)); + m_isValidated = true; + } + else + { + LOG(VB_GENERAL, LOG_ERR, + QString("Unexpected response to MYTH_PROTO_VERSION: %1") + .arg(strlist[0])); } - MSocketDevice::setSocket(socket, type); - setBlocking(false); - setState(Connected); - setKeepalive(true); + return m_isValidated; } -void MythSocket::close(void) +bool MythSocket::Announce(const QStringList &new_announce) { - setState(Idle); - MSocketDevice::close(); - if (m_cb) + if (!m_isValidated) { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "calling m_cb->connectionClosed()"); - m_cb->connectionClosed(this); + LOG(VB_GENERAL, LOG_ERR, LOC + + "refusing to announce unvalidated socket"); + return false; } + + if (m_isAnnounced) + { + LOG(VB_GENERAL, LOG_ERR, LOC + "refusing to re-announce socket"); + return false; + } + + WriteStringList(new_announce); + + QStringList tmplist; + if (!ReadStringList(tmplist, true)) + { + LOG(VB_GENERAL, LOG_ERR, LOC + + QString("\n\t\t\tCould not read string list from server %1:%2") + .arg(m_tcpSocket->peerAddress().toString()) + .arg(m_tcpSocket->peerPort())); + m_announce.clear(); + m_isAnnounced = false; + } + else + { + m_announce = new_announce; + m_isAnnounced = true; + } + + return m_isAnnounced; } -bool MythSocket::closedByRemote(void) +void MythSocket::SetAnnounce(const QStringList &new_announce) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(socket(), &rfds); + m_announce = new_announce; + m_isAnnounced = true; +} - struct timeval to; - to.tv_sec = 0; - to.tv_usec = 1000; +void MythSocket::DisconnectFromHost(void) +{ + QMetaObject::invokeMethod( + this, "DisconnectFromHostReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection); +} - int rval = select(socket() + 1, &rfds, NULL, NULL, &to); +int MythSocket::Write(const char *data, int size) +{ + int ret = -1; + QMetaObject::invokeMethod( + this, "WriteReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection, + Q_ARG(const char*, data), + Q_ARG(int, size), + Q_ARG(int*, &ret)); + return ret; +} - if (rval > 0 && FD_ISSET(socket(), &rfds) && !bytesAvailable()) - return true; +int MythSocket::Read(char *data, int size, int max_wait_ms) +{ + int ret = -1; + QMetaObject::invokeMethod( + this, "ReadReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection, + Q_ARG(char*, data), + Q_ARG(int, size), + Q_ARG(int, max_wait_ms), + Q_ARG(int*, &ret)); + return ret; +} - return false; +void MythSocket::Reset(void) +{ + QMetaObject::invokeMethod( + this, "ResetReal", + (QThread::currentThread() != m_thread->qthread()) ? + Qt::BlockingQueuedConnection : Qt::DirectConnection); } -qint64 MythSocket::readBlock(char *data, quint64 len) +////////////////////////////////////////////////////////////////////////// + +bool MythSocket::IsConnected(void) const { - LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("readBlock(0x%1, %2) called") - .arg((uint64_t)data,0,16).arg(len)); + QMutexLocker locker(&m_lock); + return m_connected; +} - if (state() != Connected) - { - LOG(VB_SOCKET, LOG_ERR, LOC + "readBlock called while not in " - "connected state"); - return -1; - } +bool MythSocket::IsDataAvailable(void) const +{ + if (QThread::currentThread() == m_thread->qthread()) + return m_tcpSocket->bytesAvailable() > 0; - m_notifyread = false; + if (!m_dataAvailable) + return false; - qint64 rval = MSocketDevice::readBlock(data, len); - if (rval == 0) - close(); + bool ret = false; - return rval; + QMetaObject::invokeMethod( + const_cast(this), "IsDataAvailableReal", + Qt::BlockingQueuedConnection, + Q_ARG(bool*, &ret)); + + return ret; } -/** - * \brief Attempt to write 'len' bytes to socket - * \return actual bytes written - */ -qint64 MythSocket::writeBlock(const char *data, quint64 len) +int MythSocket::GetSocketDescriptor(void) const +{ + QMutexLocker locker(&m_lock); + return m_socketDescriptor; +} + +QHostAddress MythSocket::GetPeerAddress(void) const { - LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("writeBlock(0x%1, %2)") - .arg((uint64_t)data, 0, 16).arg(len)); + QMutexLocker locker(&m_lock); + return m_peerAddress; +} - if (state() != Connected) +int MythSocket::GetPeerPort(void) const +{ + QMutexLocker locker(&m_lock); + return m_peerPort; +} + +////////////////////////////////////////////////////////////////////////// + +void MythSocket::IsDataAvailableReal(bool *ret) const +{ + *ret = (m_tcpSocket->bytesAvailable() > 0); +} + +void MythSocket::ConnectToHostReal(QHostAddress addr, quint16 port, bool *ret) +{ + if (m_tcpSocket->state() == QAbstractSocket::ConnectedState) { - LOG(VB_SOCKET, LOG_ERR, LOC + "writeBlock called while not in " - "connected state"); - return -1; + LOG(VB_SOCKET, LOG_ERR, LOC + + "connect() called with already open socket, closing"); + m_tcpSocket->close(); } - qint64 rval = MSocketDevice::writeBlock(data, len); + s_loopbackCacheLock.lock(); + bool usingLoopback = s_loopbackCache.contains(addr.toString()); + s_loopbackCacheLock.unlock(); - // see if socket went away - if (!isValid() || error() != MSocketDevice::NoError) + if (usingLoopback) { - close(); - return -1; + addr = QHostAddress(s_loopbackCache.value(addr.toString())); } - return rval; -} + else + { + QList localIPs = QNetworkInterface::allAddresses(); + for (int i = 0; i < localIPs.count() && !usingLoopback; ++i) + { + if (addr == localIPs[i]) + { + QHostAddress::SpecialAddress loopback = QHostAddress::LocalHost; + if (addr.protocol() == QAbstractSocket::IPv6Protocol) + loopback = QHostAddress::LocalHostIPv6; -static QString toSample(const QByteArray &payload) -{ - QString sample(""); - for (uint i = 0; (i<60) && (i<(uint)payload.length()); i++) + QMutexLocker locker(&s_loopbackCacheLock); + s_loopbackCache[addr.toString()] = loopback; + addr = QHostAddress(loopback); + usingLoopback = true; + } + } + } + + if (usingLoopback) { - sample += QChar(payload.data()[i]).isPrint() ? - QChar(payload.data()[i]) : QChar('?'); + LOG(VB_SOCKET, LOG_INFO, LOC + + "IP is local, using loopback address instead"); } - sample += (payload.length() > 60) ? "..." : ""; - return sample; + + LOG(VB_SOCKET, LOG_INFO, LOC + QString("attempting connect() to (%1:%2)") + .arg(addr.toString()).arg(port)); + + m_tcpSocket->connectToHost(addr, port, QAbstractSocket::ReadWrite); + + //setReceiveBufferSize(kSocketBufferSize); + //setAddressReusable(true); + + bool ok = m_tcpSocket->waitForConnected(); + + if (ok) + { + LOG(VB_SOCKET, LOG_INFO, LOC + QString("Connected to (%1:%2)") + .arg(addr.toString()).arg(port)); + } + else + { + LOG(VB_GENERAL, LOG_ERR, LOC + + QString("Failed to connect to (%1:%2) %3") + .arg(addr.toString()).arg(port) + .arg(m_tcpSocket->errorString())); + } + + *ret = ok; } -bool MythSocket::writeStringList(QStringList &list) +void MythSocket::DisconnectFromHostReal(void) { - if (list.size() <= 0) + m_tcpSocket->disconnectFromHost(); +} + +void MythSocket::WriteStringListReal(const QStringList *list, bool *ret) +{ + if (list->empty()) { LOG(VB_GENERAL, LOG_ERR, LOC + - "writeStringList: Error, invalid string list."); - return false; + "WriteStringList: Error, invalid string list."); + *ret = false; + return; } - if (state() != Connected) + if (m_tcpSocket->state() != QAbstractSocket::ConnectedState) { LOG(VB_GENERAL, LOG_ERR, LOC + - "writeStringList: Error, called with unconnected socket."); - return false; + "WriteStringList: Error, called with unconnected socket."); + *ret = false; + return; } - QString str = list.join("[]:[]"); + QString str = list->join("[]:[]"); if (str.isEmpty()) { LOG(VB_GENERAL, LOG_ERR, LOC + - "writeStringList: Error, joined null string."); - return false; + "WriteStringList: Error, joined null string."); + *ret = false; + return; } QByteArray utf8 = str.toUtf8(); @@ -321,7 +635,7 @@ bool MythSocket::writeStringList(QStringList &list) if (VERBOSE_LEVEL_CHECK(VB_NETWORK, LOG_INFO)) { QString msg = QString("write -> %1 %2") - .arg(socket(), 2).arg(payload.data()); + .arg(m_tcpSocket->socketDescriptor(), 2).arg(payload.data()); if (logLevel < LOG_DEBUG && msg.length() > 88) { @@ -335,17 +649,18 @@ bool MythSocket::writeStringList(QStringList &list) unsigned int errorcount = 0; while (size > 0) { - if (state() != Connected) + if (m_tcpSocket->state() != QAbstractSocket::ConnectedState) { LOG(VB_GENERAL, LOG_ERR, LOC + - "writeStringList: Error, socket went unconnected." + + "WriteStringList: Error, socket went unconnected." + QString("\n\t\t\tWe wrote %1 of %2 bytes with %3 errors") .arg(written).arg(written+size).arg(errorcount) + - QString("\n\t\t\tstarts with: %1").arg(toSample(payload))); - return false; + QString("\n\t\t\tstarts with: %1").arg(to_sample(payload))); + *ret = false; + return; } - int temp = writeBlock(payload.data() + written, size); + int temp = m_tcpSocket->write(payload.data() + written, size); if (temp > 0) { written += temp; @@ -357,210 +672,70 @@ bool MythSocket::writeStringList(QStringList &list) written_since_timer_restart = 0; } } - else if (temp < 0 && error() != MSocketDevice::NoError) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("writeStringList: Error, writeBlock failed. (%1)") - .arg(errorToString())); - return false; - } else if (temp <= 0) { errorcount++; if (timer.elapsed() > 1000) { - LOG(VB_GENERAL, LOG_ERR, LOC + "writeStringList: Error, " + - QString("No data written on writeBlock (%1 errors)") + LOG(VB_GENERAL, LOG_ERR, LOC + "WriteStringList: Error, " + + QString("No data written on write (%1 errors)") .arg(errorcount) + - QString("\n\t\t\tstarts with: %1") .arg(toSample(payload))); - return false; + QString("\n\t\t\tstarts with: %1") + .arg(to_sample(payload))); + *ret = false; + return; } usleep(1000); } } - flush(); + m_tcpSocket->flush(); - return true; + *ret = true; + return; } -/** - * \brief Read len bytes to data from socket - * \return true if desired len of data is read - */ -bool MythSocket::readData(char *data, quint64 len) +void MythSocket::ReadStringListReal( + QStringList *list, uint timeoutMS, bool *ret) { - if (state() != Connected) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "readData: Error, called with unconnected socket."); - return false; - } - - quint64 bytes_read = 0; - uint zerocnt = 0; - - while (bytes_read < len) - { - qint64 btw = len - bytes_read >= kSocketBufferSize ? - kSocketBufferSize : len - bytes_read; - qint64 sret = readBlock(data + bytes_read, btw); - if (sret > 0) - { - zerocnt = 0; - bytes_read += sret; - } - else if (!isValid()) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "readData: Error, socket went unconnected"); - close(); - return false; - } - else if (sret < 0 && error() != MSocketDevice::NoError) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("readData: Error, readBlock: %1") - .arg(errorToString())); - close(); - return false; - } - else - { - zerocnt++; - if (zerocnt > 5000) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "readData: Error, zerocnt timeout"); - return false; - } - usleep(1000); - } - } - return true; -} - -/** - * \brief Write len bytes to data to socket - * \return true if entire len of data is written - */ -bool MythSocket::writeData(const char *data, quint64 len) -{ - if (state() != Connected) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "writeData: Error, called with unconnected socket."); - return false; - } - - quint64 written = 0; - uint zerocnt = 0; - - while (written < len) - { - qint64 btw = len - written >= kSocketBufferSize ? - kSocketBufferSize : len - written; - qint64 sret = writeBlock(data + written, btw); - if (sret > 0) - { - zerocnt = 0; - written += sret; - } - else if (!isValid()) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "writeData: Error, socket went unconnected"); - close(); - return false; - } - else if (sret < 0 && error() != MSocketDevice::NoError) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("writeData: Error, writeBlock: %1") - .arg(errorToString())); - close(); - return false; - } - else - { - zerocnt++; - if (zerocnt > 5000) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "writeData: Error, zerocnt timeout"); - return false; - } - usleep(1000); - } - } - return true; -} - -bool MythSocket::readStringList(QStringList &list, uint timeoutMS) -{ - list.clear(); - - if (state() != Connected) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "readStringList: Error, called with unconnected socket."); - return false; - } + list->clear(); + *ret = false; MythTimer timer; timer.start(); int elapsed = 0; - while (waitForMore(5) < 8) + while (m_tcpSocket->bytesAvailable() < 8) { elapsed = timer.elapsed(); if (elapsed >= (int)timeoutMS) { - LOG(VB_GENERAL, LOG_ERR, LOC + "readStringList: " + + LOG(VB_GENERAL, LOG_ERR, LOC + "ReadStringList: " + QString("Error, timed out after %1 ms.").arg(timeoutMS)); - close(); - return false; + m_tcpSocket->close(); + m_dataAvailable = false; + return; } - if (state() != Connected) + if (m_tcpSocket->state() != QAbstractSocket::ConnectedState) { - LOG(VB_GENERAL, LOG_ERR, LOC + "readStringList: Connection died."); - return false; + LOG(VB_GENERAL, LOG_ERR, LOC + "ReadStringList: Connection died."); + m_dataAvailable = false; + return; } - { - struct timeval tv; - int maxfd; - fd_set rfds; - - FD_ZERO(&rfds); - FD_SET(socket(), &rfds); - maxfd = socket(); - - tv.tv_sec = 0; - tv.tv_usec = 0; - - int rval = select(maxfd + 1, &rfds, NULL, NULL, &tv); - if (rval) - { - if (bytesAvailable() == 0) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "readStringList: Connection died (select)."); - return false; - } - } - } + m_tcpSocket->waitForReadyRead(50); } QByteArray sizestr(8 + 1, '\0'); - if (readBlock(sizestr.data(), 8) < 0) + if (m_tcpSocket->read(sizestr.data(), 8) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + - QString("readStringList: Error, readBlock return error (%1)") - .arg(errorToString())); - close(); - return false; + QString("ReadStringList: Error, read return error (%1)") + .arg(m_tcpSocket->errorString())); + m_tcpSocket->close(); + m_dataAvailable = false; + return; } QString sizes = sizestr; @@ -568,48 +743,62 @@ bool MythSocket::readStringList(QStringList &list, uint timeoutMS) if (btr < 1) { - int pending = bytesAvailable(); - QByteArray dump(pending + 1, 0); - readBlock(dump.data(), pending); + int pending = m_tcpSocket->bytesAvailable(); LOG(VB_GENERAL, LOG_ERR, LOC + QString("Protocol error: '%1' is not a valid size " "prefix. %2 bytes pending.") .arg(sizestr.data()).arg(pending)); - return false; + ResetReal(); + return; } QByteArray utf8(btr + 1, 0); - qint64 read = 0; + qint64 readoffset = 0; int errmsgtime = 0; timer.start(); while (btr > 0) { - qint64 sret = readBlock(utf8.data() + read, btr); + if (m_tcpSocket->bytesAvailable() < 1) + { + if (m_tcpSocket->state() == QAbstractSocket::ConnectedState) + { + m_tcpSocket->waitForReadyRead(50); + } + else + { + LOG(VB_GENERAL, LOG_ERR, LOC + + "ReadStringList: Connection died."); + m_dataAvailable = false; + return; + } + } + + qint64 sret = m_tcpSocket->read(utf8.data() + readoffset, btr); if (sret > 0) { - read += sret; + readoffset += sret; btr -= sret; if (btr > 0) { timer.start(); } } - else if (sret < 0 && error() != MSocketDevice::NoError) + else if (sret < 0) { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("readStringList: Error, readBlock %1") - .arg(errorToString())); - close(); - return false; + LOG(VB_GENERAL, LOG_ERR, LOC + "ReadStringList: Error, read"); + m_tcpSocket->close(); + m_dataAvailable = false; + return; } - else if (!isValid()) + else if (!m_tcpSocket->isValid()) { LOG(VB_GENERAL, LOG_ERR, LOC + - "readStringList: Error, socket went unconnected"); - close(); - return false; + "ReadStringList: Error, socket went unconnected"); + m_tcpSocket->close(); + m_dataAvailable = false; + return; } else { @@ -620,19 +809,18 @@ bool MythSocket::readStringList(QStringList &list, uint timeoutMS) { errmsgtime = elapsed; LOG(VB_GENERAL, LOG_ERR, LOC + - QString("readStringList: Waiting for data: %1 %2") - .arg(read).arg(btr)); + QString("ReadStringList: Waiting for data: %1 %2") + .arg(readoffset).arg(btr)); } } if (elapsed > 100000) { LOG(VB_GENERAL, LOG_ERR, LOC + - "Error, readStringList timeout (readBlock)"); - return false; + "Error, ReadStringList timeout (readBlock)"); + m_dataAvailable = false; + return; } - - usleep(500); } } @@ -646,7 +834,8 @@ bool MythSocket::readStringList(QStringList &list, uint timeoutMS) if (VERBOSE_LEVEL_CHECK(VB_NETWORK, LOG_INFO)) { - QString msg = QString("read <- %1 %2").arg(socket(), 2) + QString msg = QString("read <- %1 %2") + .arg(m_tcpSocket->socketDescriptor(), 2) .arg(payload.data()); if (logLevel < LOG_DEBUG && msg.length() > 88) @@ -657,277 +846,58 @@ bool MythSocket::readStringList(QStringList &list, uint timeoutMS) LOG(VB_NETWORK, LOG_INFO, LOC + msg); } - list = str.split("[]:[]"); - - m_notifyread = false; - s_readyread_thread->WakeReadyReadThread(); - return true; -} - -bool MythSocket::SendReceiveStringList( - QStringList &strlist, uint min_reply_length) -{ - bool ok = false; - - Lock(); - m_expectingreply = true; - - writeStringList(strlist); - ok = readStringList(strlist); - - while (ok && strlist[0] == "BACKEND_MESSAGE") - { - // not for us - // TODO: sockets should be one directional - // a socket that would use this call should never - // receive events - if (strlist.size() >= 2) - { - QString message = strlist[1]; - strlist.pop_front(); - strlist.pop_front(); - MythEvent me(message, strlist); - gCoreContext->dispatch(me); - } - - ok = readStringList(strlist); - } - - m_expectingreply = false; - Unlock(); - - if (!ok) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "No response."); - return false; - } - - if (min_reply_length && ((uint)strlist.size() < min_reply_length)) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Response too short."); - return false; - } - - return true; -} - -void MythSocket::Lock(void) const -{ - m_lock.lock(); - s_readyread_thread->WakeReadyReadThread(); -} - -bool MythSocket::TryLock(bool wake_readyread) const -{ - if (m_lock.tryLock()) - { - if (wake_readyread) - s_readyread_thread->WakeReadyReadThread(); - return true; - } - return false; -} - -void MythSocket::Unlock(bool wake_readyread) const -{ - m_lock.unlock(); - if (wake_readyread) - s_readyread_thread->WakeReadyReadThread(); -} - -/** - * \brief connect to host - * \return true on success - */ -bool MythSocket::connect(const QString &host, quint16 port) -{ - QHostAddress hadr; + *list = str.split("[]:[]"); - // attempt direct assignment - if (!hadr.setAddress(host)) - { - // attempt internal lookup through MythCoreContext - if (!gCoreContext || - !hadr.setAddress(gCoreContext->GetBackendServerIP(host))) - { - // attempt external lookup from hosts/DNS - QHostInfo info = QHostInfo::fromName(host); - if (!info.addresses().isEmpty()) - { - hadr = info.addresses().first(); - } - else - { - LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to lookup: %1") - .arg(host)); - return false; - } - } - } + m_dataAvailable = (m_tcpSocket->bytesAvailable() > 0); - return MythSocket::connect(hadr, port); + *ret = true; } -/** - * \brief connect to host - * \return true on success - */ -bool MythSocket::connect(const QHostAddress &hadr, quint16 port) +void MythSocket::WriteReal(const char *data, int size, int *ret) { - QHostAddress addr = hadr; - - if (state() == Connected) - { - LOG(VB_SOCKET, LOG_ERR, LOC + - "connect() called with already open socket, closing"); - close(); - } - - bool usingLoopback = false; - if (s_loopback_cache.contains(addr.toString())) - { - addr = QHostAddress(s_loopback_cache.value(addr.toString())); - usingLoopback = true; - } - else - { - QList localIPs = QNetworkInterface::allAddresses(); - for (int i = 0; i < localIPs.count() && !usingLoopback; ++i) - { - if (addr == localIPs[i]) - { - QHostAddress::SpecialAddress loopback = QHostAddress::LocalHost; - if (addr.protocol() == QAbstractSocket::IPv6Protocol) - loopback = QHostAddress::LocalHostIPv6; - - s_loopback_cache[addr.toString()] = loopback; - addr = QHostAddress(loopback); - usingLoopback = true; - } - } - } - - if (usingLoopback) - LOG(VB_SOCKET, LOG_INFO, LOC + QString("IP is local, using " - "loopback address instead")); - - LOG(VB_SOCKET, LOG_INFO, LOC + QString("attempting connect() to (%1:%2)") - .arg(addr.toString()).arg(port)); - - if (!MSocketDevice::connect(addr, port)) - { - LOG(VB_SOCKET, LOG_ERR, LOC + QString("connect() failed (%1)") - .arg(errorToString())); - setState(Idle); - return false; - } - - setReceiveBufferSize(kSocketBufferSize); - setAddressReusable(true); - setKeepalive(true); - if (state() == Connecting) - { - setState(Connected); - if (m_cb) - { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "calling m_cb->connected()"); - m_cb->connected(this); - s_readyread_thread->WakeReadyReadThread(); - } - } - else - { - setState(Connected); - } - - return true; + *ret = m_tcpSocket->write(data, size); } -bool MythSocket::Validate(uint timeout_ms, bool error_dialog_desired) +void MythSocket::ReadReal(char *data, int size, int max_wait_ms, int *ret) { - if (m_isValidated) - return true; - - QStringList strlist(QString("MYTH_PROTO_VERSION %1 %2") - .arg(MYTH_PROTO_VERSION).arg(MYTH_PROTO_TOKEN)); - writeStringList(strlist); - - if (!readStringList(strlist, timeout_ms) || strlist.empty()) + MythTimer t; t.start(); + while ((m_tcpSocket->state() == QAbstractSocket::ConnectedState) && + (m_tcpSocket->bytesAvailable() < size) && + (t.elapsed() < max_wait_ms)) { - LOG(VB_GENERAL, LOG_ERR, "Protocol version check failure.\n\t\t\t" - "The response to MYTH_PROTO_VERSION was empty.\n\t\t\t" - "This happens when the backend is too busy to respond,\n\t\t\t" - "or has deadlocked due to bugs or hardware failure."); - return false; + m_tcpSocket->waitForReadyRead(max(2, max_wait_ms - t.elapsed())); } - else if (strlist[0] == "REJECT" && strlist.size() >= 2) - { - LOG(VB_GENERAL, LOG_ERR, QString("Protocol version or token mismatch " - "(frontend=%1/%2," - "backend=%3/\?\?)\n") - .arg(MYTH_PROTO_VERSION) - .arg(MYTH_PROTO_TOKEN) - .arg(strlist[1])); + *ret = m_tcpSocket->read(data, size); - QObject *GUIcontext = gCoreContext->GetGUIObject(); - if (error_dialog_desired && GUIcontext) - { - QStringList list(strlist[1]); - QCoreApplication::postEvent( - GUIcontext, new MythEvent("VERSION_MISMATCH", list)); - } - - return false; - } - else if (strlist[0] == "ACCEPT") + if ((t.elapsed() > 50) || (*ret < size)) { - LOG(VB_GENERAL, LOG_NOTICE, QString("Using protocol version %1") - .arg(MYTH_PROTO_VERSION)); - setValidated(); - return true; + LOG(VB_GENERAL, LOG_INFO, + QString("ReadReal(?, %1, %2) -> %3 took %4 ms") + .arg(size).arg(max_wait_ms).arg(*ret) + .arg(t.elapsed())); } - LOG(VB_GENERAL, LOG_ERR, - QString("Unexpected response to MYTH_PROTO_VERSION: %1") - .arg(strlist[0])); - return false; + m_dataAvailable = (m_tcpSocket->bytesAvailable() > 0); } -bool MythSocket::Announce(QStringList &strlist) +void MythSocket::ResetReal(void) { - if (!m_isValidated) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "refusing to announce unvalidated socket"); - } + vector trash; - if (m_isAnnounced) + m_tcpSocket->waitForReadyRead(30); + do { - LOG(VB_GENERAL, LOG_ERR, LOC + "refusing to re-announce socket"); - return false; - } + uint avail = m_tcpSocket->bytesAvailable(); + trash.resize(max((uint)trash.size(),avail)); + m_tcpSocket->read(&trash[0], avail); - m_announce << strlist; + LOG(VB_NETWORK, LOG_INFO, LOC + "Reset() " + + QString("%1 bytes available").arg(avail)); - writeStringList(strlist); - strlist.clear(); - - if (!readStringList(strlist, true)) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("\n\t\t\tCould not read string list from server %1:%2") - .arg(m_addr.toString()).arg(m_port)); - m_announce.clear(); - return false; + m_tcpSocket->waitForReadyRead(30); } + while (m_tcpSocket->bytesAvailable() > 0); - m_isAnnounced = true; - return true; + m_dataAvailable = false; } -void MythSocket::setAnnounce(QStringList &strlist) -{ - m_announce.clear(); - m_announce << strlist; - m_isAnnounced = true; -} diff --git a/mythtv/libs/libmythbase/mythsocket.h b/mythtv/libs/libmythbase/mythsocket.h index 18967da2010..8ce7c7f591f 100644 --- a/mythtv/libs/libmythbase/mythsocket.h +++ b/mythtv/libs/libmythbase/mythsocket.h @@ -1,117 +1,122 @@ /** -*- Mode: c++ -*- */ -#ifndef MYTHSOCKET_H -#define MYTHSOCKET_H +#ifndef MYTH_SOCKET_H +#define MYTH_SOCKET_H +#include #include #include +#include #include "referencecounter.h" -#include "msocketdevice.h" #include "mythsocket_cb.h" #include "mythbaseexp.h" - -template -class QList; -class QString; -class QHostAddress; -class MythSocketThread; - -class MBASE_PUBLIC MythSocket : - public MSocketDevice, public ReferenceCounter +#include "mthread.h" + +class QTcpSocket; + +/** \brief Class for communcating between myth backends and frontends + * + * \note Access to the methods of MythSocket must be externally + * serialized (i.e. the MythSocket must only be available to one + * thread at a time). + * + */ +class MBASE_PUBLIC MythSocket : public QObject, public ReferenceCounter { - friend class MythSocketThread; - friend class QList; - friend void ShutdownRRT(void); + Q_OBJECT + + friend class MythSocketManager; public: - MythSocket(int socket = -1, MythSocketCBs *cb = NULL); - - enum State { - Connected, - Connecting, - HostLookup, - Idle - }; - - void close(void); - bool closedByRemote(void); - void deleteLater(void); - - virtual int DecrRef(void); // ReferenceCounter - - State state(void) const; - QString stateToString(void) const { return stateToString(state()); } - QString stateToString(const State state) const; - - QString errorToString(void) const { return errorToString(error()); } - QString errorToString(const Error error) const; - - bool Validate(uint timeout_ms = kMythSocketLongTimeout, - bool error_dialog_desired = false); - void setValidated(bool isValidated=true) { m_isValidated = isValidated; } - bool isValidated(void) { return m_isValidated; } - - bool Announce(QStringList &strlist); - QStringList getAnnounce(void) { return m_announce; } - void setAnnounce(QStringList &strlist); - bool isAnnounced(void) { return m_isAnnounced; } - - bool isExpectingReply(void) { return m_expectingreply; } - - void setSocket(int socket, Type type = MSocketDevice::Stream); - void setCallbacks(MythSocketCBs *cb); - void useReadyReadCallback(bool useReadyReadCallback = true) - { m_useReadyReadCallback = useReadyReadCallback; } - - qint64 readBlock(char *data, quint64 len); - qint64 writeBlock(const char *data, quint64 len); - - bool readStringList(QStringList &list, uint timeoutMS = kLongTimeout); - bool readStringList(QStringList &list, bool quicTimeout) - { - return readStringList( - list, quicTimeout ? kShortTimeout : kLongTimeout); - } - bool writeStringList(QStringList &list); - bool SendReceiveStringList(QStringList &list, uint min_reply_length = 0); - bool readData(char *data, quint64 len); - bool writeData(const char *data, quint64 len); - - bool connect(const QHostAddress &hadr, quint16 port); - bool connect(const QString &host, quint16 port); - - void Lock(void) const; - bool TryLock(bool wakereadyread) const; - void Unlock(bool wakereadyread = true) const; + MythSocket(int socket = -1, MythSocketCBs *cb = NULL, + bool use_shared_thread = false); + + bool ConnectToHost(const QString &hostname, quint16 port); + bool ConnectToHost(const QHostAddress &address, quint16 port); + void DisconnectFromHost(void); + + bool Validate(uint timeout_ms = kMythSocketLongTimeout, + bool error_dialog_desired = false); + bool IsValidated(void) const { return m_isValidated; } + + bool Announce(const QStringList &strlist); + QStringList GetAnnounce(void) const { return m_announce; } + void SetAnnounce(const QStringList &strlist); + bool IsAnnounced(void) const { return m_isAnnounced; } + + void SetReadyReadCallbackEnabled(bool useReadyReadCallback) + { m_disableReadyReadCallback = !useReadyReadCallback; } + + bool SendReceiveStringList( + QStringList &list, uint min_reply_length = 0, + uint timeoutMS = kLongTimeout); + + bool ReadStringList(QStringList &list, uint timeoutMS = kShortTimeout); + bool WriteStringList(const QStringList &list); + + bool IsConnected(void) const; + bool IsDataAvailable(void) const; + + QHostAddress GetPeerAddress(void) const; + int GetPeerPort(void) const; + int GetSocketDescriptor(void) const; + + // RemoteFile stuff + int Write(const char*, int size); + int Read(char*, int size, int max_wait_ms); + void Reset(void); static const uint kShortTimeout; static const uint kLongTimeout; - protected: - ~MythSocket(); // force refcounting + signals: + void CallReadyRead(void); - void setState(const State state); + protected slots: + void ConnectHandler(void); + void ErrorHandler(QAbstractSocket::SocketError); + void AboutToCloseHandler(void); + void DisconnectHandler(void); + void ReadyReadHandler(void); + void CallReadyReadHandler(void); - MythSocketCBs *m_cb; - bool m_useReadyReadCallback; - State m_state; - QHostAddress m_addr; - quint16 m_port; + void ReadStringListReal(QStringList *list, uint timeoutMS, bool *ret); + void WriteStringListReal(const QStringList *list, bool *ret); + void ConnectToHostReal(QHostAddress address, quint16 port, bool *ret); + void DisconnectFromHostReal(void); - bool m_notifyread; - mutable QMutex m_lock; // externally accessible lock + void WriteReal(const char*, int size, int *ret); + void ReadReal(char*, int size, int max_wait_ms, int *ret); + void ResetReal(void); - bool m_expectingreply; - bool m_isValidated; - bool m_isAnnounced; - QStringList m_announce; + void IsDataAvailableReal(bool *ret) const; + + protected: + ~MythSocket(); // force reference counting + + QTcpSocket *m_tcpSocket; // only set in ctor + MThread *m_thread; // only set in ctor + mutable QMutex m_lock; + int m_socketDescriptor; // protected by m_lock + QHostAddress m_peerAddress; // protected by m_lock + int m_peerPort; // protected by m_lock + MythSocketCBs *m_callback; // only set in ctor + bool m_useSharedThread; // only set in ctor + volatile bool m_disableReadyReadCallback; + bool m_connected; // protected by m_lock + volatile bool m_dataAvailable; + bool m_isValidated; // only set in thread using MythSocket + bool m_isAnnounced; // only set in thread using MythSocket + QStringList m_announce; // only set in thread using MythSocket static const uint kSocketBufferSize; - static QMutex s_readyread_thread_lock; - static MythSocketThread *s_readyread_thread; - - static QMap s_loopback_cache; -}; -#endif + static QMutex s_loopbackCacheLock; + static QHash s_loopbackCache; + + static QMutex s_thread_lock; + static MThread *s_thread; // protected by s_thread_lock + static int s_thread_cnt; // protected by s_thread_lock +}; +#endif /* MYTH_SOCKET_H */ diff --git a/mythtv/libs/libmythbase/mythsocket_cb.h b/mythtv/libs/libmythbase/mythsocket_cb.h index e965ad4f23e..07067eb96bd 100644 --- a/mythtv/libs/libmythbase/mythsocket_cb.h +++ b/mythtv/libs/libmythbase/mythsocket_cb.h @@ -13,6 +13,7 @@ class MBASE_PUBLIC MythSocketCBs public: virtual ~MythSocketCBs() {} virtual void connected(MythSocket*) = 0; + virtual void error(MythSocket*, int) {} virtual void readyRead(MythSocket*) = 0; virtual void connectionFailed(MythSocket*) = 0; virtual void connectionClosed(MythSocket*) = 0; diff --git a/mythtv/libs/libmythbase/mythsocketthread.cpp b/mythtv/libs/libmythbase/mythsocketthread.cpp deleted file mode 100644 index 2b75e1c375c..00000000000 --- a/mythtv/libs/libmythbase/mythsocketthread.cpp +++ /dev/null @@ -1,389 +0,0 @@ -// ANSI C -#include - -// C++ -#include // for min/max -//using namespace std; - -#include "compat.h" - -// POSIX -#ifndef USING_MINGW -#include // for select -#endif -#include // for fnctl -#include // for fnctl -#include // for checking errno - -#ifndef O_NONBLOCK -#define O_NONBLOCK 0 /* not actually supported in MINGW */ -#endif - -// Qt -#include - -// MythTV -#include "mythsocketthread.h" -#include "mythbaseutil.h" -#include "mythlogging.h" -#include "mythsocket.h" - -#define SLOC(a) QString("MythSocketThread(sock 0x%1:%2): ")\ - .arg((uint64_t)a, 0, 16).arg(a->socket()) -#define LOC QString("MythSocketThread: ") - -const uint MythSocketThread::kShortWait = 100; - -MythSocketThread::MythSocketThread() - : MThread("Socket"), m_readyread_run(false) -{ - for (int i = 0; i < 2; i++) - { - m_readyread_pipe[i] = -1; - m_readyread_pipe_flags[i] = 0; - } -} - -void ShutdownRRT(void) -{ - QMutexLocker locker(&MythSocket::s_readyread_thread_lock); - if (MythSocket::s_readyread_thread) - { - MythSocket::s_readyread_thread->ShutdownReadyReadThread(); - MythSocket::s_readyread_thread->wait(); - } -} - -void MythSocketThread::ShutdownReadyReadThread(void) -{ - { - QMutexLocker locker(&m_readyread_lock); - m_readyread_run = false; - } - - WakeReadyReadThread(); - - wait(); // waits for thread to exit - - CloseReadyReadPipe(); -} - -void MythSocketThread::CloseReadyReadPipe(void) const -{ - for (uint i = 0; i < 2; i++) - { - if (m_readyread_pipe[i] >= 0) - { - ::close(m_readyread_pipe[i]); - m_readyread_pipe[i] = -1; - m_readyread_pipe_flags[i] = 0; - } - } -} - -void MythSocketThread::StartReadyReadThread(void) -{ - QMutexLocker locker(&m_readyread_lock); - if (!m_readyread_run) - { - atexit(ShutdownRRT); - setup_pipe(m_readyread_pipe, m_readyread_pipe_flags); - m_readyread_run = true; - start(); - m_readyread_started_wait.wait(&m_readyread_lock); - } -} - -void MythSocketThread::AddToReadyRead(MythSocket *sock) -{ - if (sock->socket() == -1) - { - LOG(VB_SOCKET, LOG_ERR, SLOC(sock) + - "attempted to insert invalid socket to ReadyRead"); - return; - } - StartReadyReadThread(); - - sock->IncrRef(); - - { - QMutexLocker locker(&m_readyread_lock); - m_readyread_addlist.push_back(sock); - } - - WakeReadyReadThread(); -} - -void MythSocketThread::RemoveFromReadyRead(MythSocket *sock) -{ - { - QMutexLocker locker(&m_readyread_lock); - m_readyread_dellist.push_back(sock); - } - WakeReadyReadThread(); -} - -void MythSocketThread::WakeReadyReadThread(void) const -{ - if (!isRunning()) - return; - - QMutexLocker locker(&m_readyread_lock); - m_readyread_wait.wakeAll(); - - if (m_readyread_pipe[1] < 0) - return; - - char buf[1] = { '0' }; - ssize_t wret = 0; - while (wret <= 0) - { - wret = ::write(m_readyread_pipe[1], &buf, 1); - if ((wret < 0) && (EAGAIN != errno) && (EINTR != errno)) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "Failed to write to readyread pipe, closing pipe."); - - // Closing the pipe will cause the run loop's select to exit. - // Then the next time through the loop we should fallback to - // using the code for platforms that don't support pipes.. - CloseReadyReadPipe(); - break; - } - } -} - -void MythSocketThread::ReadyToBeRead(MythSocket *sock) -{ - LOG(VB_SOCKET, LOG_DEBUG, SLOC(sock) + "socket is readable"); - int bytesAvail = sock->bytesAvailable(); - - if (bytesAvail == 0 && sock->closedByRemote()) - { - LOG(VB_SOCKET, LOG_INFO, SLOC(sock) + "socket closed"); - sock->close(); - } - else if (bytesAvail > 0 && sock->m_cb && sock->m_useReadyReadCallback) - { - sock->m_notifyread = true; - LOG(VB_SOCKET, LOG_DEBUG, SLOC(sock) + "calling m_cb->readyRead()"); - sock->m_cb->readyRead(sock); - } -} - -void MythSocketThread::ProcessAddRemoveQueues(void) -{ - while (!m_readyread_dellist.empty()) - { - MythSocket *sock = m_readyread_dellist.front(); - m_readyread_dellist.pop_front(); - - if (m_readyread_list.removeAll(sock)) - m_readyread_downref_list.push_back(sock); - } - - while (!m_readyread_addlist.empty()) - { - MythSocket *sock = m_readyread_addlist.front(); - m_readyread_addlist.pop_front(); - m_readyread_list.push_back(sock); - } -} - -void MythSocketThread::run(void) -{ - RunProlog(); - LOG(VB_SOCKET, LOG_DEBUG, LOC + "readyread thread start"); - - QMutexLocker locker(&m_readyread_lock); - m_readyread_started_wait.wakeAll(); - while (m_readyread_run) - { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "ProcessAddRemoveQueues"); - - ProcessAddRemoveQueues(); - - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Construct FD_SET"); - - // construct FD_SET for all connected and unlocked sockets... - int maxfd = -1; - fd_set rfds; - FD_ZERO(&rfds); - - QList::const_iterator it = m_readyread_list.begin(); - for (; it != m_readyread_list.end(); ++it) - { - if (!(*it)->TryLock(false)) - continue; - - if ((*it)->state() == MythSocket::Connected && - !(*it)->m_notifyread) - { - FD_SET((*it)->socket(), &rfds); - maxfd = std::max((*it)->socket(), maxfd); - } - (*it)->Unlock(false); - } - - // There are no unlocked sockets, wait for event before we continue.. - if (maxfd < 0) - { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Empty FD_SET, sleeping"); - if (m_readyread_wait.wait(&m_readyread_lock)) - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Empty FD_SET, woken up"); - else - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Empty FD_SET, timed out"); - continue; - } - - int rval = 0; - - if (m_readyread_pipe[0] >= 0) - { - // Clear out any pending pipe reads, we have already taken care of - // this event above under the m_readyread_lock. - char dummy[128]; - if (m_readyread_pipe_flags[0] & O_NONBLOCK) - { - rval = ::read(m_readyread_pipe[0], dummy, 128); - FD_SET(m_readyread_pipe[0], &rfds); - maxfd = std::max(m_readyread_pipe[0], maxfd); - } - - // also exit select on exceptions on same descriptors - fd_set efds; - memcpy(&efds, &rfds, sizeof(fd_set)); - - // The select waits forever for data, so if we need to process - // anything else we need to write to m_readyread_pipe[1].. - // We unlock the ready read lock, because we don't need it - // and this will allow WakeReadyReadThread() to run.. - m_readyread_lock.unlock(); - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Waiting on select.."); - rval = select(maxfd + 1, &rfds, NULL, &efds, NULL); - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Got data on select"); - m_readyread_lock.lock(); - - if (rval > 0 && FD_ISSET(m_readyread_pipe[0], &rfds)) - { - int ret = ::read(m_readyread_pipe[0], dummy, 128); - if (ret < 0) - { - LOG(VB_SOCKET, LOG_ERR, LOC + - "Strange.. failed to read event pipe"); - } - } - } - else - { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Waiting on select.. (no pipe)"); - - fd_set savefds; - memcpy(&savefds, &rfds, sizeof(fd_set)); - - // Unfortunately, select on a pipe is not supported on all - // platforms. So we fallback to a loop that instead times out - // of select and checks for wakeAll event. - while (!rval) - { - // also exit select on exceptions on same descriptors - fd_set efds; - memcpy(&efds, &savefds, sizeof(fd_set)); - - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = kShortWait * 1000; - rval = select(maxfd + 1, &rfds, NULL, &efds, &timeout); - if (!rval) - { - m_readyread_wait.wait(&m_readyread_lock, kShortWait); - memcpy(&rfds, &savefds, sizeof(fd_set)); - } - } - - if (rval > 0) - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Got data on select (no pipe)"); - } - - if (rval <= 0) - { - if (rval == 0) - { - // Note: This should never occur when using pipes. When there - // is no error there should be data in at least one fd.. - LOG(VB_SOCKET, LOG_DEBUG, LOC + "select timeout"); - } - else - LOG(VB_SOCKET, LOG_ERR, LOC + "select returned error" + ENO); - - m_readyread_wait.wait(&m_readyread_lock, kShortWait); - continue; - } - - // ReadyToBeRead allows calls back into the socket so we need - // to release the lock for a little while. - // since only this loop updates m_readyread_list this is safe. - m_readyread_lock.unlock(); - - // Actually read some data! This is a form of co-operative - // multitasking so the ready read handlers should be quick.. - - uint downref_tm = 0; - if (!m_readyread_downref_list.empty()) - { - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Deleting stale sockets"); - - QTime tm = QTime::currentTime(); - for (it = m_readyread_downref_list.begin(); - it != m_readyread_downref_list.end(); ++it) - { - (*it)->DecrRef(); - } - m_readyread_downref_list.clear(); - downref_tm = tm.elapsed(); - } - - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Processing ready reads"); - - QMap timers; - QTime tm = QTime::currentTime(); - it = m_readyread_list.begin(); - - for (; it != m_readyread_list.end() && m_readyread_run; ++it) - { - if (!(*it)->TryLock(false)) - continue; - - int socket = (*it)->socket(); - - if (socket >= 0 && - (*it)->state() == MythSocket::Connected && - FD_ISSET(socket, &rfds)) - { - QTime rrtm = QTime::currentTime(); - ReadyToBeRead(*it); - timers[socket] = rrtm.elapsed(); - } - (*it)->Unlock(false); - } - - if (VERBOSE_LEVEL_CHECK(VB_SOCKET, LOG_DEBUG)) - { - QString rep = QString("Total read time: %1ms, on sockets") - .arg(tm.elapsed()); - QMap::const_iterator it = timers.begin(); - for (; it != timers.end(); ++it) - rep += QString(" {%1,%2ms}").arg(it.key()).arg(*it); - if (downref_tm) - rep += QString(" {downref, %1ms}").arg(downref_tm); - - LOG(VB_SOCKET, LOG_DEBUG, LOC + rep); - } - - m_readyread_lock.lock(); - LOG(VB_SOCKET, LOG_DEBUG, LOC + "Reacquired ready read lock"); - } - - LOG(VB_SOCKET, LOG_DEBUG, LOC + "readyread thread exit"); - RunEpilog(); -} diff --git a/mythtv/libs/libmythbase/mythsocketthread.h b/mythtv/libs/libmythbase/mythsocketthread.h deleted file mode 100644 index 5215304067b..00000000000 --- a/mythtv/libs/libmythbase/mythsocketthread.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _MYTH_SOCKET_THREAD_H_ -#define _MYTH_SOCKET_THREAD_H_ - -#include -#include -#include - -#include "mythbaseexp.h" -#include "mthread.h" - -MBASE_PUBLIC void ShutdownRRT(void); - -class MythSocket; -class MythSocketThread : public MThread -{ - public: - MythSocketThread(); - - virtual void run(void); - - void StartReadyReadThread(void); - void WakeReadyReadThread(void) const; - void ShutdownReadyReadThread(void); - - void AddToReadyRead(MythSocket *sock); - void RemoveFromReadyRead(MythSocket *sock); - - private: - void ProcessAddRemoveQueues(void); - void ReadyToBeRead(MythSocket *sock); - void CloseReadyReadPipe(void) const; - - bool m_readyread_run; - mutable QMutex m_readyread_lock; - mutable QWaitCondition m_readyread_wait; - mutable QWaitCondition m_readyread_started_wait; - - mutable int m_readyread_pipe[2]; - mutable long m_readyread_pipe_flags[2]; - - QList m_readyread_list; - QList m_readyread_dellist; - QList m_readyread_addlist; - QList m_readyread_downref_list; - - static const uint kShortWait; -}; - -#endif // _MYTH_SOCKET_THREAD_H_ diff --git a/mythtv/libs/libmythbase/remotefile.cpp b/mythtv/libs/libmythbase/remotefile.cpp index e4824e8658b..d81f7fa8e77 100644 --- a/mythtv/libs/libmythbase/remotefile.cpp +++ b/mythtv/libs/libmythbase/remotefile.cpp @@ -85,7 +85,7 @@ MythSocket *RemoteFile::openSocket(bool control) port = 6543; } - if (!lsock->connect(host, port)) + if (!lsock->ConnectToHost(host, port)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Could not connect to server %1:%2") .arg(host).arg(port)); @@ -110,8 +110,7 @@ MythSocket *RemoteFile::openSocket(bool control) if (control) { strlist.append(QString("ANN Playback %1 %2").arg(hostname).arg(false)); - lsock->writeStringList(strlist); - if (!lsock->readStringList(strlist, true)) + if (!lsock->SendReceiveStringList(strlist)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Could not read string list from server %1:%2") @@ -132,8 +131,7 @@ MythSocket *RemoteFile::openSocket(bool control) for (; it != possibleauxfiles.end(); ++it) strlist << *it; - if (!lsock->writeStringList(strlist) || - !lsock->readStringList(strlist, true)) + if (!lsock->SendReceiveStringList(strlist)) { LOG(VB_GENERAL, LOG_ERR, loc + QString("Did not get proper response from %1:%2") @@ -211,18 +209,14 @@ bool RemoteFile::ReOpen(QString newFilename) return false; } - if (!sock->isOpen() || sock->error()) - return false; - - if (!controlSock->isOpen() || controlSock->error()) - return false; + if (!sock->IsConnected() || !controlSock->IsConnected()) + return -1; QStringList strlist( QString(query).arg(recordernum) ); strlist << "REOPEN"; strlist << newFilename; - controlSock->writeStringList(strlist); - controlSock->readStringList(strlist); + controlSock->SendReceiveStringList(strlist); lock.unlock(); @@ -242,8 +236,8 @@ void RemoteFile::Close(void) strlist << "DONE"; lock.lock(); - controlSock->writeStringList(strlist); - if (!controlSock->readStringList(strlist, true)) + if (!controlSock->SendReceiveStringList( + strlist, 0, MythSocket::kShortTimeout)) { LOG(VB_GENERAL, LOG_ERR, "Remote file timeout."); } @@ -385,39 +379,23 @@ void RemoteFile::Reset(void) LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Reset(): Called with no socket"); return; } - - while (sock && (sock->bytesAvailable() > 0)) - { - int avail; - char *trash; - - avail = sock->bytesAvailable(); - trash = new char[avail + 1]; - sock->readBlock(trash, avail); - delete [] trash; - - LOG(VB_NETWORK, LOG_INFO, - QString ("%1 bytes available during reset.") .arg(avail)); - locker.unlock(); - usleep(30000); - locker.relock(); - } + sock->Reset(); } long long RemoteFile::Seek(long long pos, int whence, long long curpos) { - lock.lock(); + QMutexLocker locker(&lock); + if (!sock) { LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Seek(): Called with no socket"); - return 0; + return -1; } - if (!sock->isOpen() || sock->error()) - return 0; - - if (!controlSock->isOpen() || controlSock->error()) - return 0; + if (!sock->IsConnected() || !controlSock->IsConnected()) + { + return -1; + } QStringList strlist( QString(query).arg(recordernum) ); strlist << "SEEK"; @@ -428,20 +406,16 @@ long long RemoteFile::Seek(long long pos, int whence, long long curpos) else strlist << QString::number(readposition); - controlSock->writeStringList(strlist); - controlSock->readStringList(strlist); - lock.unlock(); + bool ok = controlSock->SendReceiveStringList(strlist); - long long retval = -1; - if (!strlist.empty()) + if (ok && !strlist.empty()) { - retval = strlist[0].toLongLong(); - readposition = retval; + readposition = strlist[0].toLongLong(); + sock->Reset(); + return strlist[0].toLongLong(); } - Reset(); - - return retval; + return -1; } int RemoteFile::Write(const void *data, int size) @@ -466,21 +440,26 @@ int RemoteFile::Write(const void *data, int size) return -1; } - if (!sock->isOpen() || sock->error()) - return -1; - - if (!controlSock->isOpen() || controlSock->error()) + if (!sock->IsConnected() || !controlSock->IsConnected()) + { return -1; + } QStringList strlist( QString(query).arg(recordernum) ); strlist << "WRITE_BLOCK"; strlist << QString::number(size); - controlSock->writeStringList(strlist); + bool ok = controlSock->WriteStringList(strlist); + if (!ok) + { + LOG(VB_NETWORK, LOG_ERR, + "RemoteFile::Write(): Block notification failed"); + return -1; + } recv = size; while (sent < recv && !error && zerocnt++ < 50) { - int ret = sock->writeBlock((char *)data + sent, recv - sent); + int ret = sock->Write((char*)data + sent, recv - sent); if (ret > 0) { sent += ret; @@ -492,19 +471,19 @@ int RemoteFile::Write(const void *data, int size) break; } - if (controlSock->bytesAvailable() > 0) + if (controlSock->IsDataAvailable() && + controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) && + !strlist.empty()) { - if (controlSock->readStringList(strlist, true)) - { - recv = strlist[0].toInt(); // -1 on backend error - response = true; - } + recv = strlist[0].toInt(); // -1 on backend error + response = true; } } if (!error && !response) { - if (controlSock->readStringList(strlist, true)) + if (controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) && + !strlist.empty()) { recv = strlist[0].toInt(); // -1 on backend error } @@ -517,8 +496,8 @@ int RemoteFile::Write(const void *data, int size) } LOG(VB_NETWORK, LOG_DEBUG, - QString("RemoteFile::Write(): reqd=%1, sent=%2, rept=%3, error=%4") - .arg(size).arg(sent).arg(recv).arg(error)); + QString("RemoteFile::Write(): reqd=%1, sent=%2, rept=%3, error=%4") + .arg(size).arg(sent).arg(recv).arg(error)); if (recv < 0) return recv; @@ -543,37 +522,32 @@ int RemoteFile::Read(void *data, int size) return -1; } - if (!sock->isOpen() || sock->error()) - return -1; - - if (!controlSock->isOpen() || controlSock->error()) + if (!sock->IsConnected() || !controlSock->IsConnected()) return -1; - if (sock->bytesAvailable() > 0) + if (sock->IsDataAvailable()) { LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Read socket not empty to start!"); - while (sock->waitForMore(5) > 0) - { - int avail = sock->bytesAvailable(); - char *trash = new char[avail + 1]; - sock->readBlock(trash, avail); - delete [] trash; - } + sock->Reset(); } - if (controlSock->bytesAvailable() > 0) + while (controlSock->IsDataAvailable()) { LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Control socket not empty to start!"); - QStringList tempstrlist; - controlSock->readStringList(tempstrlist); + controlSock->Reset(); } QStringList strlist( QString(query).arg(recordernum) ); strlist << "REQUEST_BLOCK"; strlist << QString::number(size); - controlSock->writeStringList(strlist); + bool ok = controlSock->WriteStringList(strlist); + if (!ok) + { + LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Block request failed"); + return -1; + } sent = size; @@ -583,27 +557,28 @@ int RemoteFile::Read(void *data, int size) while (recv < sent && !error && mtimer.elapsed() < 10000) { - while (recv < sent && sock->waitForMore(waitms) > 0) + MythTimer ctt; // check control socket timer + ctt.start(); + while ((recv < sent) && (ctt.elapsed() < 500)) { - int ret = sock->readBlock(((char *)data) + recv, sent - recv); + int ret = sock->Read( + ((char *)data) + recv, sent - recv, 500); if (ret > 0) { recv += ret; } - else if (sock->error() != MythSocket::NoError) + else if (ret < 0) { - LOG(VB_GENERAL, LOG_ERR, "RemoteFile::Read(): socket error"); error = true; - break; } - if (waitms < 200) waitms += 20; } - if (controlSock->bytesAvailable() > 0) + if (controlSock->IsDataAvailable() && + controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) && + !strlist.empty()) { - controlSock->readStringList(strlist, true); sent = strlist[0].toInt(); // -1 on backend error response = true; } @@ -611,7 +586,8 @@ int RemoteFile::Read(void *data, int size) if (!error && !response) { - if (controlSock->readStringList(strlist, true)) + if (controlSock->ReadStringList(strlist, MythSocket::kShortTimeout) && + !strlist.empty()) { sent = strlist[0].toInt(); // -1 on backend error } @@ -660,18 +636,14 @@ void RemoteFile::SetTimeout(bool fast) return; } - if (!sock->isOpen() || sock->error()) - return; - - if (!controlSock->isOpen() || controlSock->error()) + if (!sock->IsConnected() || !controlSock->IsConnected()) return; QStringList strlist( QString(query).arg(recordernum) ); strlist << "SET_TIMEOUT"; strlist << QString::number((int)fast); - controlSock->writeStringList(strlist); - controlSock->readStringList(strlist); + controlSock->SendReceiveStringList(strlist); timeoutisfast = fast; } diff --git a/mythtv/libs/libmythbase/remotefile.h b/mythtv/libs/libmythbase/remotefile.h index a88bd3437f9..66c3fef7eb1 100644 --- a/mythtv/libs/libmythbase/remotefile.h +++ b/mythtv/libs/libmythbase/remotefile.h @@ -47,11 +47,6 @@ class MBASE_PUBLIC RemoteFile long long GetFileSize(void) const { return filesize; } - const MythSocket *getSocket(void) const - { return sock; } - MythSocket *getSocket(void) - { return sock; } - QStringList GetAuxiliaryFiles(void) const { return auxfiles; } diff --git a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp index 640ede0ebf7..382b36aefd5 100644 --- a/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp +++ b/mythtv/libs/libmythprotoserver/mythsocketmanager.cpp @@ -54,8 +54,7 @@ MythServer::MythServer(QObject *parent) : ServerPool(parent) void MythServer::newTcpConnection(int socket) { - MythSocket *s = new MythSocket(socket); - emit newConnection(s); + emit newConnection(socket); } MythSocketManager::MythSocketManager() : @@ -74,6 +73,13 @@ MythSocketManager::~MythSocketManager() delete *i; m_handlerMap.clear(); + + QMutexLocker locker(&m_socketListLock); + while (!m_socketList.empty()) + { + (*m_socketList.begin())->DecrRef(); + m_socketList.erase(m_socketList.begin()); + } } bool MythSocketManager::Listen(int port) @@ -93,11 +99,17 @@ bool MythSocketManager::Listen(int port) return false; } - connect(m_server, SIGNAL(newConnection(MythSocket *)), - this, SLOT(newConnection(MythSocket *))); + connect(m_server, SIGNAL(newConnection(int)), + this, SLOT(newConnection(int))); return true; } +void MythSocketManager::newConnection(int sd) +{ + QMutexLocker locker(&m_socketListLock); + m_socketList.insert(new MythSocket(sd, this)); +} + void MythSocketManager::RegisterHandler(SocketRequestHandler *handler) { QWriteLocker wlock(&m_handlerLock); @@ -141,12 +153,6 @@ SocketHandler *MythSocketManager::GetConnectionBySocket(MythSocket *sock) void MythSocketManager::readyRead(MythSocket *sock) { - if (sock->isExpectingReply()) - { - LOG(VB_SOCKET, LOG_DEBUG, "Socket marked as expecting reply."); - return; - } - m_threadPool.startReserved( new ProcessRequestRunnable(*this, sock), "ServiceRequest", PRT_TIMEOUT); @@ -154,6 +160,9 @@ void MythSocketManager::readyRead(MythSocket *sock) void MythSocketManager::connectionClosed(MythSocket *sock) { + // TODO We should delete the MythSocket's at some point + // prior to MythSocketManager shutdown... + { QReadLocker rlock(&m_handlerLock); @@ -176,24 +185,17 @@ void MythSocketManager::ProcessRequest(MythSocket *sock) { // used as context manager since MythSocket cannot be used directly // with QMutexLocker - - if (sock->isExpectingReply()) - return; - - sock->Lock(); - if (sock->bytesAvailable() > 0) + if (sock->IsDataAvailable()) { ProcessRequestWork(sock); } - - sock->Unlock(); } void MythSocketManager::ProcessRequestWork(MythSocket *sock) { QStringList listline; - if (!sock->readStringList(listline)) + if (!sock->ReadStringList(listline)) return; QString line = listline[0].simplified(); @@ -209,7 +211,7 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) return; } - if (!sock->isValidated()) + if (!sock->IsValidated()) { // all sockets must be validated against the local protocol version // before any subsequent commands can be run @@ -223,12 +225,12 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) "Use of socket attempted before protocol validation."); listline.clear(); listline << "ERROR" << "socket has not been validated"; - sock->writeStringList(listline); + sock->WriteStringList(listline); } return; } - if (!sock->isAnnounced()) + if (!sock->IsAnnounced()) { // all sockets must be announced before any subsequent commands can // be run @@ -262,7 +264,7 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) LOG(VB_SOCKET, LOG_ERR, LOC + "Socket announce unhandled."); listline.clear(); listline << "ERROR" << "unhandled announce"; - sock->writeStringList(listline); + sock->WriteStringList(listline); } return; @@ -273,7 +275,7 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) "Use of socket attempted before announcement."); listline.clear(); listline << "ERROR" << "socket has not been announced"; - sock->writeStringList(listline); + sock->WriteStringList(listline); } return; } @@ -283,7 +285,7 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) LOG(VB_SOCKET, LOG_ERR, LOC + "ANN sent out of sequence."); listline.clear(); listline << "ERROR" << "socket has already been announced"; - sock->writeStringList(listline); + sock->WriteStringList(listline); return; } @@ -297,7 +299,7 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) LOG(VB_SOCKET, LOG_ERR, LOC + "No handler found for socket."); listline.clear(); listline << "ERROR" << "socket handler cannot be found"; - sock->writeStringList(listline); + sock->WriteStringList(listline); return; } @@ -326,7 +328,7 @@ void MythSocketManager::ProcessRequestWork(MythSocket *sock) listline.clear(); listline << "ERROR" << "unknown command"; - sock->writeStringList(listline); + sock->WriteStringList(listline); } } @@ -341,7 +343,7 @@ void MythSocketManager::HandleVersion(MythSocket *socket, "Client speaks protocol version " + version + " but we speak " + MYTH_PROTO_VERSION + '!'); retlist << "REJECT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); HandleDone(socket); return; } @@ -351,7 +353,7 @@ void MythSocketManager::HandleVersion(MythSocket *socket, LOG(VB_GENERAL, LOG_ERR, LOC + "Client did not pass protocol " "token. Refusing connection!"); retlist << "REJECT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); HandleDone(socket); return; } @@ -362,19 +364,19 @@ void MythSocketManager::HandleVersion(MythSocket *socket, LOG(VB_GENERAL, LOG_ERR, LOC + "Client sent incorrect protocol token " "for protocol version. Refusing connection!"); retlist << "REJECT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); HandleDone(socket); return; } LOG(VB_SOCKET, LOG_DEBUG, LOC + "Client validated"); retlist << "ACCEPT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); - socket->setValidated(); + socket->WriteStringList(retlist); + socket->m_isValidated = true; } void MythSocketManager::HandleDone(MythSocket *sock) { - sock->close(); + sock->DisconnectFromHost(); } diff --git a/mythtv/libs/libmythprotoserver/mythsocketmanager.h b/mythtv/libs/libmythprotoserver/mythsocketmanager.h index b4b4d392883..2fd1a1bceae 100644 --- a/mythtv/libs/libmythprotoserver/mythsocketmanager.h +++ b/mythtv/libs/libmythprotoserver/mythsocketmanager.h @@ -4,10 +4,12 @@ using namespace std; // Qt -#include #include +#include #include +#include #include +#include #include // MythTV @@ -24,7 +26,7 @@ class MythServer : public ServerPool MythServer(QObject *parent=0); signals: - void newConnection(MythSocket *); + void newConnection(int socketDescriptor); protected slots: virtual void newTcpConnection(int socket); @@ -53,7 +55,7 @@ class PROTOSERVER_PUBLIC MythSocketManager : public QObject, public MythSocketCB bool Listen(int port); public slots: - void newConnection(MythSocket *socket) { socket->setCallbacks(this); } + void newConnection(int sd); private: void ProcessRequestWork(MythSocket *socket); @@ -69,5 +71,7 @@ class PROTOSERVER_PUBLIC MythSocketManager : public QObject, public MythSocketCB MythServer *m_server; MThreadPool m_threadPool; + QMutex m_socketListLock; + QSet m_socketList; }; #endif diff --git a/mythtv/libs/libmythprotoserver/requesthandler/basehandler.cpp b/mythtv/libs/libmythprotoserver/requesthandler/basehandler.cpp index 9493a546c98..35c2188afd0 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/basehandler.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/basehandler.cpp @@ -37,7 +37,7 @@ bool BaseRequestHandler::HandleAnnounce(MythSocket *socket, bool normalevents = ( (eventlevel == 1) || (eventlevel == 2)); SocketHandler *handler = new SocketHandler(socket, m_parent, hostname); - socket->setAnnounce(slist); + socket->SetAnnounce(slist); handler->BlockShutdown(blockShutdown); handler->AllowStandardEvents(normalevents); @@ -45,8 +45,7 @@ bool BaseRequestHandler::HandleAnnounce(MythSocket *socket, m_parent->AddSocketHandler(handler); - QStringList sl; sl << "OK"; - handler->SendStringList(sl); + handler->WriteStringList(QStringList("OK")); handler->DecrRef(); handler = NULL; @@ -101,7 +100,7 @@ bool BaseRequestHandler::HandleQueryLoad(SocketHandler *sock) << QString::number(loads[1]) << QString::number(loads[2]); - sock->SendStringList(strlist); + sock->WriteStringList(strlist); return true; } @@ -123,7 +122,7 @@ bool BaseRequestHandler::HandleQueryUptime(SocketHandler *sock) strlist << "Could not determine uptime."; } - sock->SendStringList(strlist); + sock->WriteStringList(strlist); return true; } @@ -138,7 +137,7 @@ bool BaseRequestHandler::HandleQueryHostname(SocketHandler *sock) strlist << gCoreContext->GetHostName(); - sock->SendStringList(strlist); + sock->WriteStringList(strlist); return true; } @@ -163,7 +162,7 @@ bool BaseRequestHandler::HandleQueryMemStats(SocketHandler *sock) << "Could not determine memory stats."; } - sock->SendStringList(strlist); + sock->WriteStringList(strlist); return true; } @@ -179,7 +178,7 @@ bool BaseRequestHandler::HandleQueryTimeZone(SocketHandler *sock) << QString::number(MythTZ::calc_utc_offset()) << MythDate::current_iso_string(true); - sock->SendStringList(strlist); + sock->WriteStringList(strlist); return true; } diff --git a/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp b/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp index 28e612fdb0b..ddaf8375f96 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/fileserverhandler.cpp @@ -184,13 +184,14 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, handler->AllowStandardEvents(true); handler->AllowSystemEvents(true); + handler->WriteStringList(QStringList("OK")); + QWriteLocker wlock(&m_fsLock); m_fsMap.insert(commands[2], handler); m_parent->AddSocketHandler(handler); - slist.clear(); - slist << "OK"; - handler->SendStringList(slist); + handler->DecrRef(); + return true; } return false; @@ -250,7 +251,7 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, "to write to in FileTransfer write command"); slist << "ERROR" << "filetransfer_directory_not_found"; - socket->writeStringList(slist); + socket->WriteStringList(slist); return true; } @@ -262,7 +263,7 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, .arg(qurl.toString())); slist << "ERROR" << "filetransfer_filename_empty"; - socket->writeStringList(slist); + socket->WriteStringList(slist); return true; } @@ -274,7 +275,7 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, .arg(basename)); slist << "ERROR" << "filetransfer_filename_dangerous"; - socket->writeStringList(slist); + socket->WriteStringList(slist); return true; } @@ -291,7 +292,7 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, .arg(filename)); slist << "ERROR" << "filetransfer_filename_is_a_directory"; - socket->writeStringList(slist); + socket->WriteStringList(slist); return true; } @@ -309,7 +310,7 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, .arg(filename)); slist << "ERROR" << "filetransfer_unable_to_create_subdirectory"; - socket->writeStringList(slist); + socket->WriteStringList(slist); return true; } } @@ -323,11 +324,11 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, { QWriteLocker wlock(&m_ftLock); - m_ftMap.insert(socket->socket(), ft); + m_ftMap.insert(socket->GetSocketDescriptor(), ft); } slist << "OK" - << QString::number(socket->socket()) + << QString::number(socket->GetSocketDescriptor()) << QString::number(ft->GetFileSize()); if (checkfiles.size()) @@ -342,8 +343,10 @@ bool FileServerHandler::HandleAnnounce(MythSocket *socket, } } - socket->writeStringList(slist); + socket->WriteStringList(slist); m_parent->AddSocketHandler(ft); + ft->DecrRef(); ft = NULL; + return true; } @@ -405,7 +408,7 @@ bool FileServerHandler::HandleQueryFreeSpace(SocketHandler *socket) for (i = disks.begin(); i != disks.end(); ++i) i->ToStringList(res); - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -441,7 +444,7 @@ bool FileServerHandler::HandleQueryFreeSpaceList(SocketHandler *socket) << QString::number(total) << QString::number(used); - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -462,7 +465,7 @@ bool FileServerHandler::HandleQueryFreeSpaceSummary(SocketHandler *socket) } res << QString::number(total) << QString::number(used); - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -580,7 +583,7 @@ bool FileServerHandler::HandleQueryFileExists(SocketHandler *socket, QString("ERROR checking for file, filename '%1' " "fails sanity checks").arg(filename)); res << ""; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -619,7 +622,7 @@ bool FileServerHandler::HandleQueryFileExists(SocketHandler *socket, else res << "0"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -652,7 +655,7 @@ bool FileServerHandler::HandleQueryFileHash(SocketHandler *socket, QString("ERROR checking for file, filename '%1' " "fails sanity checks").arg(filename)); res << ""; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } break; @@ -711,7 +714,7 @@ bool FileServerHandler::HandleQueryFileHash(SocketHandler *socket, res << hash; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -746,7 +749,7 @@ bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, if (socket) { res << "0"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } return false; @@ -761,7 +764,7 @@ bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, if (socket) { res << "0"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } return false; @@ -773,7 +776,7 @@ bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, if (socket) { res << "1"; - socket->SendStringList(res); + socket->WriteStringList(res); } RunDeleteThread(); deletethread->AddFile(fullfile); @@ -785,7 +788,7 @@ bool FileServerHandler::HandleDeleteFile(SocketHandler *socket, if (socket) { res << "0"; - socket->SendStringList(res); + socket->WriteStringList(res); } } @@ -811,7 +814,7 @@ bool FileServerHandler::HandleGetFileList(SocketHandler *socket, LOG(VB_GENERAL, LOG_ERR, QString("Invalid Request. %1") .arg(slist.join("[]:[]"))); res << "EMPTY LIST"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -867,7 +870,7 @@ bool FileServerHandler::HandleGetFileList(SocketHandler *socket, } } - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -881,7 +884,7 @@ bool FileServerHandler::HandleFileQuery(SocketHandler *socket, LOG(VB_GENERAL, LOG_ERR, QString("Invalid Request. %1") .arg(slist.join("[]:[]"))); res << "EMPTY LIST"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -928,7 +931,7 @@ bool FileServerHandler::HandleFileQuery(SocketHandler *socket, } } - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -959,7 +962,7 @@ bool FileServerHandler::HandleQueryFileTransfer(SocketHandler *socket, << "unknown_file_transfer_socket"; } - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -1042,7 +1045,7 @@ bool FileServerHandler::HandleQueryFileTransfer(SocketHandler *socket, } ft->DecrRef(); - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -1054,7 +1057,7 @@ bool FileServerHandler::HandleDownloadFile(SocketHandler *socket, if (slist.size() != 4) { res << "ERROR" << QString("Bad %1 command").arg(slist[0]); - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -1078,7 +1081,7 @@ bool FileServerHandler::HandleDownloadFile(SocketHandler *socket, LOG(VB_GENERAL, LOG_ERR, QString("Unable to determine directory " "to write to in %1 write command").arg(slist[0])); res << "ERROR" << "downloadfile_directory_not_found"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -1089,7 +1092,7 @@ bool FileServerHandler::HandleDownloadFile(SocketHandler *socket, "filename '%2' does not pass sanity checks.") .arg(slist[0]).arg(filename)); res << "ERROR" << "downloadfile_filename_dangerous"; - socket->SendStringList(res); + socket->WriteStringList(res); return true; } @@ -1118,7 +1121,7 @@ bool FileServerHandler::HandleDownloadFile(SocketHandler *socket, << gCoreContext->GetMasterHostPrefix(storageGroup) + filename; } - socket->SendStringList(res); + socket->WriteStringList(res); return true; } diff --git a/mythtv/libs/libmythprotoserver/requesthandler/messagehandler.cpp b/mythtv/libs/libmythprotoserver/requesthandler/messagehandler.cpp index 9dc4c80581d..391f31abd63 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/messagehandler.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/messagehandler.cpp @@ -53,7 +53,7 @@ bool MessageHandler::HandleInbound(SocketHandler *sock, QStringList &slist) if (slist.size() < 2) { res << "ERROR" << "Insufficient Length"; - sock->SendStringList(res); + sock->WriteStringList(res); return true; } @@ -74,7 +74,7 @@ bool MessageHandler::HandleInbound(SocketHandler *sock, QStringList &slist) } res << "OK"; - sock->SendStringList(res); + sock->WriteStringList(res); return true; } diff --git a/mythtv/libs/libmythprotoserver/requesthandler/outboundhandler.cpp b/mythtv/libs/libmythprotoserver/requesthandler/outboundhandler.cpp index edf8ead9600..430591a314d 100644 --- a/mythtv/libs/libmythprotoserver/requesthandler/outboundhandler.cpp +++ b/mythtv/libs/libmythprotoserver/requesthandler/outboundhandler.cpp @@ -34,18 +34,13 @@ bool OutboundRequestHandler::DoConnectToMaster(void) if (m_socket) m_socket->DecrRef(); - m_socket = new MythSocket(); - - while (m_socket->state() != MythSocket::Idle) - { - usleep(5000); - } + m_socket = new MythSocket(-1, m_parent); QString server = gCoreContext->GetSetting("MasterServerIP", "localhost"); QString hostname = gCoreContext->GetMasterHostName(); int port = gCoreContext->GetNumSetting("MasterServerPort", 6543); - if (!m_socket->connect(server, port)) + if (!m_socket->ConnectToHost(server, port)) { LOG(VB_GENERAL, LOG_ERR, "Failed to connect to master backend."); m_socket->DecrRef(); @@ -53,13 +48,10 @@ bool OutboundRequestHandler::DoConnectToMaster(void) return false; } - m_socket->Lock(); - #ifndef IGNORE_PROTO_VER_MISMATCH if (!m_socket->Validate()) { LOG(VB_GENERAL, LOG_NOTICE, "Unable to confirm protocol version with backend."); - m_socket->Unlock(); m_socket->DecrRef(); m_socket = NULL; return false; @@ -69,7 +61,6 @@ bool OutboundRequestHandler::DoConnectToMaster(void) if (!AnnounceSocket()) { LOG(VB_GENERAL, LOG_NOTICE, "Announcement to upstream master backend failed."); - m_socket->Unlock(); m_socket->DecrRef(); m_socket = NULL; return false; @@ -83,9 +74,6 @@ bool OutboundRequestHandler::DoConnectToMaster(void) handler->DecrRef(); // drop local instance in counter handler = NULL; - m_socket->Unlock(); - m_parent->newConnection(m_socket); // configure callbacks - LOG(VB_GENERAL, LOG_NOTICE, "Connected to master backend."); return true; diff --git a/mythtv/libs/libmythprotoserver/sockethandler.cpp b/mythtv/libs/libmythprotoserver/sockethandler.cpp index 319973969ac..d03deb546ab 100644 --- a/mythtv/libs/libmythprotoserver/sockethandler.cpp +++ b/mythtv/libs/libmythprotoserver/sockethandler.cpp @@ -26,18 +26,12 @@ SocketHandler::~SocketHandler() } } -bool SocketHandler::SendStringList(QStringList &strlist, bool lock) +bool SocketHandler::WriteStringList(const QStringList &strlist) { if (!m_socket) return false; - LOG(VB_GENERAL, LOG_DEBUG, "Locking Socket for write"); - if (lock) m_socket->Lock(); - bool res = m_socket->writeStringList(strlist); - if (lock) m_socket->Unlock(); - LOG(VB_GENERAL, LOG_DEBUG, "UnLocking Socket from write"); - - return res; + return m_socket->WriteStringList(strlist); } bool SocketHandler::SendReceiveStringList(QStringList &strlist, diff --git a/mythtv/libs/libmythprotoserver/sockethandler.h b/mythtv/libs/libmythprotoserver/sockethandler.h index 197b9324cb9..34ee81a0047 100644 --- a/mythtv/libs/libmythprotoserver/sockethandler.h +++ b/mythtv/libs/libmythprotoserver/sockethandler.h @@ -29,7 +29,7 @@ class PROTOSERVER_PUBLIC SocketHandler : public ReferenceCounter MythSocket *GetSocket(void) { return m_socket; } MythSocketManager *GetParent(void) { return m_parent; } - bool SendStringList(QStringList &strlist, bool lock=false); + bool WriteStringList(const QStringList &strlist); bool SendReceiveStringList(QStringList &strlist, uint min_reply_length=0); void BlockShutdown(bool block) { m_blockShutdown = block; } diff --git a/mythtv/libs/libmythprotoserver/sockethandler/filetransfer.cpp b/mythtv/libs/libmythprotoserver/sockethandler/filetransfer.cpp index f760a382d3c..db156c8b904 100644 --- a/mythtv/libs/libmythprotoserver/sockethandler/filetransfer.cpp +++ b/mythtv/libs/libmythprotoserver/sockethandler/filetransfer.cpp @@ -34,7 +34,7 @@ FileTransfer::FileTransfer(QString &filename, MythSocket *remote, pginfo->MarkAsInUse(true, kFileTransferInUseID); if (write) - remote->useReadyReadCallback(false); + remote->SetReadyReadCallbackEnabled(false); } FileTransfer::~FileTransfer() @@ -120,11 +120,11 @@ int FileTransfer::RequestBlock(int size) int request = size - tot; ret = rbuffer->Read(buf, request); - + if (rbuffer->GetStopReads() || ret <= 0) break; - if (!GetSocket()->writeData(buf, (uint)ret)) + if (GetSocket()->Write(buf, (uint)ret) != ret) { tot = -1; break; @@ -157,7 +157,7 @@ int FileTransfer::WriteBlock(int size) { int request = size - tot; - if (!GetSocket()->readData(buf, (uint)request)) + if (GetSocket()->Read(buf, (uint)request, 25 /*ms*/) != request) break; ret = rbuffer->Write(buf, request); diff --git a/mythtv/libs/libmythtv/remoteencoder.cpp b/mythtv/libs/libmythtv/remoteencoder.cpp index 04f63f06d6e..edcf90eac27 100644 --- a/mythtv/libs/libmythtv/remoteencoder.cpp +++ b/mythtv/libs/libmythtv/remoteencoder.cpp @@ -88,7 +88,7 @@ bool RemoteEncoder::SendReceiveStringList( return false; } - if (!controlSock->writeStringList(strlist)) + if (!controlSock->WriteStringList(strlist)) { LOG(VB_GENERAL, LOG_ERR, "RemoteEncoder::SendReceiveStringList(): " "Failed to write data."); @@ -96,7 +96,7 @@ bool RemoteEncoder::SendReceiveStringList( } if (!backendError && - !controlSock->readStringList(strlist, MythSocket::kShortTimeout)) + !controlSock->ReadStringList(strlist, MythSocket::kShortTimeout)) { LOG(VB_GENERAL, LOG_ERR, "RemoteEncoder::SendReceiveStringList(): No response."); diff --git a/mythtv/libs/libmythupnp/libmythupnp.pro b/mythtv/libs/libmythupnp/libmythupnp.pro index b24665d362b..74fbdb1a66e 100644 --- a/mythtv/libs/libmythupnp/libmythupnp.pro +++ b/mythtv/libs/libmythupnp/libmythupnp.pro @@ -18,6 +18,7 @@ QMAKE_CLEAN += version.cpp # Input HEADERS += mmulticastsocketdevice.h mbroadcastsocketdevice.h +HEADERS += msocketdevice.h HEADERS += httprequest.h upnp.h ssdp.h taskqueue.h upnpsubscription.h HEADERS += upnpdevice.h upnptasknotify.h upnptasksearch.h upnputil.h HEADERS += httpserver.h upnpcds.h upnpcdsobjects.h bufferedsocketdevice.h upnpmsrr.h @@ -32,6 +33,9 @@ HEADERS += serializers/jsonSerializer.h serializers/soapSerializer.h HEADERS += serializers/xmlplistSerializer.h SOURCES += mmulticastsocketdevice.cpp +SOURCES += msocketdevice.cpp +unix:SOURCES += msocketdevice_unix.cpp +mingw:SOURCES += msocketdevice_win.cpp SOURCES += httprequest.cpp upnp.cpp ssdp.cpp taskqueue.cpp upnputil.cpp SOURCES += upnpdevice.cpp upnptasknotify.cpp upnptasksearch.cpp SOURCES += httpserver.cpp upnpcds.cpp upnpcdsobjects.cpp bufferedsocketdevice.cpp diff --git a/mythtv/libs/libmythbase/msocketdevice.cpp b/mythtv/libs/libmythupnp/msocketdevice.cpp similarity index 100% rename from mythtv/libs/libmythbase/msocketdevice.cpp rename to mythtv/libs/libmythupnp/msocketdevice.cpp diff --git a/mythtv/libs/libmythbase/msocketdevice.h b/mythtv/libs/libmythupnp/msocketdevice.h similarity index 100% rename from mythtv/libs/libmythbase/msocketdevice.h rename to mythtv/libs/libmythupnp/msocketdevice.h diff --git a/mythtv/libs/libmythbase/msocketdevice_unix.cpp b/mythtv/libs/libmythupnp/msocketdevice_unix.cpp similarity index 100% rename from mythtv/libs/libmythbase/msocketdevice_unix.cpp rename to mythtv/libs/libmythupnp/msocketdevice_unix.cpp diff --git a/mythtv/libs/libmythbase/msocketdevice_win.cpp b/mythtv/libs/libmythupnp/msocketdevice_win.cpp similarity index 100% rename from mythtv/libs/libmythbase/msocketdevice_win.cpp rename to mythtv/libs/libmythupnp/msocketdevice_win.cpp diff --git a/mythtv/programs/mythbackend/encoderlink.cpp b/mythtv/programs/mythbackend/encoderlink.cpp index 2c7bc7684e4..479235ec163 100644 --- a/mythtv/programs/mythbackend/encoderlink.cpp +++ b/mythtv/programs/mythbackend/encoderlink.cpp @@ -81,6 +81,7 @@ EncoderLink::~EncoderLink(void) delete tv; tv = NULL; } + SetSocket(NULL); } /** \fn EncoderLink::SetSocket(PlaybackSock *lsock) diff --git a/mythtv/programs/mythbackend/filetransfer.cpp b/mythtv/programs/mythbackend/filetransfer.cpp index 18d5963591a..310929a9a88 100644 --- a/mythtv/programs/mythbackend/filetransfer.cpp +++ b/mythtv/programs/mythbackend/filetransfer.cpp @@ -33,7 +33,7 @@ FileTransfer::FileTransfer(QString &filename, MythSocket *remote, bool write) : pginfo->MarkAsInUse(true, kFileTransferInUseID); if (write) - remote->useReadyReadCallback(false); + remote->SetReadyReadCallbackEnabled(false); rbuffer->Start(); } @@ -138,7 +138,7 @@ int FileTransfer::RequestBlock(int size) if (rbuffer->GetStopReads() || ret <= 0) break; - if (!sock->writeData(buf, (uint)ret)) + if (sock->Write(buf, (uint)ret) != ret) { tot = -1; break; @@ -171,7 +171,7 @@ int FileTransfer::WriteBlock(int size) { int request = size - tot; - if (!sock->readData(buf, (uint)request)) + if (sock->Read(buf, (uint)request, 25 /*ms */) != request) break; ret = rbuffer->Write(buf, request); diff --git a/mythtv/programs/mythbackend/main_helpers.cpp b/mythtv/programs/mythbackend/main_helpers.cpp index 04ff9746a25..d2c40ece40c 100644 --- a/mythtv/programs/mythbackend/main_helpers.cpp +++ b/mythtv/programs/mythbackend/main_helpers.cpp @@ -25,7 +25,6 @@ #include "tv_rec.h" #include "scheduledrecording.h" -#include "mythsocketthread.h" #include "autoexpire.h" #include "scheduler.h" #include "mainserver.h" @@ -424,7 +423,7 @@ using namespace MythTZ; int connect_to_master(void) { MythSocket *tempMonitorConnection = new MythSocket(); - if (tempMonitorConnection->connect( + if (tempMonitorConnection->ConnectToHost( gCoreContext->GetSetting("MasterServerIP", "127.0.0.1"), gCoreContext->GetNumSetting("MasterServerPort", 6543))) { @@ -438,8 +437,7 @@ int connect_to_master(void) QStringList tempMonitorDone("DONE"); QStringList tempMonitorAnnounce("ANN Monitor tzcheck 0"); - tempMonitorConnection->writeStringList(tempMonitorAnnounce); - tempMonitorConnection->readStringList(tempMonitorAnnounce); + tempMonitorConnection->SendReceiveStringList(tempMonitorAnnounce); if (tempMonitorAnnounce.empty() || tempMonitorAnnounce[0] == "ERROR") { @@ -464,14 +462,13 @@ int connect_to_master(void) if (tempMonitorConnection) { timeCheck.push_back("QUERY_TIME_ZONE"); - tempMonitorConnection->writeStringList(timeCheck); - tempMonitorConnection->readStringList(timeCheck); + tempMonitorConnection->SendReceiveStringList(timeCheck); } if (timeCheck.size() < 3) { return GENERIC_EXIT_SOCKET_ERROR; } - tempMonitorConnection->writeStringList(tempMonitorDone); + tempMonitorConnection->WriteStringList(tempMonitorDone); QDateTime our_time = MythDate::current(); QDateTime master_time = MythDate::fromString(timeCheck[2]); diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp index 6e23d0a0389..bbb67829a87 100644 --- a/mythtv/programs/mythbackend/mainserver.cpp +++ b/mythtv/programs/mythbackend/mainserver.cpp @@ -144,6 +144,8 @@ class ProcessRequestRunnable : public QRunnable virtual void run(void) { + LOG(VB_GENERAL, LOG_INFO, QString("Processing request for sock %1") + .arg(m_sock->GetSocketDescriptor())); m_parent.ProcessRequest(m_sock); m_sock->DecrRef(); m_sock = NULL; @@ -282,8 +284,8 @@ MainServer::MainServer(bool master, int port, SetExitCode(GENERIC_EXIT_SOCKET_ERROR, false); return; } - connect(mythserver, SIGNAL(newConnect(MythSocket *)), - this, SLOT(newConnection(MythSocket *))); + connect(mythserver, SIGNAL(NewConnection(int)), + this, SLOT(NewConnection(int))); gCoreContext->addListener(this); @@ -385,6 +387,30 @@ void MainServer::Stop() masterFreeSpaceListWait.wait(locker.mutex()); } } + + // Close all open sockets + QWriteLocker locker(&sockListLock); + + vector::iterator it = playbackList.begin(); + for (; it != playbackList.end(); ++it) + (*it)->DecrRef(); + playbackList.clear(); + + vector::iterator ft = fileTransferList.begin(); + for (; ft != fileTransferList.end(); ++ft) + (*ft)->DecrRef(); + fileTransferList.clear(); + + QSet::iterator cs = controlSocketList.begin(); + for (; cs != controlSocketList.end(); ++cs) + (*cs)->DecrRef(); + controlSocketList.clear(); + + while (!decrRefSocketList.empty()) + { + (*decrRefSocketList.begin())->DecrRef(); + decrRefSocketList.erase(decrRefSocketList.begin()); + } } void MainServer::autoexpireUpdate(void) @@ -392,9 +418,10 @@ void MainServer::autoexpireUpdate(void) AutoExpire::Update(false); } -void MainServer::newConnection(MythSocket *socket) +void MainServer::NewConnection(int socketDescriptor) { - socket->setCallbacks(this); + QWriteLocker locker(&sockListLock); + controlSocketList.insert(new MythSocket(socketDescriptor, this)); } void MainServer::readyRead(MythSocket *sock) @@ -404,38 +431,44 @@ void MainServer::readyRead(MythSocket *sock) bool expecting_reply = testsock && testsock->isExpectingReply(); sockListLock.unlock(); if (expecting_reply) + { + LOG(VB_GENERAL, LOG_INFO, "readyRead ignoring, expecting reply"); return; + } threadPool.startReserved( new ProcessRequestRunnable(*this, sock), "ProcessRequest", PRT_TIMEOUT); + + QCoreApplication::processEvents(); } void MainServer::ProcessRequest(MythSocket *sock) { - sock->Lock(); - - if (sock->bytesAvailable() > 0) - { + if (sock->IsDataAvailable()) ProcessRequestWork(sock); - } - - sock->Unlock(); + else + LOG(VB_GENERAL, LOG_INFO, QString("No data on sock %1") + .arg(sock->GetSocketDescriptor())); } void MainServer::ProcessRequestWork(MythSocket *sock) { QStringList listline; - if (!sock->readStringList(listline)) + LOG(VB_GENERAL, LOG_INFO, "PRW: Calling ReadStringList()"); + if (!sock->ReadStringList(listline) || listline.empty()) + { + LOG(VB_GENERAL, LOG_INFO, "No data in ProcessRequestWork()"); return; + } QString line = listline[0]; line = line.simplified(); QStringList tokens = line.split(' ', QString::SkipEmptyParts); QString command = tokens[0]; -#if 0 - LOG(VB_GENERAL, LOG_DEBUG, "command='" + command + "'"); +#if 1 + LOG(VB_GENERAL, LOG_INFO, "PRW: command='" + command + "'"); #endif if (command == "MYTH_PROTO_VERSION") { @@ -860,6 +893,20 @@ void MainServer::customEvent(QEvent *e) QStringList broadcast; QSet receivers; + // delete stale sockets in the UI thread + sockListLock.lockForRead(); + bool decrRefEmpty = decrRefSocketList.empty(); + sockListLock.unlock(); + if (!decrRefEmpty) + { + QWriteLocker locker(&sockListLock); + while (!decrRefSocketList.empty()) + { + (*decrRefSocketList.begin())->DecrRef(); + decrRefSocketList.erase(decrRefSocketList.begin()); + } + } + if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage) { MythEvent *me = (MythEvent *)e; @@ -1255,15 +1302,8 @@ void MainServer::customEvent(QEvent *e) } MythSocket *sock = pbs->getSocket(); - if (reallysendit && sock->socket() >= 0) - { - sock->Lock(); - - if (sock->socket() >= 0) - sock->writeStringList(broadcast); - - sock->Unlock(); - } + if (reallysendit && sock->IsConnected()) + sock->WriteStringList(broadcast); } // Done with the pbs list, so decrement all the instances.. @@ -1293,7 +1333,7 @@ void MainServer::HandleVersion(MythSocket *socket, const QStringList &slist) "MainServer::HandleVersion - Client speaks protocol version " + version + " but we speak " + MYTH_PROTO_VERSION + '!'); retlist << "REJECT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); HandleDone(socket); return; } @@ -1304,7 +1344,7 @@ void MainServer::HandleVersion(MythSocket *socket, const QStringList &slist) "MainServer::HandleVersion - Client did not pass protocol " "token. Refusing connection!"); retlist << "REJECT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); HandleDone(socket); return; } @@ -1316,13 +1356,13 @@ void MainServer::HandleVersion(MythSocket *socket, const QStringList &slist) "MainServer::HandleVersion - Client sent incorrect protocol" " token for protocol version. Refusing connection!"); retlist << "REJECT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); HandleDone(socket); return; } retlist << "ACCEPT" << MYTH_PROTO_VERSION; - socket->writeStringList(retlist); + socket->WriteStringList(retlist); } /** @@ -1353,7 +1393,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, .arg(info)); errlist << "malformed_ann_query"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1368,7 +1408,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, QString("Client %1 is trying to announce a socket " "multiple times.") .arg(commands[2])); - socket->writeStringList(retlist); + socket->WriteStringList(retlist); sockListLock.unlock(); return; } @@ -1383,7 +1423,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, .arg(commands[1])); errlist << "malformed_ann_query"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } // Monitor connections are same as Playback but they don't @@ -1400,6 +1440,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, pbs->setBlockShutdown(commands[1] == "Playback"); sockListLock.lockForWrite(); + controlSocketList.remove(socket); playbackList.push_back(pbs); sockListLock.unlock(); @@ -1414,7 +1455,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, LOG(VB_GENERAL, LOG_ERR, "Received malformed ANN MediaServer query"); errlist << "malformed_ann_query"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1423,6 +1464,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, pbs->setAsMediaServer(); pbs->setBlockShutdown(false); sockListLock.lockForWrite(); + controlSocketList.remove(socket); playbackList.push_back(pbs); sockListLock.unlock(); @@ -1436,7 +1478,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, LOG(VB_GENERAL, LOG_ERR, QString("Received malformed ANN %1 query") .arg(commands[1])); errlist << "malformed_ann_query"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1489,6 +1531,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, pbs->setBlockShutdown(false); sockListLock.lockForWrite(); + controlSocketList.remove(socket); playbackList.push_back(pbs); sockListLock.unlock(); @@ -1503,7 +1546,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, { LOG(VB_GENERAL, LOG_ERR, "Received malformed FileTransfer command"); errlist << "malformed_filetransfer_command"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1543,7 +1586,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, LOG(VB_GENERAL, LOG_ERR, "Unable to determine directory " "to write to in FileTransfer write command"); errlist << "filetransfer_directory_not_found"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1557,7 +1600,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, QString("FileTransfer write filename is empty in url '%1'.") .arg(qurl.toString())); errlist << "filetransfer_filename_empty"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1568,7 +1611,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, QString("FileTransfer write filename '%1' does not pass " "sanity checks.") .arg(basename)); errlist << "filetransfer_filename_dangerous"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1581,7 +1624,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, { LOG(VB_GENERAL, LOG_ERR, "Empty filename, cowardly aborting!"); errlist << "filetransfer_filename_empty"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1593,7 +1636,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, QString("FileTransfer filename '%1' is actually a directory, " "cannot transfer.") .arg(filename)); errlist << "filetransfer_filename_is_a_directory"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } @@ -1610,7 +1653,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, "subdirectory which does not exist, and can " "not be created.") .arg(filename)); errlist << "filetransfer_unable_to_create_subdirectory"; - socket->writeStringList(errlist); + socket->WriteStringList(errlist); return; } } @@ -1624,10 +1667,11 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, ft->IncrRef(); sockListLock.lockForWrite(); + controlSocketList.remove(socket); fileTransferList.push_back(ft); sockListLock.unlock(); - retlist << QString::number(socket->socket()); + retlist << QString::number(socket->GetSocketDescriptor()); retlist << QString::number(ft->GetFileSize()); ft->DecrRef(); @@ -1647,7 +1691,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, } } - socket->writeStringList(retlist); + socket->WriteStringList(retlist); } /** @@ -1657,7 +1701,7 @@ void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, */ void MainServer::HandleDone(MythSocket *socket) { - socket->close(); + socket->DisconnectFromHost(); } void MainServer::SendResponse(MythSocket *socket, QStringList &commands) @@ -1680,7 +1724,7 @@ void MainServer::SendResponse(MythSocket *socket, QStringList &commands) if (do_write) { - socket->writeStringList(commands); + socket->WriteStringList(commands); } else { @@ -5707,10 +5751,16 @@ void MainServer::DeletePBS(PlaybackSock *sock) deferredDeleteList.push_back(dds); } +#undef QT_NO_DEBUG + void MainServer::connectionClosed(MythSocket *socket) { sockListLock.lockForWrite(); + // make sure these are not actually deleted in the callback + socket->IncrRef(); + decrRefSocketList.push_back(socket); + vector::iterator it = playbackList.begin(); for (; it != playbackList.end(); ++it) { @@ -5808,13 +5858,14 @@ void MainServer::connectionClosed(MythSocket *socket) if (testsock) LOG(VB_GENERAL, LOG_ERR, "Playback sock still exists?"); + pbs->DecrRef(); + sockListLock.unlock(); // Since we may already be holding the scheduler lock // delay handling the disconnect until a little later. #9885 SendSlaveDisconnectedEvent(disconnectedSlaves, needsReschedule); - pbs->DecrRef(); return; } } @@ -5832,11 +5883,20 @@ void MainServer::connectionClosed(MythSocket *socket) } } + QSet::iterator cs = controlSocketList.find(socket); + if (cs != controlSocketList.end()) + { + (*cs)->DecrRef(); + controlSocketList.erase(cs); + sockListLock.unlock(); + return; + } + sockListLock.unlock(); LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Unknown socket closing MythSocket(0x%1)") - .arg((uint64_t)socket,0,16)); + .arg((intptr_t)socket,0,16)); } PlaybackSock *MainServer::GetSlaveByHostname(const QString &hostname) @@ -5914,7 +5974,7 @@ FileTransfer *MainServer::GetFileTransferByID(int id) vector::iterator it = fileTransferList.begin(); for (; it != fileTransferList.end(); ++it) { - if (id == (*it)->getSocket()->socket()) + if (id == (*it)->getSocket()->GetSocketDescriptor()) { retval = (*it); break; @@ -6118,7 +6178,7 @@ QString MainServer::LocalFilePath(const QUrl &url, const QString &wantgroup) void MainServer::reconnectTimeout(void) { - MythSocket *masterServerSock = new MythSocket(); + MythSocket *masterServerSock = new MythSocket(-1, this); QString server = gCoreContext->GetSetting("MasterServerIP", "127.0.0.1"); int port = gCoreContext->GetNumSetting("MasterServerPort", 6543); @@ -6126,7 +6186,7 @@ void MainServer::reconnectTimeout(void) LOG(VB_GENERAL, LOG_NOTICE, QString("Connecting to master server: %1:%2") .arg(server).arg(port)); - if (!masterServerSock->connect(server, port)) + if (!masterServerSock->ConnectToHost(server, port)) { LOG(VB_GENERAL, LOG_NOTICE, "Connection to master server timed out."); masterServerReconnect->start(kMasterServerReconnectTimeout); @@ -6134,22 +6194,12 @@ void MainServer::reconnectTimeout(void) return; } - if (masterServerSock->state() != MythSocket::Connected) - { - LOG(VB_GENERAL, LOG_ERR, "Could not connect to master server."); - masterServerReconnect->start(kMasterServerReconnectTimeout); - masterServerSock->DecrRef(); - return; - } - LOG(VB_GENERAL, LOG_NOTICE, "Connected successfully"); QString str = QString("ANN SlaveBackend %1 %2") .arg(gCoreContext->GetHostName()) .arg(gCoreContext->GetBackendServerIP()); - masterServerSock->Lock(); - QStringList strlist( str ); QMap::Iterator iter = encoderList->begin(); @@ -6170,12 +6220,11 @@ void MainServer::reconnectTimeout(void) } } - if (!masterServerSock->writeStringList(strlist) || - !masterServerSock->readStringList(strlist) || - strlist.empty() || strlist[0] == "ERROR") + if (!masterServerSock->SendReceiveStringList(strlist, 1) || + (strlist[0] == "ERROR")) { - masterServerSock->Unlock(); // DownRef will delete socket... - masterServerSock->DecrRef(); masterServerSock = NULL; + masterServerSock->DecrRef(); + masterServerSock = NULL; if (strlist.empty()) { LOG(VB_GENERAL, LOG_ERR, LOC + @@ -6193,16 +6242,12 @@ void MainServer::reconnectTimeout(void) return; } - masterServerSock->setCallbacks(this); - masterServer = new PlaybackSock(this, masterServerSock, server, kPBSEvents_Normal); sockListLock.lockForWrite(); playbackList.push_back(masterServer); sockListLock.unlock(); - masterServerSock->Unlock(); - autoexpireUpdateTimer->start(1000); } @@ -6245,7 +6290,7 @@ void MainServer::ShutSlaveBackendsDown(QString &haltcmd) for (; it != playbackList.end(); ++it) { if ((*it)->isSlaveBackend()) - (*it)->getSocket()->writeStringList(bcast); + (*it)->getSocket()->WriteStringList(bcast); } sockListLock.unlock(); diff --git a/mythtv/programs/mythbackend/mainserver.h b/mythtv/programs/mythbackend/mainserver.h index e27c9ae8378..ee92fa258a9 100644 --- a/mythtv/programs/mythbackend/mainserver.h +++ b/mythtv/programs/mythbackend/mainserver.h @@ -133,7 +133,7 @@ class MainServer : public QObject, public MythSocketCBs void autoexpireUpdate(void); private slots: - void newConnection(MythSocket *); + void NewConnection(int socketDescriptor); private: @@ -274,6 +274,8 @@ class MainServer : public QObject, public MythSocketCBs QReadWriteLock sockListLock; vector playbackList; vector fileTransferList; + QSet controlSocketList; + vector decrRefSocketList; QMutex masterFreeSpaceListLock; FreeSpaceUpdater * volatile masterFreeSpaceListUpdater; diff --git a/mythtv/programs/mythbackend/playbacksock.cpp b/mythtv/programs/mythbackend/playbacksock.cpp index 30b76063d66..65a49ace6a2 100644 --- a/mythtv/programs/mythbackend/playbacksock.cpp +++ b/mythtv/programs/mythbackend/playbacksock.cpp @@ -78,34 +78,14 @@ bool PlaybackSock::SendReceiveStringList( bool ok = false; sock->IncrRef(); - sock->Lock(); { QMutexLocker locker(&sockLock); expectingreply = true; - - sock->writeStringList(strlist); - ok = sock->readStringList(strlist); - - while (ok && strlist[0] == "BACKEND_MESSAGE") - { - // oops, not for us - if (strlist.size() >= 2) - { - QString message = strlist[1]; - strlist.pop_front(); - strlist.pop_front(); - MythEvent me(message, strlist); - gCoreContext->dispatch(me); - } - - ok = sock->readStringList(strlist); - } - + ok = sock->SendReceiveStringList(strlist); expectingreply = false; } - sock->Unlock(); sock->DecrRef(); if (!ok) diff --git a/mythtv/programs/mythbackend/server.cpp b/mythtv/programs/mythbackend/server.cpp index ac0472db04a..2b01ae64093 100644 --- a/mythtv/programs/mythbackend/server.cpp +++ b/mythtv/programs/mythbackend/server.cpp @@ -1,9 +1,8 @@ #include "server.h" -#include "mythsocket.h" +#include "mythlogging.h" void MythServer::newTcpConnection(int socket) { - MythSocket *s = new MythSocket(socket); - emit newConnect(s); + emit NewConnection(socket); } diff --git a/mythtv/programs/mythbackend/server.h b/mythtv/programs/mythbackend/server.h index fee448f57e4..57b4bd50fd2 100644 --- a/mythtv/programs/mythbackend/server.h +++ b/mythtv/programs/mythbackend/server.h @@ -10,7 +10,7 @@ class MythServer : public ServerPool Q_OBJECT signals: - void newConnect(MythSocket*); + void NewConnection(int socketDescriptor); protected: virtual void newTcpConnection(int socket);