SshClient.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. GNU General Public License version 3 notice
  3. Copyright (C) 2012 Mihawk <luiz@netdome.biz>. All rights reserved.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see < http://www.gnu.org/licenses/ >.
  14. */
  15. #include "SshClient.h"
  16. #include "App.h"
  17. #include <QProcess>
  18. #include <QRegExp>
  19. #include <QDateTime>
  20. #include <QTimerEvent>
  21. #include <QStringList>
  22. #include <QDebug>
  23. SshClient::SshClient(App* app, QObject *parent) :
  24. QObject(parent),
  25. myApp(app),
  26. myProcess(new QProcess(this)),
  27. myCommandRegex(new QRegExp("^([0-9]{4}-[0-9]{2}-[0-9]{2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2})\\s(\\+[0-9]{4}):\\s(.+)$")),
  28. myConnectedFlag(false),
  29. myConnectionTimerID(0),
  30. myPingTimerID(0),
  31. myPongTimerID(0),
  32. myClients(new QStringList())
  33. {
  34. connect(myProcess, SIGNAL(readyRead()), SLOT(read()));
  35. connect(myProcess, SIGNAL(finished(int)), SLOT(exited(int)));
  36. }
  37. SshClient::~SshClient()
  38. {
  39. delete myCommandRegex;
  40. delete myClients;
  41. }
  42. bool SshClient::isConnected() const
  43. {
  44. return myConnectedFlag;
  45. }
  46. void SshClient::read()
  47. {
  48. QString data(myProcess->readAll().trimmed());
  49. if(data.isEmpty())
  50. return;
  51. QStringList lines = data.split("\n", QString::SkipEmptyParts);
  52. QString line;
  53. foreach(line, lines)
  54. {
  55. line = line.trimmed();
  56. if(myCommandRegex->indexIn(line) != -1)
  57. {
  58. QDateTime time = QDateTime::fromString(myCommandRegex->cap(1), "yyyy-MM-dd HH:mm:ss");
  59. time = time.addSecs(-myCommandRegex->cap(2).toInt()/100*60*60);
  60. parse(time,
  61. myCommandRegex->cap(3).section(' ', 0, 0),
  62. myCommandRegex->cap(3).section(' ', 1)
  63. );
  64. }
  65. }
  66. }
  67. void SshClient::exited(int)
  68. {
  69. reconnect();
  70. }
  71. void SshClient::ping()
  72. {
  73. write("PING\n");
  74. myPingTimerID = startTimer(30000);
  75. }
  76. void SshClient::pong()
  77. {
  78. killTimer(myPingTimerID);
  79. myPongTimerID = startTimer(30000);
  80. }
  81. void SshClient::write(const QString &data)
  82. {
  83. myProcess->write(data.toAscii());
  84. myProcess->waitForBytesWritten();
  85. }
  86. void SshClient::parse(const QDateTime &time, const QString &command, const QString &commandData)
  87. {
  88. /* JOINED - Another user has just joined central */
  89. if(command == "JOINED")
  90. {
  91. QRegExp a("^User '([a-zA-Z]+)'.+$");
  92. if(a.indexIn(commandData) != -1)
  93. {
  94. if(!myClients->contains(a.capturedTexts().at(1)))
  95. myClients->push_back(a.capturedTexts().at(1));
  96. }
  97. return;
  98. }
  99. /* PARTED - Another user has left central */
  100. if(command == "PARTED")
  101. {
  102. QRegExp a("^User '([a-zA-Z]+)'.+$");
  103. if(a.indexIn(commandData) != -1)
  104. myClients->removeAll(a.capturedTexts().at(1));
  105. return;
  106. }
  107. /* HELLO - Server acknowledge */
  108. if(command == "HELLO")
  109. {
  110. ping();
  111. myConnectedFlag = true;
  112. killTimer(myConnectionTimerID);
  113. emit connected();
  114. return;
  115. }
  116. /* PING PONG - The connection is still up */
  117. if(command == "PONG")
  118. {
  119. pong();
  120. return;
  121. }
  122. /* SYS - Central generic message */
  123. if(command == "SYS")
  124. {
  125. myApp->print("Central Message: " + commandData + "\n");
  126. return;
  127. }
  128. /* BC - Broadcast order from central */
  129. if(command == "BC")
  130. {
  131. QRegExp a("^([A-Za-z0-9]+) (.+),(.+),(.+),'(.+)','(.+)'$");
  132. if(a.indexIn(commandData) == -1)
  133. return;
  134. int serverCount, userCount;
  135. myApp->broadcast(a.cap(3) + " " + a.cap(5) + " - " + a.cap(4) + " : " + a.cap(6), &serverCount, &userCount);
  136. if(userCount)
  137. write("BC_RE " + a.cap(1) + " Players=" + QString::number(userCount) + ",Servers=" + QString::number(serverCount) + "\n");
  138. return;
  139. }
  140. /* BC_ID - Broadcast reply with the ID of the broadcast you just generated */
  141. if(command == "BC_ID")
  142. {
  143. //BC_ID 4e5fca581569e168c7a86a0a9a91949f for: QDEV,-dev-,qw://123.123
  144. QRegExp a("^([A-Za-z0-9]+) for: .+,-(.+)-,qw://(.+)$");
  145. if(a.indexIn(commandData) == -1)
  146. return;
  147. QString hash = a.cap(1);
  148. //QString frequency = a.cap(2);
  149. QString server = a.cap(3);
  150. myApp->setReplyHash(server, hash);
  151. return;
  152. }
  153. /* BC_RE - Broadcast reply to increment the counters */
  154. if(command == "BC_RE")
  155. {
  156. QRegExp a("^([A-Za-z0-9]+) (Users|Players)=([0-9]+),(Channels|Servers)=([0-9]+)$");
  157. if(a.indexIn(commandData) == -1)
  158. return;
  159. QString hash = a.cap(1);
  160. QString userType = a.cap(2);
  161. QString channelType = a.cap(4);
  162. int userCount = 0;
  163. int channelCount = 0;
  164. int playerCount = 0;
  165. int serverCount = 0;
  166. if(userType == "Users")
  167. {
  168. userCount = a.cap(3).toInt();
  169. playerCount = 0;
  170. }
  171. else if(userType == "Players")
  172. {
  173. playerCount = a.cap(3).toInt();
  174. userCount = 0;
  175. }
  176. if(channelType == "Channels")
  177. {
  178. channelCount = a.cap(5).toInt();
  179. serverCount = 0;
  180. }
  181. else if(channelType == "Servers")
  182. {
  183. serverCount = a.cap(5).toInt();
  184. channelCount = 0;
  185. }
  186. myApp->incrementReplyCounters(hash, userCount, channelCount, playerCount, serverCount);
  187. return;
  188. }
  189. myApp->print("Unparsed cmd from central: " + time.toString() + " " + command + " " + commandData + "\n");
  190. }
  191. bool SshClient::connectToHost(const QString &user, const QString &host)
  192. {
  193. myProcess->start("ssh", QStringList() << user + "@" + host);
  194. myUsername = user;
  195. myHostname = host;
  196. bool r = myProcess->waitForStarted();
  197. if(!r)
  198. return false;
  199. else
  200. {
  201. myConnectionTimerID = startTimer(30000);
  202. return true;
  203. }
  204. }
  205. void SshClient::reconnect()
  206. {
  207. if(!myUsername.isEmpty() && !myHostname.isEmpty())
  208. connectToHost(myUsername, myHostname);
  209. }
  210. void SshClient::disconnectFromHost()
  211. {
  212. killTimer(myConnectionTimerID);
  213. killTimer(myPingTimerID);
  214. killTimer(myPongTimerID);
  215. myProcess->terminate();
  216. myProcess->waitForFinished();
  217. myConnectedFlag = false;
  218. }
  219. void SshClient::timerEvent(QTimerEvent *e)
  220. {
  221. if(e->timerId() == myConnectionTimerID)
  222. {
  223. disconnectFromHost();
  224. emit error(ConnectionTimedOutError);
  225. return;
  226. }
  227. if(e->timerId() == myPingTimerID)
  228. {
  229. disconnectFromHost();
  230. emit error(ConnectionTimedOutError);
  231. return;
  232. }
  233. if(e->timerId() == myPongTimerID)
  234. {
  235. killTimer(myPongTimerID);
  236. ping();
  237. return;
  238. }
  239. }