sdbconnector.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. Q_LOGGING_CATEGORY(QTC_TIZEN_SDBCONNECTOR, "qtcreator.plugin.tizen.sdbconnector")
  39. const int DefaultServerPort=26099;
  40. namespace Tizen {
  41. namespace Internal {
  42. SdbConnector::SdbConnector(QObject *parent) :
  43. QObject(parent),
  44. m_socket(0),
  45. m_sdbProcess(0),
  46. m_state(SdbDisconnected),
  47. m_sdbPort(DefaultServerPort),
  48. m_startWait(0),
  49. m_retry(0)
  50. {
  51. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  52. m_startWait = new QTimer(this);
  53. connect(m_startWait, SIGNAL(timeout()), SLOT(_q_startWaitTimeout()));
  54. m_startWait->setInterval(1000);
  55. m_startWait->setSingleShot(true);
  56. m_commandResponseTimer = new QTimer(this);
  57. connect(m_commandResponseTimer, SIGNAL(timeout()), SLOT(_q_commandTimeout()));
  58. m_commandResponseTimer->setSingleShot(true);
  59. m_commandResponseTimer->setInterval(500);
  60. }
  61. SdbConnector::~SdbConnector()
  62. {
  63. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  64. }
  65. int SdbConnector::serverPort() const
  66. {
  67. return m_sdbPort;
  68. }
  69. QString SdbConnector::sdbPath() const
  70. {
  71. return m_sdbPath;
  72. }
  73. void SdbConnector::setSdbPath(const QString& path)
  74. {
  75. m_sdbPath = path;
  76. }
  77. SdbState SdbConnector::state() const
  78. {
  79. return m_state;
  80. }
  81. void SdbConnector::startConnector()
  82. {
  83. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "State:" << m_state;
  84. if (m_sdbPath.isEmpty()) {
  85. qCWarning(QTC_TIZEN_SDBCONNECTOR) << "SDB path empty";
  86. return;
  87. }
  88. if(!QFile::exists(m_sdbPath)) {
  89. qCWarning(QTC_TIZEN_SDBCONNECTOR) << "SDB executable not found in " << m_sdbPath;
  90. return;
  91. }
  92. if (QProcess::execute(m_sdbPath, QStringList() << QStringLiteral("kill-server"))) {
  93. qCWarning(QTC_TIZEN_SDBCONNECTOR) << "Error encountered while running " << m_sdbPath << " kill-server";
  94. }
  95. if(m_state == SdbDisconnected || m_state == SdbError) {
  96. startConnecting();
  97. } else if(m_state == SdbDisconnecting) {
  98. m_socket->disconnect(this);
  99. m_socket->deleteLater();
  100. m_socket = NULL;
  101. m_retry = 0;
  102. startConnecting();
  103. }
  104. }
  105. void SdbConnector::stopConnector()
  106. {
  107. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "State:" << m_state;
  108. m_commandResponseTimer->stop();
  109. if(m_state == SdbConnecting) {
  110. m_socket->disconnect(this);
  111. m_socket->deleteLater();
  112. m_socket = NULL;
  113. m_retry = 0;
  114. m_state = SdbDisconnected;
  115. emit stateChanged(SdbDisconnected);
  116. } else if(m_state == SdbConnected) {
  117. m_socket->disconnectFromHost();
  118. } else if(m_state == SdbDisconnecting) {
  119. } else if(m_state == SdbRestarting) {
  120. m_startWait->stop();
  121. m_retry = 0;
  122. }
  123. }
  124. void SdbConnector::startConnecting()
  125. {
  126. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Port:" << m_sdbPort;
  127. if(m_state != SdbConnecting) {
  128. m_state = SdbConnecting;
  129. emit stateChanged(m_state);
  130. }
  131. m_socket = new QTcpSocket(this);
  132. connect(m_socket, SIGNAL(connected()), SLOT(_q_tcpConnected()));
  133. connect(m_socket, SIGNAL(readyRead()), SLOT(_q_readyRead()));
  134. connect(m_socket, SIGNAL(disconnected()), SLOT(_q_tcpDisconnected()));
  135. connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(_q_socketError(QAbstractSocket::SocketError)));
  136. m_socket->connectToHost(QHostAddress::LocalHost, m_sdbPort);
  137. m_commandResponseTimer->start(1000);
  138. }
  139. void SdbConnector::_q_tcpConnected()
  140. {
  141. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Local port:" << m_socket->localPort();
  142. m_commandResponseTimer->stop();
  143. m_state = SdbConnected;
  144. m_protoState = WaitingForDeviceListResp;
  145. m_socket->write(SdbPacketUtils::makeRequest(QByteArray("host:track-devices")));
  146. m_commandResponseTimer->start();
  147. emit stateChanged(SdbConnected);
  148. }
  149. void SdbConnector::_q_readyRead()
  150. {
  151. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "m_socket->atEnd():" << m_socket->atEnd() << "m_protoState:" << m_protoState ;
  152. while(!m_socket->atEnd()) {
  153. if(m_protoState == WaitingForDeviceListResp) {
  154. SdbResponse resp;
  155. if(SdbPacketUtils::parseResponse(m_socket, SdbPacketUtils::DontReadDiagnosticString, resp)) {
  156. m_commandResponseTimer->stop();
  157. m_protoState = WaitingForDeviceListHeader;
  158. if(!resp.okay) {
  159. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "[SdbConnector] Failed to query device list";
  160. }
  161. }
  162. }
  163. if(m_protoState == WaitingForDeviceListHeader) {
  164. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "m_socket->bytesAvailable():" << m_socket->bytesAvailable();
  165. if(m_socket->bytesAvailable() >= 4) {
  166. char hdr[5];
  167. if(m_socket->read(hdr, 4) != 4)
  168. return;
  169. hdr[4] = 0;
  170. sscanf(hdr, "%X", &m_packetLength);
  171. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "m_packetLength:" << m_packetLength;
  172. m_protoState = WaitingForDeviceListData;
  173. } else {
  174. return;
  175. }
  176. }
  177. if(m_protoState == WaitingForDeviceListData) {
  178. if(m_socket->bytesAvailable() >= m_packetLength) {
  179. SdbDeviceList deviceList;
  180. m_protoState = WaitingForDeviceListHeader;
  181. if (m_packetLength > 0) {
  182. QByteArray string = m_socket->read(m_packetLength);
  183. QList<QByteArray> lines = string.split('\n');
  184. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "received list update" << string;
  185. if(!lines.empty())
  186. deviceList.reserve(lines.size());
  187. foreach(const QByteArray& line, lines) {
  188. QList<QByteArray> params = line.split('\t');
  189. if(params.length() == 3) {
  190. SdbDevice device;
  191. device.serialNumber = params.at(0).trimmed();
  192. device.name = QString::fromUtf8(params.at(2));
  193. QByteArray deviceState = params.at(1).trimmed();
  194. if(deviceState == "offline") {
  195. device.state = SdbDevice::Offline;
  196. } else if(deviceState == "device") {
  197. device.state = SdbDevice::Device;
  198. } else {
  199. device.state = SdbDevice::Unknown;
  200. }
  201. deviceList.append(device);
  202. }
  203. }
  204. }
  205. emit deviceListUpdated(deviceList);
  206. } else
  207. return;
  208. }
  209. }
  210. }
  211. void SdbConnector::_q_tcpDisconnected()
  212. {
  213. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  214. m_commandResponseTimer->stop();
  215. m_socket->disconnect(this);
  216. m_socket->deleteLater();
  217. m_socket = NULL;
  218. m_retry = 0;
  219. m_state = SdbDisconnected;
  220. emit stateChanged(SdbDisconnected);
  221. }
  222. void SdbConnector::_q_socketError(QAbstractSocket::SocketError error)
  223. {
  224. Q_UNUSED(error);
  225. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Error =" << error << "and error string =" << m_socket->errorString();
  226. m_commandResponseTimer->stop();
  227. if(m_state == SdbConnecting) {
  228. m_socket->disconnect(this);
  229. m_socket->deleteLater();
  230. m_socket = NULL;
  231. if (m_retry > 0) {
  232. m_state = SdbError;
  233. m_retry = 0;
  234. emit stateChanged(SdbError);
  235. return;
  236. }
  237. m_state = SdbRestarting;
  238. m_sdbProcess = new QProcess(this);
  239. connect(m_sdbProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(_q_finished(int,QProcess::ExitStatus)));
  240. m_sdbProcess->start(m_sdbPath, QStringList() << QLatin1String("start-server"));
  241. emit stateChanged(SdbRestarting);
  242. } else if(m_state == SdbConnected) {
  243. m_socket->disconnect(this);
  244. m_socket->deleteLater();
  245. m_socket = NULL;
  246. m_state = SdbDisconnected;
  247. m_retry = 0;
  248. emit stateChanged(SdbDisconnected);
  249. }
  250. }
  251. void SdbConnector::_q_finished(int exitCode, QProcess::ExitStatus exitStatus)
  252. {
  253. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Exit code =" << exitCode << "Status =" << exitStatus <<
  254. "Error =" << m_sdbProcess->errorString();
  255. QString output = QString::fromLatin1(m_sdbProcess->readAll());
  256. QRegularExpression rePortLine(QStringLiteral("daemon not running. starting it now on port \\d*"));
  257. QRegularExpression rePort(QStringLiteral("\\d+"));
  258. output = rePortLine.match(output).captured();
  259. output = rePort.match(output).captured();
  260. if (output.isEmpty()) {
  261. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Can't determine the sdb server port";
  262. m_sdbPort = DefaultServerPort;
  263. } else
  264. m_sdbPort = output.toInt();
  265. m_sdbProcess->deleteLater();
  266. m_sdbProcess = NULL;
  267. if(exitStatus == QProcess::NormalExit && exitCode == 0) {
  268. m_startWait->start();
  269. } else {
  270. m_state = SdbError;
  271. m_retry = 0;
  272. emit stateChanged(SdbError);
  273. }
  274. }
  275. void SdbConnector::_q_startWaitTimeout()
  276. {
  277. qCDebug(QTC_TIZEN_SDBCONNECTOR);
  278. ++m_retry;
  279. startConnecting();
  280. }
  281. QTcpSocket * SdbConnector::createChannel(QObject *parent)
  282. {
  283. if(m_state != SdbConnected)
  284. return NULL;
  285. QTcpSocket * socket = new QTcpSocket(parent);
  286. socket->connectToHost(QHostAddress::LocalHost, m_sdbPort);
  287. return socket;
  288. }
  289. void SdbConnector::_q_commandTimeout()
  290. {
  291. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Command timeout in state" << m_state;
  292. if(m_state == SdbConnecting) {
  293. m_socket->disconnect(this);
  294. m_socket->deleteLater();
  295. m_socket = NULL;
  296. QFileInfo fi(m_sdbPath);
  297. if( m_retry > 0) {
  298. m_state = SdbError;
  299. m_retry = 0;
  300. emit stateChanged(SdbError);
  301. return;
  302. }
  303. qCDebug(QTC_TIZEN_SDBCONNECTOR) << "Try starting SDB";
  304. m_state = SdbRestarting;
  305. m_sdbProcess = new QProcess(this);
  306. connect(m_sdbProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(_q_finished(int,QProcess::ExitStatus)));
  307. m_sdbProcess->start(m_sdbPath, QStringList() << QLatin1String("start-server"));
  308. emit stateChanged(SdbRestarting);
  309. } else if(m_state == SdbConnected) {
  310. m_socket->disconnect(this);
  311. m_socket->deleteLater();
  312. m_socket = NULL;
  313. m_state = SdbError;
  314. m_retry = 0;
  315. emit stateChanged(SdbError);
  316. }
  317. }
  318. } //namespace Internal
  319. } //namespace Tizen