From ce3329047d378a14006ce74ec273ac59e3375303 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 12 May 2010 19:42:27 +0200 Subject: initial import of latest svn version --- src/net/pvsServerConnection.cpp | 243 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/net/pvsServerConnection.cpp (limited to 'src/net/pvsServerConnection.cpp') diff --git a/src/net/pvsServerConnection.cpp b/src/net/pvsServerConnection.cpp new file mode 100644 index 0000000..04a1ef6 --- /dev/null +++ b/src/net/pvsServerConnection.cpp @@ -0,0 +1,243 @@ +#include "pvsServerConnection.h" +#include "src/util/consoleLogger.h" +#include "src/util/util.h" +#include "pvsMsg.h" +#include "src/pvs.h" +#include +#include "src/core/pvsChatClient.h" +#include "src/util/serviceDiscoveryUtil.h" +#include "src/net/pvsDiscoveredServer.h" +//#define verbose + +PVSServerConnection::PVSServerConnection(PVS *parent) : QObject(parent) +{ + _client = parent; + _incomplete = NULL; + _socket = NULL; + _timerId = 0; + _timer = 0; + _wasConnected = false; + loadCommands(); +} + +inline void PVSServerConnection::timerStop() +{ + if (_timer == 0) return; + killTimer(_timer); + _timer = 0; +} + +bool PVSServerConnection::connectToServer(PVSDiscoveredServer* server, QString passwd) +{ + QHostAddress host = server->getHost(); + if (_socket != NULL && _socket->state() == QAbstractSocket::ConnectedState + && _socket->peerAddress() == host) return false; + int port = server->getPort(); + if (port < 1 || port > 65535) port = SERVER_PORT_INT; + ConsoleLog writeNetwork("Connecting to host:"); + ConsoleLog writeNetwork(host.toString().toUtf8().data()); + timerStop(); + if (_socket != NULL) + { + _socket->blockSignals(true); + _socket->abort(); + _socket->deleteLater(); + } + _name = server->getName(); + _expectedFingerprint = server->getFingerprint(); + _passwd = passwd; + _socket = new QSslSocket(this); + connect(_socket, SIGNAL(encrypted()), this, SLOT(sock_connected())); + connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError))); + char tex[2000]; + snprintf(tex, 2000, "Connecting to %s on port %d", host.toString().toUtf8().data(), (int)port); + ConsoleLog writeNetwork(tex); + connect(_socket, + SIGNAL(sslErrors(const QList &)), + this, + SLOT(sslErrors(const QList &)) + ); + _socket->connectToHostEncrypted(host.toString(), port); + if (_timer == 0) _timer = startTimer(10000); + + return true; // we really don't know yet if it will succeed since its async +} + +void PVSServerConnection::sslErrors ( const QList & errors ) +{ + for (QList::const_iterator it = errors.begin(); it != errors.end(); it++) + { + QSslError err = *it; + printf("Connect SSL: %s\n", err.errorString().toUtf8().data()); + if (err.error() == QSslError::HostNameMismatch) continue; // We don't pay attention to hostnames for validation + if (err.error() == QSslError::SelfSignedCertificate) continue; // Also, this will always be the case; we check the fingerprint later + ConsoleLog writeNetwork(err.errorString().toUtf8().data()); + ConsoleLog writeNetwork("***** SSL ERROR, ABORTING *****"); + return; + } + _socket->ignoreSslErrors(); +} + +void PVSServerConnection::disconnectFromServer() +{ + if (_socket == NULL) return; + _socket->disconnectFromHost(); + handleDisconnectInternal(); +} + +void PVSServerConnection::timerEvent(QTimerEvent *event) +{ + if (_socket != NULL && _socket->state() == QAbstractSocket::ConnectedState) return; + // TODO: Check for ping timeout +} + +void PVSServerConnection::sendMessage(PVSMsg newMessage) +{ + if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) return; + char *data; + int len; + newMessage.getBinaryData(data, len); + QByteArray qba(data, len); + _socket->write(qba); +} + +void PVSServerConnection::ping() +{ + sendMessage(PVSMsg(PVSCOMMAND, "PING", "U THERE?"));; +} + +QString PVSServerConnection::getServerName() +{ + if (!isConnected()) return QString(); + return _name; +} + +void PVSServerConnection::loadCommands() +{ + addLoginHandler("ID", this, &PVSServerConnection::onID); + addCommandHandler("PING", this, &PVSServerConnection::onPing); +} + +void PVSServerConnection::onID(PVSMsg idmsg) +{ + _id = (unsigned int)string2Int(idmsg.getMessage()); +} + +void PVSServerConnection::onPing(PVSMsg pingmsg) +{ + if (pingmsg.getMessage().at(pingmsg.getMessage().size()-1) == '?') + { + sendMessage(PVSMsg(PVSCOMMAND, "PING", "HI!")); + } +} + +void PVSServerConnection::handleClientMsg(PVSMsg receiver) +{ + // FIXME: @SimonR, this line cuase problems with pvs in daemon mode and dbus + //qDebug("Got Message for this client: [%c][%s][%s]\n", (char)receiver.getType(), receiver.getIdent().toUtf8().data(), receiver.getMessage().toUtf8().data()); + if (receiver.getType() == PVSCOMMAND) + { + _commandDispatcher.fire(receiver.getIdent(), receiver); +// ConsoleLog writeNetwork(QString("Received a command and handled it.").append(receiver.getIdent().append(QString(":").append(receiver.getMessage())))); + } + else if (receiver.getType() == PVSMESSAGE) + { + _chatDispatcher.fire(receiver.getIdent(), receiver); + ConsoleLog writeNetwork(QString("Received a chat message and handled it.").append(receiver.getIdent().append(QString(":").append(receiver.getMessage())))); + } + else if (receiver.getType() == PVSLOGIN) + { + _loginDispatcher.fire(receiver.getIdent(), receiver); +// ConsoleLog writeNetwork(QString("Received a login and handled it. Ident: ").append(receiver.getIdent().append(QString(":")).append(receiver.getMessage()))); + } + else if (receiver.getType() == PVSUNKNOWN) + { + ConsoleLog writeNetwork(QString("Received an unknown type. Ident : ").append(receiver.getIdent().append(QString(" : ").append(receiver.getMessage())))); + } +} + +void PVSServerConnection::sock_dataArrival() +{ + if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) + { + ConsoleLog writeError("dataArrival called in bad state"); + return; + } + + while (_socket->bytesAvailable()) + { + int retval = 0; + do + { + if (_incomplete == NULL) _incomplete = new PVSMsg(); // we need a pvsmsg object + retval = _incomplete->readMessage(_socket); // let the message read data from socket + if (retval == -1) // error parsing msg, disconnect client! + { + this->disconnectFromServer(); + return; + } + if (retval == 1) // message is complete + { + this->handleClientMsg(*_incomplete); + delete _incomplete; // ...and delete... + _incomplete = NULL; // ...so the next msg can be parsed + } + } while (retval == 1); + } +} + +void PVSServerConnection::sock_closed() +{ + // should this be unreliable in some way i suggest using the signal "stateChanged()" instead + // and check if the state changed to unconnected. + ConsoleLog writeNetwork("Socket was closed... oh well.."); + handleDisconnectInternal(); +} + +void PVSServerConnection::sock_error(QAbstractSocket::SocketError errcode) +{ + char txt[204]; + snprintf(txt, 200, "Connection error: %d", (int)errcode); + ConsoleLog writeNetwork(txt); + handleDisconnectInternal(); +} + +// Send to server username and loginname. +void PVSServerConnection::sock_connected() +{ + QByteArray cert = _socket->peerCertificate().digest(QCryptographicHash::Sha1); + if (_expectedFingerprint != cert) + { // Nich mit mir, Freundchen! + disconnectFromServer(); + // Maybe you want to inform the user that there was a certificate mismatch + // and that it is very possible that the CIA is trying to eavesdrop on the connection + return; + } + ConsoleLog writeNetwork("Connected!"); + _wasConnected = true; + sendMessage( + PVSMsg(PVSLOGIN, "USERNAME", getFullUsername()+","+getenv("USER"))); + sendMessage( + PVSMsg(PVSLOGIN, "PASSWORD", _passwd)); + ConsoleLog writeNetwork("Sent Username and password."); + + _client->onConnected(_name); +} + +void PVSServerConnection::handleDisconnectInternal() +{ + _socket->blockSignals(true); + _socket->abort(); + _socket->deleteLater(); + _socket = NULL; + _name = QString(); + _client->securityUnlock(); + timerStop(); + if (_wasConnected) + { + _wasConnected = false; + _client->onDisconnected(); + } +} -- cgit v1.2.3-55-g7522