PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/rinputd_1.0.4/common/Connection.cpp

#
C++ | 378 lines | 300 code | 50 blank | 28 comment | 66 complexity | bd945141b07ddcb70f03511cca52a7b7 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Copyright (C) 2009 Chase Douglas
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as published
  6. * by the Free Software Foundation.
  7. *
  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. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. *
  17. * In addition, as a special exception, the copyright holders give
  18. * permission to link the code of portions of this program with the
  19. * OpenSSL library under certain conditions as described in each
  20. * individual source file, and distribute linked combinations
  21. * including the two.
  22. * You must obey the GNU General Public License in all respects
  23. * for all of the code used other than OpenSSL. If you modify
  24. * file(s) with this exception, you may extend this exception to your
  25. * version of the file(s), but you are not obligated to do so. If you
  26. * do not wish to do so, delete this exception statement from your
  27. * version.
  28. */
  29. #include <errno.h>
  30. #include <netinet/in.h>
  31. #include <netinet/tcp.h>
  32. #include <sys/socket.h>
  33. #include <QPair>
  34. #include <QHostAddress>
  35. #include <QSslConfiguration>
  36. #include "Connection.h"
  37. #include "macros.h"
  38. Connection::Connection(int sock, QSslConfiguration &configuration) :
  39. state(BARE),
  40. communicating(FALSE),
  41. type(SERVER),
  42. credentialsSize(0) {
  43. socket.setSocketDescriptor(sock);
  44. socket.setSslConfiguration(configuration);
  45. connect(&socket, SIGNAL(connected()), SLOT(sockConnected()));
  46. connect(&socket, SIGNAL(disconnected()), SLOT(sockDisconnected()));
  47. connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sockError()));
  48. connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(sslErrors(const QList<QSslError> &)));
  49. connect(&socket, SIGNAL(encrypted()), SLOT(sockEncrypted()));
  50. connect(&socket, SIGNAL(readyRead()), SLOT(sockReadyRead()));
  51. connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(bytesWritten(qint64)));
  52. connect(this, SIGNAL(disconnectSignal()), SLOT(disconnect()));
  53. int yes = 1;
  54. if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes))) {
  55. qWarning("Warning: Keepalive socket option set failed, dead connections will persist: %s", strerror(errno));
  56. }
  57. int time = 1;
  58. #ifdef TCP_KEEPIDLE
  59. if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &time, sizeof(time))) {
  60. #else
  61. if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &time, sizeof(time))) {
  62. #endif
  63. qWarning("Warning: Keepalive idle time could not be set: %s", strerror(errno));
  64. }
  65. }
  66. Connection::Connection(QString &hostname, quint16 port) :
  67. state(BARE),
  68. communicating(FALSE),
  69. type(CLIENT) {
  70. connect(&socket, SIGNAL(connected()), SLOT(sockConnected()));
  71. connect(&socket, SIGNAL(disconnected()), SLOT(sockDisconnected()));
  72. connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sockError()));
  73. connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(sslErrors(const QList<QSslError> &)));
  74. connect(&socket, SIGNAL(encrypted()), SLOT(sockEncrypted()));
  75. connect(&socket, SIGNAL(readyRead()), SLOT(sockReadyRead()));
  76. connect(&socket, SIGNAL(bytesWritten(qint64)), SLOT(bytesWritten(qint64)));
  77. connect(this, SIGNAL(disconnectSignal()), SLOT(disconnect()));
  78. int yes = 1;
  79. if (setsockopt(socket.socketDescriptor(), SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes))) {
  80. qWarning("Warning: Keepalive socket option set failed, dead connections will persist: %s", strerror(errno));
  81. }
  82. int time = 1;
  83. #ifdef TCP_KEEPIDLE
  84. if (setsockopt(socket.socketDescriptor(), SOL_TCP, TCP_KEEPIDLE, &time, sizeof(time))) {
  85. #else
  86. if (setsockopt(socket.socketDescriptor(), IPPROTO_TCP, TCP_KEEPALIVE, &time, sizeof(time))) {
  87. #endif
  88. qWarning("Warning: Keepalive idle time could not be set: %s", strerror(errno));
  89. }
  90. socket.connectToHost(hostname, port);
  91. }
  92. void Connection::sockConnected() {
  93. emit connected();
  94. }
  95. void Connection::sockDisconnected() {
  96. qWarning("%s disconnected", qPrintable(socket.peerAddress().toString()));
  97. emit disconnected();
  98. }
  99. void Connection::startEncryption() {
  100. if (type == CLIENT) {
  101. socket.startClientEncryption();
  102. }
  103. else {
  104. socket.startServerEncryption();
  105. }
  106. qDebug("Starting encryption for %s", qPrintable(socket.peerAddress().toString()));
  107. }
  108. void Connection::sockEncrypted() {
  109. state = ENCRYPTED;
  110. qDebug("Connection from %s is encrypted", qPrintable(socket.peerAddress().toString()));
  111. emit encrypted();
  112. }
  113. void Connection::startAuthentication() {
  114. state = AUTHENTICATING;
  115. if (type == CLIENT) {
  116. QByteArray message;
  117. message.append('\0');
  118. message.append(CONFIG("user").toString());
  119. message.append('\0');
  120. message.append(CONFIG("pass").toString());
  121. message.append('\0');
  122. if (message.length() > 255) {
  123. qCritical("Error: Credentials are too long");
  124. disconnect();
  125. return;
  126. }
  127. message.prepend((unsigned char)message.length());
  128. sockWrite(message);
  129. }
  130. qDebug("Starting authentication with %s", qPrintable(socket.peerAddress().toString()));
  131. }
  132. void Connection::startCommunication() {
  133. communicating = TRUE;
  134. if (socket.bytesAvailable()) {
  135. sockReadyRead();
  136. }
  137. qDebug("Starting communication with %s", qPrintable(socket.peerAddress().toString()));
  138. }
  139. QHostAddress Connection::peerAddress() {
  140. return socket.peerAddress();
  141. }
  142. void Connection::sockReadyRead() {
  143. if (state == AUTHENTICATING) {
  144. if (type == CLIENT) {
  145. char message;
  146. qint64 ret = socket.read(&message, 1);
  147. if (ret < 0) {
  148. qCritical("Error: Failed to receive authentication message from server %s", qPrintable(socket.peerAddress().toString()));
  149. disconnect();
  150. }
  151. else if (ret == 1 && message == 'a') {
  152. state = AUTHENTICATED;
  153. qWarning("Authenticated to server %s", qPrintable(socket.peerAddress().toString()));
  154. emit authenticated();
  155. }
  156. else {
  157. qCritical("Error: Failed to authenticate to server %s", qPrintable(socket.peerAddress().toString()));
  158. }
  159. }
  160. else {
  161. if (!credentialsSize) {
  162. qint64 ret = socket.read((char *)&credentialsSize, 1);
  163. if (ret < 0 || ret > 1) {
  164. qCritical("Failed to read size of credentials from client %s", qPrintable(socket.peerAddress().toString()));
  165. disconnect();
  166. return;
  167. }
  168. if (ret == 0) {
  169. return;
  170. }
  171. if (credentialsSize < 5) {
  172. qCritical("Size of credentials from client %s invalid", qPrintable(socket.peerAddress().toString()));
  173. disconnect();
  174. return;
  175. }
  176. }
  177. buffer += socket.read(credentialsSize - buffer.length());
  178. if (buffer.length() == credentialsSize) {
  179. qDebug("Read credentials from client %s", qPrintable(socket.peerAddress().toString()));
  180. if (buffer.at(0) != '\0' || buffer.count('\0') != 3) {
  181. qCritical("Error: Credentials format incorrect");
  182. disconnect();
  183. return;
  184. }
  185. buffer.remove(0, 1);
  186. int index = buffer.indexOf('\0');
  187. if (index < 0) {
  188. qCritical("Error: Credentials format incorrect");
  189. buffer.clear();
  190. disconnect();
  191. return;
  192. }
  193. if (buffer.at(buffer.length() - 1) != '\0') {
  194. qCritical("Error: Credentials format incorrect");
  195. disconnect();
  196. return;
  197. }
  198. buffer.remove(buffer.length() - 1, 1);
  199. QByteArray user(buffer.left(index));
  200. QByteArray pass(buffer.right(buffer.length() - (index + 1)));
  201. buffer.fill(0);
  202. emit checkPass(user, pass);
  203. user.fill(0);
  204. pass.fill(0);
  205. }
  206. }
  207. }
  208. else if (communicating) {
  209. emit readyRead();
  210. }
  211. }
  212. void Connection::sockError() {
  213. if (socket.error() == QAbstractSocket::RemoteHostClosedError) {
  214. return;
  215. }
  216. qCritical("Error from %s: %s", qPrintable(socket.peerAddress().toString()), qPrintable(socket.errorString()));
  217. if (socket.error() == QAbstractSocket::ConnectionRefusedError) {
  218. emit disconnected();
  219. }
  220. else {
  221. disconnect();
  222. }
  223. }
  224. void Connection::sslErrors(const QList<QSslError> &errors) {
  225. bool ignore = TRUE;
  226. for (int i = 0; i < errors.count(); i++) {
  227. switch(errors[i].error()) {
  228. case QSslError::HostNameMismatch:
  229. case QSslError::SelfSignedCertificate:
  230. qCritical("Security Layer Warning for %s: %s", qPrintable(socket.peerAddress().toString()), qPrintable(errors[i].errorString()));
  231. break;
  232. default:
  233. qCritical("An SSL error from %s occurred: %s", qPrintable(socket.peerAddress().toString()), qPrintable(errors[i].errorString()));
  234. ignore = FALSE;
  235. break;
  236. }
  237. }
  238. if (ignore) {
  239. socket.ignoreSslErrors();
  240. }
  241. else {
  242. qCritical("Exiting connection due to error(s)");
  243. disconnect();
  244. }
  245. }
  246. void Connection::bytesWritten(qint64 size) {
  247. qDebug("%lld bytes written to %s", size, qPrintable(socket.peerAddress().toString()));
  248. }
  249. void Connection::checkPassResult(bool ok) {
  250. if (ok) {
  251. state = AUTHENTICATED;
  252. sockWrite("a");
  253. qWarning("Client %s authenticated", qPrintable(socket.peerAddress().toString()));
  254. emit authenticated();
  255. }
  256. else {
  257. sockWrite("i");
  258. qCritical("Error: Client %s failed to authenticate", qPrintable(socket.peerAddress().toString()));
  259. disconnect();
  260. }
  261. }
  262. bool Connection::sockWrite(const char *data, qint64 maxSize) {
  263. qint64 written = 0;
  264. qDebug("Writing %lld bytes: '%s'", maxSize, data);
  265. while (written < maxSize) {
  266. qint64 ret;
  267. ret = socket.write(data + written, maxSize - written);
  268. if (ret < 0) {
  269. qWarning("Failed to send complete data buffer");
  270. return false;
  271. }
  272. written += ret;
  273. }
  274. return true;
  275. }
  276. bool Connection::sockWrite(const char *data) {
  277. return sockWrite(data, qstrlen(data));
  278. }
  279. bool Connection::sockWrite(const QByteArray &byteArray) {
  280. return sockWrite(byteArray.data(), byteArray.length());
  281. }
  282. qint64 Connection::bytesAvailable() {
  283. if (state == AUTHENTICATING) {
  284. return 0;
  285. }
  286. return socket.bytesAvailable();
  287. }
  288. qint64 Connection::peek(char *data, qint64 maxSize) {
  289. if (state == AUTHENTICATING) {
  290. return 0;
  291. }
  292. return socket.peek(data, maxSize);
  293. }
  294. qint64 Connection::read(char *data, qint64 maxSize) {
  295. if (state == AUTHENTICATING) {
  296. return 0;
  297. }
  298. return socket.read(data, maxSize);
  299. }
  300. QByteArray Connection::read(qint64 maxSize) {
  301. if (state == AUTHENTICATING) {
  302. return QByteArray();
  303. }
  304. return socket.read(maxSize);
  305. }
  306. QByteArray Connection::readAll() {
  307. if (state == AUTHENTICATING) {
  308. return QByteArray();
  309. }
  310. return socket.readAll();
  311. }
  312. bool Connection::write(const QByteArray &message) {
  313. if (state == AUTHENTICATING) {
  314. return false;
  315. }
  316. return sockWrite(message);
  317. }
  318. void Connection::disconnect() {
  319. qWarning("Closing connection to %s", qPrintable(socket.peerAddress().toString()));
  320. socket.flush();
  321. socket.disconnectFromHost();
  322. }
  323. void Connection::disconnectLater() {
  324. emit disconnectSignal();
  325. }
  326. Connection::~Connection() {
  327. disconnect();
  328. }