00001
00002 #include <cstdlib>
00003 #include <cassert>
00004 #include <cerrno>
00005
00006 #include "compat.h"
00007
00008
00009 #ifndef USING_MINGW
00010 #include <sys/select.h>
00011 #endif
00012
00013
00014 #include <QByteArray>
00015 #include <QHostInfo>
00016 #include <QNetworkInterface>
00017 #include <QAbstractSocket>
00018 #include <QMap>
00019 #include <QCoreApplication>
00020
00021
00022 #include "mythsocketthread.h"
00023 #include "mythsocket.h"
00024 #include "mythtimer.h"
00025 #include "mythsocket.h"
00026 #include "mythevent.h"
00027 #include "mythversion.h"
00028 #include "mythlogging.h"
00029 #include "mythcorecontext.h"
00030
00031 #define SLOC(a) QString("MythSocket(%1:%2): ")\
00032 .arg((uint64_t)a, 0, 16).arg(a->socket())
00033 #define LOC SLOC(this)
00034
00035 const uint MythSocket::kSocketBufferSize = 128000;
00036 const uint MythSocket::kShortTimeout = kMythSocketShortTimeout;
00037 const uint MythSocket::kLongTimeout = kMythSocketLongTimeout;
00038
00039 QMutex MythSocket::s_readyread_thread_lock;
00040 MythSocketThread *MythSocket::s_readyread_thread = NULL;
00041
00042 QMap<QString, QHostAddress::SpecialAddress> MythSocket::s_loopback_cache;
00043
00044 MythSocket::MythSocket(int socket, MythSocketCBs *cb)
00045 : MSocketDevice(MSocketDevice::Stream), m_cb(cb),
00046 m_useReadyReadCallback(true),
00047 m_state(Idle), m_addr(), m_port(0),
00048 m_ref_count(0), m_notifyread(false), m_expectingreply(false),
00049 m_isValidated(false), m_isAnnounced(false)
00050 {
00051 LOG(VB_SOCKET, LOG_DEBUG, LOC + "new socket");
00052 if (socket > -1)
00053 {
00054 setSocket(socket);
00055 #ifdef USING_MINGW
00056
00057
00058 setSendBufferSize(kSocketBufferSize);
00059 #endif
00060 }
00061
00062 if (!s_readyread_thread)
00063 {
00064 QMutexLocker locker(&s_readyread_thread_lock);
00065 if (!s_readyread_thread)
00066 s_readyread_thread = new MythSocketThread();
00067 }
00068
00069 if (m_cb)
00070 s_readyread_thread->AddToReadyRead(this);
00071 }
00072
00073 MythSocket::~MythSocket()
00074 {
00075 close();
00076 LOG(VB_SOCKET, LOG_DEBUG, LOC + "delete socket");
00077 }
00078
00079 void MythSocket::setCallbacks(MythSocketCBs *cb)
00080 {
00081 if (m_cb && cb)
00082 {
00083 m_cb = cb;
00084 return;
00085 }
00086
00087 m_cb = cb;
00088
00089 if (m_cb)
00090 s_readyread_thread->AddToReadyRead(this);
00091 else
00092 s_readyread_thread->RemoveFromReadyRead(this);
00093 }
00094
00095 void MythSocket::UpRef(void)
00096 {
00097 QMutexLocker locker(&m_ref_lock);
00098 m_ref_count++;
00099 LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("UpRef: %1").arg(m_ref_count));
00100 }
00101
00102 bool MythSocket::DownRef(void)
00103 {
00104 m_ref_lock.lock();
00105 int ref = --m_ref_count;
00106 m_ref_lock.unlock();
00107
00108 LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("DownRef: %1").arg(ref));
00109
00110 if (m_cb && ref == 0)
00111 {
00112 m_cb = NULL;
00113 s_readyread_thread->RemoveFromReadyRead(this);
00114
00115 return true;
00116 }
00117 else if (ref < 0)
00118 {
00119 delete this;
00120 return true;
00121 }
00122
00123 return false;
00124 }
00125
00126 MythSocket::State MythSocket::state(void) const
00127 {
00128 return m_state;
00129 }
00130
00131 void MythSocket::setState(const State state)
00132 {
00133 if (state != m_state)
00134 {
00135 LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("state change %1 -> %2")
00136 .arg(stateToString(m_state)).arg(stateToString(state)));
00137
00138 m_state = state;
00139 }
00140 }
00141
00142 QString MythSocket::stateToString(const State state) const
00143 {
00144 switch(state)
00145 {
00146 case Connected:
00147 return "Connected";
00148 case Connecting:
00149 return "Connecting";
00150 case HostLookup:
00151 return "HostLookup";
00152 case Idle:
00153 return "Idle";
00154 default:
00155 return QString("Invalid State: %1").arg(state);
00156 }
00157 }
00158
00159 QString MythSocket::errorToString(const Error error) const
00160 {
00161 switch(error)
00162 {
00163 case NoError:
00164 return "NoError";
00165 case AlreadyBound:
00166 return "AlreadyBound";
00167 case Inaccessible:
00168 return "Inaccessible";
00169 case NoResources:
00170 return "NoResources";
00171 case InternalError:
00172 return "InternalError";
00173 case Impossible:
00174 return "Impossible";
00175 case NoFiles:
00176 return "NoFiles";
00177 case ConnectionRefused:
00178 return "ConnectionRefused";
00179 case NetworkFailure:
00180 return "NetworkFailure";
00181 case UnknownError:
00182 return "UnknownError";
00183 default:
00184 return QString("Invalid error: %1").arg(error);
00185 }
00186 }
00187
00188 void MythSocket::setSocket(int socket, Type type)
00189 {
00190 LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("setSocket: %1").arg(socket));
00191 if (socket < 0)
00192 {
00193 LOG(VB_SOCKET, LOG_DEBUG, LOC + "setSocket called with invalid socket");
00194 return;
00195 }
00196
00197 if (state() == Connected)
00198 {
00199 LOG(VB_SOCKET, LOG_DEBUG, LOC +
00200 "setSocket called while in Connected state, closing");
00201 close();
00202 }
00203
00204 MSocketDevice::setSocket(socket, type);
00205 setBlocking(false);
00206 setState(Connected);
00207 setKeepalive(true);
00208 }
00209
00210 void MythSocket::close(void)
00211 {
00212 setState(Idle);
00213 MSocketDevice::close();
00214 if (m_cb)
00215 {
00216 LOG(VB_SOCKET, LOG_DEBUG, LOC + "calling m_cb->connectionClosed()");
00217 m_cb->connectionClosed(this);
00218 }
00219 }
00220
00221 bool MythSocket::closedByRemote(void)
00222 {
00223 fd_set rfds;
00224 FD_ZERO(&rfds);
00225 FD_SET(socket(), &rfds);
00226
00227 struct timeval to;
00228 to.tv_sec = 0;
00229 to.tv_usec = 1000;
00230
00231 int rval = select(socket() + 1, &rfds, NULL, NULL, &to);
00232
00233 if (rval > 0 && FD_ISSET(socket(), &rfds) && !bytesAvailable())
00234 return true;
00235
00236 return false;
00237 }
00238
00239 qint64 MythSocket::readBlock(char *data, quint64 len)
00240 {
00241 LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("readBlock(0x%1, %2) called")
00242 .arg((uint64_t)data,0,16).arg(len));
00243
00244 if (state() != Connected)
00245 {
00246 LOG(VB_SOCKET, LOG_ERR, LOC + "readBlock called while not in "
00247 "connected state");
00248 return -1;
00249 }
00250
00251 m_notifyread = false;
00252
00253 qint64 rval = MSocketDevice::readBlock(data, len);
00254 if (rval == 0)
00255 close();
00256
00257 return rval;
00258 }
00259
00264 qint64 MythSocket::writeBlock(const char *data, quint64 len)
00265 {
00266 LOG(VB_SOCKET, LOG_DEBUG, LOC + QString("writeBlock(0x%1, %2)")
00267 .arg((uint64_t)data, 0, 16).arg(len));
00268
00269 if (state() != Connected)
00270 {
00271 LOG(VB_SOCKET, LOG_ERR, LOC + "writeBlock called while not in "
00272 "connected state");
00273 return -1;
00274 }
00275
00276 qint64 rval = MSocketDevice::writeBlock(data, len);
00277
00278
00279 if (!isValid() || error() != MSocketDevice::NoError)
00280 {
00281 close();
00282 return -1;
00283 }
00284 return rval;
00285 }
00286
00287 static QString toSample(const QByteArray &payload)
00288 {
00289 QString sample("");
00290 for (uint i = 0; (i<60) && (i<(uint)payload.length()); i++)
00291 {
00292 sample += QChar(payload.data()[i]).isPrint() ?
00293 QChar(payload.data()[i]) : QChar('?');
00294 }
00295 sample += (payload.length() > 60) ? "..." : "";
00296 return sample;
00297 }
00298
00299 bool MythSocket::writeStringList(QStringList &list)
00300 {
00301 if (list.size() <= 0)
00302 {
00303 LOG(VB_GENERAL, LOG_ERR, LOC +
00304 "writeStringList: Error, invalid string list.");
00305 return false;
00306 }
00307
00308 if (state() != Connected)
00309 {
00310 LOG(VB_GENERAL, LOG_ERR, LOC +
00311 "writeStringList: Error, called with unconnected socket.");
00312 return false;
00313 }
00314
00315 QString str = list.join("[]:[]");
00316 if (str.isEmpty())
00317 {
00318 LOG(VB_GENERAL, LOG_ERR, LOC +
00319 "writeStringList: Error, joined null string.");
00320 return false;
00321 }
00322
00323 QByteArray utf8 = str.toUtf8();
00324 int size = utf8.length();
00325 int written = 0;
00326 int written_since_timer_restart = 0;
00327
00328 QByteArray payload;
00329 payload = payload.setNum(size);
00330 payload += " ";
00331 payload.truncate(8);
00332 payload += utf8;
00333 size = payload.length();
00334
00335 if (VERBOSE_LEVEL_CHECK(VB_NETWORK, LOG_INFO))
00336 {
00337 QString msg = QString("write -> %1 %2")
00338 .arg(socket(), 2).arg(payload.data());
00339
00340 if (logLevel < LOG_DEBUG && msg.length() > 88)
00341 {
00342 msg.truncate(85);
00343 msg += "...";
00344 }
00345 LOG(VB_NETWORK, LOG_INFO, LOC + msg);
00346 }
00347
00348 MythTimer timer; timer.start();
00349 unsigned int errorcount = 0;
00350 while (size > 0)
00351 {
00352 if (state() != Connected)
00353 {
00354 LOG(VB_GENERAL, LOG_ERR, LOC +
00355 "writeStringList: Error, socket went unconnected." +
00356 QString("\n\t\t\tWe wrote %1 of %2 bytes with %3 errors")
00357 .arg(written).arg(written+size).arg(errorcount) +
00358 QString("\n\t\t\tstarts with: %1").arg(toSample(payload)));
00359 return false;
00360 }
00361
00362 int temp = writeBlock(payload.data() + written, size);
00363 if (temp > 0)
00364 {
00365 written += temp;
00366 written_since_timer_restart += temp;
00367 size -= temp;
00368 if ((timer.elapsed() > 500) && written_since_timer_restart != 0)
00369 {
00370 timer.restart();
00371 written_since_timer_restart = 0;
00372 }
00373 }
00374 else if (temp < 0 && error() != MSocketDevice::NoError)
00375 {
00376 LOG(VB_GENERAL, LOG_ERR, LOC +
00377 QString("writeStringList: Error, writeBlock failed. (%1)")
00378 .arg(errorToString()));
00379 return false;
00380 }
00381 else if (temp <= 0)
00382 {
00383 errorcount++;
00384 if (timer.elapsed() > 1000)
00385 {
00386 LOG(VB_GENERAL, LOG_ERR, LOC + "writeStringList: Error, " +
00387 QString("No data written on writeBlock (%1 errors)")
00388 .arg(errorcount) +
00389 QString("\n\t\t\tstarts with: %1") .arg(toSample(payload)));
00390 return false;
00391 }
00392 usleep(1000);
00393 }
00394 }
00395
00396 flush();
00397
00398 return true;
00399 }
00400
00405 bool MythSocket::readData(char *data, quint64 len)
00406 {
00407 if (state() != Connected)
00408 {
00409 LOG(VB_GENERAL, LOG_ERR, LOC +
00410 "readData: Error, called with unconnected socket.");
00411 return false;
00412 }
00413
00414 quint64 bytes_read = 0;
00415 uint zerocnt = 0;
00416
00417 while (bytes_read < len)
00418 {
00419 qint64 btw = len - bytes_read >= kSocketBufferSize ?
00420 kSocketBufferSize : len - bytes_read;
00421 qint64 sret = readBlock(data + bytes_read, btw);
00422 if (sret > 0)
00423 {
00424 zerocnt = 0;
00425 bytes_read += sret;
00426 }
00427 else if (!isValid())
00428 {
00429 LOG(VB_GENERAL, LOG_ERR, LOC +
00430 "readData: Error, socket went unconnected");
00431 close();
00432 return false;
00433 }
00434 else if (sret < 0 && error() != MSocketDevice::NoError)
00435 {
00436 LOG(VB_GENERAL, LOG_ERR, LOC +
00437 QString("readData: Error, readBlock: %1")
00438 .arg(errorToString()));
00439 close();
00440 return false;
00441 }
00442 else
00443 {
00444 zerocnt++;
00445 if (zerocnt > 5000)
00446 {
00447 LOG(VB_GENERAL, LOG_ERR, LOC +
00448 "readData: Error, zerocnt timeout");
00449 return false;
00450 }
00451 usleep(1000);
00452 }
00453 }
00454 return true;
00455 }
00456
00461 bool MythSocket::writeData(const char *data, quint64 len)
00462 {
00463 if (state() != Connected)
00464 {
00465 LOG(VB_GENERAL, LOG_ERR, LOC +
00466 "writeData: Error, called with unconnected socket.");
00467 return false;
00468 }
00469
00470 quint64 written = 0;
00471 uint zerocnt = 0;
00472
00473 while (written < len)
00474 {
00475 qint64 btw = len - written >= kSocketBufferSize ?
00476 kSocketBufferSize : len - written;
00477 qint64 sret = writeBlock(data + written, btw);
00478 if (sret > 0)
00479 {
00480 zerocnt = 0;
00481 written += sret;
00482 }
00483 else if (!isValid())
00484 {
00485 LOG(VB_GENERAL, LOG_ERR, LOC +
00486 "writeData: Error, socket went unconnected");
00487 close();
00488 return false;
00489 }
00490 else if (sret < 0 && error() != MSocketDevice::NoError)
00491 {
00492 LOG(VB_GENERAL, LOG_ERR, LOC +
00493 QString("writeData: Error, writeBlock: %1")
00494 .arg(errorToString()));
00495 close();
00496 return false;
00497 }
00498 else
00499 {
00500 zerocnt++;
00501 if (zerocnt > 5000)
00502 {
00503 LOG(VB_GENERAL, LOG_ERR, LOC +
00504 "writeData: Error, zerocnt timeout");
00505 return false;
00506 }
00507 usleep(1000);
00508 }
00509 }
00510 return true;
00511 }
00512
00513 bool MythSocket::readStringList(QStringList &list, uint timeoutMS)
00514 {
00515 list.clear();
00516
00517 if (state() != Connected)
00518 {
00519 LOG(VB_GENERAL, LOG_ERR, LOC +
00520 "readStringList: Error, called with unconnected socket.");
00521 return false;
00522 }
00523
00524 MythTimer timer;
00525 timer.start();
00526 int elapsed = 0;
00527
00528 while (waitForMore(5) < 8)
00529 {
00530 elapsed = timer.elapsed();
00531 if (elapsed >= (int)timeoutMS)
00532 {
00533 LOG(VB_GENERAL, LOG_ERR, LOC + "readStringList: " +
00534 QString("Error, timed out after %1 ms.").arg(timeoutMS));
00535 close();
00536 return false;
00537 }
00538
00539 if (state() != Connected)
00540 {
00541 LOG(VB_GENERAL, LOG_ERR, LOC + "readStringList: Connection died.");
00542 return false;
00543 }
00544
00545 {
00546 struct timeval tv;
00547 int maxfd;
00548 fd_set rfds;
00549
00550 FD_ZERO(&rfds);
00551 FD_SET(socket(), &rfds);
00552 maxfd = socket();
00553
00554 tv.tv_sec = 0;
00555 tv.tv_usec = 0;
00556
00557 int rval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
00558 if (rval)
00559 {
00560 if (bytesAvailable() == 0)
00561 {
00562 LOG(VB_GENERAL, LOG_ERR, LOC +
00563 "readStringList: Connection died (select).");
00564 return false;
00565 }
00566 }
00567 }
00568 }
00569
00570 QByteArray sizestr(8 + 1, '\0');
00571 if (readBlock(sizestr.data(), 8) < 0)
00572 {
00573 LOG(VB_GENERAL, LOG_ERR, LOC +
00574 QString("readStringList: Error, readBlock return error (%1)")
00575 .arg(errorToString()));
00576 close();
00577 return false;
00578 }
00579
00580 QString sizes = sizestr;
00581 qint64 btr = sizes.trimmed().toInt();
00582
00583 if (btr < 1)
00584 {
00585 int pending = bytesAvailable();
00586 QByteArray dump(pending + 1, 0);
00587 readBlock(dump.data(), pending);
00588 LOG(VB_GENERAL, LOG_ERR, LOC +
00589 QString("Protocol error: '%1' is not a valid size "
00590 "prefix. %2 bytes pending.")
00591 .arg(sizestr.data()).arg(pending));
00592 return false;
00593 }
00594
00595 QByteArray utf8(btr + 1, 0);
00596
00597 qint64 read = 0;
00598 int errmsgtime = 0;
00599 timer.start();
00600
00601 while (btr > 0)
00602 {
00603 qint64 sret = readBlock(utf8.data() + read, btr);
00604 if (sret > 0)
00605 {
00606 read += sret;
00607 btr -= sret;
00608 if (btr > 0)
00609 {
00610 timer.start();
00611 }
00612 }
00613 else if (sret < 0 && error() != MSocketDevice::NoError)
00614 {
00615 LOG(VB_GENERAL, LOG_ERR, LOC +
00616 QString("readStringList: Error, readBlock %1")
00617 .arg(errorToString()));
00618 close();
00619 return false;
00620 }
00621 else if (!isValid())
00622 {
00623 LOG(VB_GENERAL, LOG_ERR, LOC +
00624 "readStringList: Error, socket went unconnected");
00625 close();
00626 return false;
00627 }
00628 else
00629 {
00630 elapsed = timer.elapsed();
00631 if (elapsed > 10000)
00632 {
00633 if ((elapsed - errmsgtime) > 10000)
00634 {
00635 errmsgtime = elapsed;
00636 LOG(VB_GENERAL, LOG_ERR, LOC +
00637 QString("readStringList: Waiting for data: %1 %2")
00638 .arg(read).arg(btr));
00639 }
00640 }
00641
00642 if (elapsed > 100000)
00643 {
00644 LOG(VB_GENERAL, LOG_ERR, LOC +
00645 "Error, readStringList timeout (readBlock)");
00646 return false;
00647 }
00648
00649 usleep(500);
00650 }
00651 }
00652
00653 QString str = QString::fromUtf8(utf8.data());
00654
00655 QByteArray payload;
00656 payload = payload.setNum(str.length());
00657 payload += " ";
00658 payload.truncate(8);
00659 payload += str;
00660
00661 if (VERBOSE_LEVEL_CHECK(VB_NETWORK, LOG_INFO))
00662 {
00663 QString msg = QString("read <- %1 %2").arg(socket(), 2)
00664 .arg(payload.data());
00665
00666 if (logLevel < LOG_DEBUG && msg.length() > 88)
00667 {
00668 msg.truncate(85);
00669 msg += "...";
00670 }
00671 LOG(VB_NETWORK, LOG_INFO, LOC + msg);
00672 }
00673
00674 list = str.split("[]:[]");
00675
00676 m_notifyread = false;
00677 s_readyread_thread->WakeReadyReadThread();
00678 return true;
00679 }
00680
00681 bool MythSocket::SendReceiveStringList(
00682 QStringList &strlist, uint min_reply_length)
00683 {
00684 bool ok = false;
00685
00686 Lock();
00687 m_expectingreply = true;
00688
00689 writeStringList(strlist);
00690 ok = readStringList(strlist);
00691
00692 while (ok && strlist[0] == "BACKEND_MESSAGE")
00693 {
00694
00695
00696
00697
00698 if (strlist.size() >= 2)
00699 {
00700 QString message = strlist[1];
00701 strlist.pop_front();
00702 strlist.pop_front();
00703 MythEvent me(message, strlist);
00704 gCoreContext->dispatch(me);
00705 }
00706
00707 ok = readStringList(strlist);
00708 }
00709
00710 m_expectingreply = false;
00711 Unlock();
00712
00713 if (!ok)
00714 {
00715 LOG(VB_GENERAL, LOG_ERR, LOC + "No response.");
00716 return false;
00717 }
00718
00719 if (min_reply_length && ((uint)strlist.size() < min_reply_length))
00720 {
00721 LOG(VB_GENERAL, LOG_ERR, LOC + "Response too short.");
00722 return false;
00723 }
00724
00725 return true;
00726 }
00727
00728 void MythSocket::Lock(void) const
00729 {
00730 m_lock.lock();
00731 s_readyread_thread->WakeReadyReadThread();
00732 }
00733
00734 bool MythSocket::TryLock(bool wake_readyread) const
00735 {
00736 if (m_lock.tryLock())
00737 {
00738 if (wake_readyread)
00739 s_readyread_thread->WakeReadyReadThread();
00740 return true;
00741 }
00742 return false;
00743 }
00744
00745 void MythSocket::Unlock(bool wake_readyread) const
00746 {
00747 m_lock.unlock();
00748 if (wake_readyread)
00749 s_readyread_thread->WakeReadyReadThread();
00750 }
00751
00756 bool MythSocket::connect(const QString &host, quint16 port)
00757 {
00758 QHostAddress hadr;
00759
00760
00761 if (!hadr.setAddress(host))
00762 {
00763
00764 if (!gCoreContext ||
00765 !hadr.setAddress(gCoreContext->GetBackendServerIP(host)))
00766 {
00767
00768 QHostInfo info = QHostInfo::fromName(host);
00769 if (!info.addresses().isEmpty())
00770 {
00771 hadr = info.addresses().first();
00772 }
00773 else
00774 {
00775 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to lookup: %1")
00776 .arg(host));
00777 return false;
00778 }
00779 }
00780 }
00781
00782 return MythSocket::connect(hadr, port);
00783 }
00784
00789 bool MythSocket::connect(const QHostAddress &hadr, quint16 port)
00790 {
00791 QHostAddress addr = hadr;
00792
00793 if (state() == Connected)
00794 {
00795 LOG(VB_SOCKET, LOG_ERR, LOC +
00796 "connect() called with already open socket, closing");
00797 close();
00798 }
00799
00800 bool usingLoopback = false;
00801 if (s_loopback_cache.contains(addr.toString()))
00802 {
00803 addr = QHostAddress(s_loopback_cache.value(addr.toString()));
00804 usingLoopback = true;
00805 }
00806 else
00807 {
00808 QList<QHostAddress> localIPs = QNetworkInterface::allAddresses();
00809 for (int i = 0; i < localIPs.count() && !usingLoopback; ++i)
00810 {
00811 if (addr == localIPs[i])
00812 {
00813 QHostAddress::SpecialAddress loopback = QHostAddress::LocalHost;
00814 if (addr.protocol() == QAbstractSocket::IPv6Protocol)
00815 loopback = QHostAddress::LocalHostIPv6;
00816
00817 s_loopback_cache[addr.toString()] = loopback;
00818 addr = QHostAddress(loopback);
00819 usingLoopback = true;
00820 }
00821 }
00822 }
00823
00824 if (usingLoopback)
00825 LOG(VB_SOCKET, LOG_INFO, LOC + QString("IP is local, using "
00826 "loopback address instead"));
00827
00828 LOG(VB_SOCKET, LOG_INFO, LOC + QString("attempting connect() to (%1:%2)")
00829 .arg(addr.toString()).arg(port));
00830
00831 if (!MSocketDevice::connect(addr, port))
00832 {
00833 LOG(VB_SOCKET, LOG_ERR, LOC + QString("connect() failed (%1)")
00834 .arg(errorToString()));
00835 setState(Idle);
00836 return false;
00837 }
00838
00839 setReceiveBufferSize(kSocketBufferSize);
00840 setAddressReusable(true);
00841 setKeepalive(true);
00842 if (state() == Connecting)
00843 {
00844 setState(Connected);
00845 if (m_cb)
00846 {
00847 LOG(VB_SOCKET, LOG_DEBUG, LOC + "calling m_cb->connected()");
00848 m_cb->connected(this);
00849 s_readyread_thread->WakeReadyReadThread();
00850 }
00851 }
00852 else
00853 {
00854 setState(Connected);
00855 }
00856
00857 return true;
00858 }
00859
00860 bool MythSocket::Validate(uint timeout_ms, bool error_dialog_desired)
00861 {
00862 if (m_isValidated)
00863 return true;
00864
00865 QStringList strlist(QString("MYTH_PROTO_VERSION %1 %2")
00866 .arg(MYTH_PROTO_VERSION).arg(MYTH_PROTO_TOKEN));
00867 writeStringList(strlist);
00868
00869 if (!readStringList(strlist, timeout_ms) || strlist.empty())
00870 {
00871 LOG(VB_GENERAL, LOG_ERR, "Protocol version check failure.\n\t\t\t"
00872 "The response to MYTH_PROTO_VERSION was empty.\n\t\t\t"
00873 "This happens when the backend is too busy to respond,\n\t\t\t"
00874 "or has deadlocked due to bugs or hardware failure.");
00875 return false;
00876 }
00877 else if (strlist[0] == "REJECT" && strlist.size() >= 2)
00878 {
00879 LOG(VB_GENERAL, LOG_ERR, QString("Protocol version or token mismatch "
00880 "(frontend=%1/%2,"
00881 "backend=%3/\?\?)\n")
00882 .arg(MYTH_PROTO_VERSION)
00883 .arg(MYTH_PROTO_TOKEN)
00884 .arg(strlist[1]));
00885
00886 QObject *GUIcontext = gCoreContext->GetGUIObject();
00887 if (error_dialog_desired && GUIcontext)
00888 {
00889 QStringList list(strlist[1]);
00890 QCoreApplication::postEvent(
00891 GUIcontext, new MythEvent("VERSION_MISMATCH", list));
00892 }
00893
00894 return false;
00895 }
00896 else if (strlist[0] == "ACCEPT")
00897 {
00898 LOG(VB_GENERAL, LOG_NOTICE, QString("Using protocol version %1")
00899 .arg(MYTH_PROTO_VERSION));
00900 setValidated();
00901 return true;
00902 }
00903
00904 LOG(VB_GENERAL, LOG_ERR,
00905 QString("Unexpected response to MYTH_PROTO_VERSION: %1")
00906 .arg(strlist[0]));
00907 return false;
00908 }
00909
00910 bool MythSocket::Announce(QStringList &strlist)
00911 {
00912 if (!m_isValidated)
00913 {
00914 LOG(VB_GENERAL, LOG_ERR, LOC +
00915 "refusing to announce unvalidated socket");
00916 }
00917
00918 if (m_isAnnounced)
00919 {
00920 LOG(VB_GENERAL, LOG_ERR, LOC + "refusing to re-announce socket");
00921 return false;
00922 }
00923
00924 m_announce << strlist;
00925
00926 writeStringList(strlist);
00927 strlist.clear();
00928
00929 if (!readStringList(strlist, true))
00930 {
00931 LOG(VB_GENERAL, LOG_ERR, LOC +
00932 QString("\n\t\t\tCould not read string list from server %1:%2")
00933 .arg(m_addr.toString()).arg(m_port));
00934 m_announce.clear();
00935 return false;
00936 }
00937
00938 m_isAnnounced = true;
00939 return true;
00940 }
00941
00942 void MythSocket::setAnnounce(QStringList &strlist)
00943 {
00944 m_announce.clear();
00945 m_announce << strlist;
00946 m_isAnnounced = true;
00947 }