sdbconnector.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Jarek Pelczar <jpelczar@gmail.com>
  4. ** Copyright (C) 2014 Tomasz Olszak <olszak.tomasz@gmail.com>
  5. **
  6. ** This file is part of Qt Creator.
  7. **
  8. ** Commercial License Usage
  9. ** Licensees holding valid commercial Qt licenses may use this file in
  10. ** accordance with the commercial license agreement provided with the
  11. ** Software or, alternatively, in accordance with the terms contained in
  12. ** a written agreement between you and Digia. For licensing terms and
  13. ** conditions see http://qt.digia.com/licensing. For further information
  14. ** use the contact form at http://qt.digia.com/contact-us.
  15. **
  16. ** GNU Lesser General Public License Usage
  17. ** Alternatively, this file may be used under the terms of the GNU Lesser
  18. ** General Public License version 2.1 as published by the Free Software
  19. ** Foundation and appearing in the file LICENSE.LGPL included in the
  20. ** packaging of this file. Please review the following information to
  21. ** ensure the GNU Lesser General Public License version 2.1 requirements
  22. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  23. **
  24. ** In addition, as a special exception, Digia gives you certain additional
  25. ** rights. These rights are described in the Digia Qt LGPL Exception
  26. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  27. **
  28. ****************************************************************************/
  29. #include "tizendebug.h"
  30. #include "sdbconnector.h"
  31. #include "sdbpacketutils.h"
  32. #include <QHostAddress>
  33. #include <QTcpSocket>
  34. #include <QRegularExpression>
  35. #include <QDebug>
  36. #include <QFileInfo>
  37. #include <coreplugin/id.h>
  38. const int DefaultServerPort=26099;
  39. namespace Tizen {
  40. namespace Internal {
  41. SdbConnector::SdbConnector(QObject *parent) :
  42. QObject(parent),
  43. m_socket(0),
  44. m_sdbProcess(0),
  45. m_state(SdbDisconnected),
  46. m_sdbPort(DefaultServerPort),
  47. m_startWait(0),
  48. m_retry(0)
  49. {
  50. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  51. m_startWait = new QTimer(this);
  52. connect(m_startWait, SIGNAL(timeout()), SLOT(_q_startWaitTimeout()));
  53. m_startWait->setInterval(1000);
  54. m_startWait->setSingleShot(true);
  55. m_commandResponseTimer = new QTimer(this);
  56. connect(m_commandResponseTimer, SIGNAL(timeout()), SLOT(_q_commandTimeout()));
  57. m_commandResponseTimer->setSingleShot(true);
  58. m_commandResponseTimer->setInterval(500);
  59. }
  60. SdbConnector::~SdbConnector()
  61. {
  62. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  63. }
  64. int SdbConnector::serverPort() const
  65. {
  66. return m_sdbPort;
  67. }
  68. QString SdbConnector::sdbPath() const
  69. {
  70. return m_sdbPath;
  71. }
  72. void SdbConnector::setSdbPath(const QString& path)
  73. {
  74. m_sdbPath = path;
  75. }
  76. SdbState SdbConnector::state() const
  77. {
  78. return m_state;
  79. }
  80. void SdbConnector::startConnector()
  81. {
  82. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "State:" << m_state;
  83. if (m_sdbPath.isEmpty()) {
  84. qCWarning(QTC_TIZEN_SDBCONNECTOR) << "SDB path empty";
  85. return;
  86. }
  87. if(!QFile::exists(m_sdbPath)) {
  88. qCWarning(QTC_TIZEN_SDBCONNECTOR) << "SDB executable not found in " << m_sdbPath;
  89. return;
  90. }
  91. if (QProcess::execute(m_sdbPath, QStringList() << QStringLiteral("kill-server"))) {
  92. qCWarning(QTC_TIZEN_SDBCONNECTOR) << "Error encountered while running " << m_sdbPath << " kill-server";
  93. }
  94. if(m_state == SdbDisconnected || m_state == SdbError) {
  95. startConnecting();
  96. } else if(m_state == SdbDisconnecting) {
  97. m_socket->disconnect(this);
  98. m_socket->deleteLater();
  99. m_socket = NULL;
  100. m_retry = 0;
  101. startConnecting();
  102. }
  103. }
  104. void SdbConnector::stopConnector()
  105. {
  106. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "State:" << m_state;
  107. m_commandResponseTimer->stop();
  108. if(m_state == SdbConnecting) {
  109. m_socket->disconnect(this);
  110. m_socket->deleteLater();
  111. m_socket = NULL;
  112. m_retry = 0;
  113. m_state = SdbDisconnected;
  114. emit stateChanged(SdbDisconnected);
  115. } else if(m_state == SdbConnected) {
  116. m_socket->disconnectFromHost();
  117. } else if(m_state == SdbDisconnecting) {
  118. } else if(m_state == SdbRestarting) {
  119. m_startWait->stop();
  120. m_retry = 0;
  121. }
  122. }
  123. void SdbConnector::startConnecting()
  124. {
  125. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Port:" << m_sdbPort;
  126. if(m_state != SdbConnecting) {
  127. m_state = SdbConnecting;
  128. emit stateChanged(m_state);
  129. }
  130. m_socket = new QTcpSocket(this);
  131. connect(m_socket, SIGNAL(connected()), SLOT(_q_tcpConnected()));
  132. connect(m_socket, SIGNAL(readyRead()), SLOT(_q_readyRead()));
  133. connect(m_socket, SIGNAL(disconnected()), SLOT(_q_tcpDisconnected()));
  134. connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(_q_socketError(QAbstractSocket::SocketError)));
  135. m_socket->connectToHost(QHostAddress::LocalHost, m_sdbPort);
  136. m_commandResponseTimer->start(1000);
  137. }
  138. void SdbConnector::_q_tcpConnected()
  139. {
  140. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Local port:" << m_socket->localPort();
  141. m_commandResponseTimer->stop();
  142. m_state = SdbConnected;
  143. m_protoState = WaitingForDeviceListResp;
  144. m_socket->write(SdbPacketUtils::makeRequest(QByteArray("host:track-devices")));
  145. m_commandResponseTimer->start();
  146. emit stateChanged(SdbConnected);
  147. }
  148. void SdbConnector::_q_readyRead()
  149. {
  150. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "m_socket->atEnd():" << m_socket->atEnd() << "m_protoState:" << m_protoState ;
  151. while(!m_socket->atEnd()) {
  152. if(m_protoState == WaitingForDeviceListResp) {
  153. SdbResponse resp;
  154. if(SdbPacketUtils::parseResponse(m_socket, SdbPacketUtils::DontReadDiagnosticString, resp)) {
  155. m_commandResponseTimer->stop();
  156. m_protoState = WaitingForDeviceListHeader;
  157. if(!resp.okay) {
  158. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "[SdbConnector] Failed to query device list";
  159. }
  160. }
  161. }
  162. if(m_protoState == WaitingForDeviceListHeader) {
  163. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "m_socket->bytesAvailable():" << m_socket->bytesAvailable();
  164. if(m_socket->bytesAvailable() >= 4) {
  165. char hdr[5];
  166. if(m_socket->read(hdr, 4) != 4)
  167. return;
  168. hdr[4] = 0;
  169. sscanf(hdr, "%X", &m_packetLength);
  170. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "m_packetLength:" << m_packetLength;
  171. m_protoState = WaitingForDeviceListData;
  172. } else {
  173. return;
  174. }
  175. }
  176. if(m_protoState == WaitingForDeviceListData) {
  177. if(m_socket->bytesAvailable() >= m_packetLength) {
  178. SdbDeviceList deviceList;
  179. m_protoState = WaitingForDeviceListHeader;
  180. if (m_packetLength > 0) {
  181. QByteArray string = m_socket->read(m_packetLength);
  182. QList<QByteArray> lines = string.split('\n');
  183. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "received list update" << string;
  184. if(!lines.empty())
  185. deviceList.reserve(lines.size());
  186. foreach(const QByteArray& line, lines) {
  187. QList<QByteArray> params = line.split('\t');
  188. if(params.length() == 3) {
  189. SdbDevice device;
  190. device.serialNumber = params.at(0).trimmed();
  191. device.name = QString::fromUtf8(params.at(2));
  192. QByteArray deviceState = params.at(1).trimmed();
  193. if(deviceState == "offline") {
  194. device.state = SdbDevice::Offline;
  195. } else if(deviceState == "device") {
  196. device.state = SdbDevice::Device;
  197. } else {
  198. device.state = SdbDevice::Unknown;
  199. }
  200. deviceList.append(device);
  201. }
  202. }
  203. }
  204. emit deviceListUpdated(deviceList);
  205. } else
  206. return;
  207. }
  208. }
  209. }
  210. void SdbConnector::_q_tcpDisconnected()
  211. {
  212. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  213. m_commandResponseTimer->stop();
  214. m_socket->disconnect(this);
  215. m_socket->deleteLater();
  216. m_socket = NULL;
  217. m_retry = 0;
  218. m_state = SdbDisconnected;
  219. emit stateChanged(SdbDisconnected);
  220. }
  221. void SdbConnector::_q_socketError(QAbstractSocket::SocketError error)
  222. {
  223. Q_UNUSED(error);
  224. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Error =" << error << "and error string =" << m_socket->errorString();
  225. m_commandResponseTimer->stop();
  226. if(m_state == SdbConnecting) {
  227. m_socket->disconnect(this);
  228. m_socket->deleteLater();
  229. m_socket = NULL;
  230. if (m_retry > 0) {
  231. m_state = SdbError;
  232. m_retry = 0;
  233. emit stateChanged(SdbError);
  234. return;
  235. }
  236. m_state = SdbRestarting;
  237. m_sdbProcess = new QProcess(this);
  238. connect(m_sdbProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(_q_finished(int,QProcess::ExitStatus)));
  239. m_sdbProcess->start(m_sdbPath, QStringList() << QLatin1String("start-server"));
  240. emit stateChanged(SdbRestarting);
  241. } else if(m_state == SdbConnected) {
  242. m_socket->disconnect(this);
  243. m_socket->deleteLater();
  244. m_socket = NULL;
  245. m_state = SdbDisconnected;
  246. m_retry = 0;
  247. emit stateChanged(SdbDisconnected);
  248. }
  249. }
  250. void SdbConnector::_q_finished(int exitCode, QProcess::ExitStatus exitStatus)
  251. {
  252. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Exit code =" << exitCode << "Status =" << exitStatus <<
  253. "Error =" << m_sdbProcess->errorString();
  254. QString output = QString::fromLatin1(m_sdbProcess->readAll());
  255. QRegularExpression rePortLine(QStringLiteral("daemon not running. starting it now on port \\d*"));
  256. QRegularExpression rePort(QStringLiteral("\\d+"));
  257. output = rePortLine.match(output).captured();
  258. output = rePort.match(output).captured();
  259. if (output.isEmpty()) {
  260. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Can't determine the sdb server port";
  261. m_sdbPort = DefaultServerPort;
  262. } else
  263. m_sdbPort = output.toInt();
  264. m_sdbProcess->deleteLater();
  265. m_sdbProcess = NULL;
  266. if(exitStatus == QProcess::NormalExit && exitCode == 0) {
  267. m_startWait->start();
  268. } else {
  269. m_state = SdbError;
  270. m_retry = 0;
  271. emit stateChanged(SdbError);
  272. }
  273. }
  274. void SdbConnector::_q_startWaitTimeout()
  275. {
  276. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  277. ++m_retry;
  278. startConnecting();
  279. }
  280. QTcpSocket * SdbConnector::createChannel(QObject *parent)
  281. {
  282. if(m_state != SdbConnected)
  283. return NULL;
  284. QTcpSocket * socket = new QTcpSocket(parent);
  285. socket->connectToHost(QHostAddress::LocalHost, m_sdbPort);
  286. return socket;
  287. }
  288. void SdbConnector::_q_commandTimeout()
  289. {
  290. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Command timeout in state" << m_state;
  291. if(m_state == SdbConnecting) {
  292. m_socket->disconnect(this);
  293. m_socket->deleteLater();
  294. m_socket = NULL;
  295. QFileInfo fi(m_sdbPath);
  296. if( m_retry > 0) {
  297. m_state = SdbError;
  298. m_retry = 0;
  299. emit stateChanged(SdbError);
  300. return;
  301. }
  302. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Try starting SDB";
  303. m_state = SdbRestarting;
  304. m_sdbProcess = new QProcess(this);
  305. connect(m_sdbProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(_q_finished(int,QProcess::ExitStatus)));
  306. m_sdbProcess->start(m_sdbPath, QStringList() << QLatin1String("start-server"));
  307. emit stateChanged(SdbRestarting);
  308. } else if(m_state == SdbConnected) {
  309. m_socket->disconnect(this);
  310. m_socket->deleteLater();
  311. m_socket = NULL;
  312. m_state = SdbError;
  313. m_retry = 0;
  314. emit stateChanged(SdbError);
  315. }
  316. }
  317. } //namespace Internal
  318. } //namespace Tizen