summaryrefslogblamecommitdiffstats
path: root/src/net/pvsClientConnection.cpp
blob: 9f66562e18ee96d3d658e164b118f3a79770590b (plain) (tree)







































































































































                                                                                                                                  
                                          


























                                                                  












                                                                    
/*
# Copyright (c) 2009,2010 - OpenSLX Project, Computer Center University of
# Freiburg
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# pvsClientConnection.cpp
#    - ???.
# -----------------------------------------------------------------------------
*/

#include "pvsClientConnection.h"
#include "pvsListenServer.h"
#include "src/util/consoleLogger.h"

#include <cassert>
#include <QtNetwork/QHostAddress>


PVSClientConnection::PVSClientConnection(PVSListenServer* server, QSslSocket* sock)
{
    assert(sock);
    assert(server);
    _socket = sock;
    _incomplete = NULL;
    _toldDisconnect = false;
    _server = server;
    _lastData = time(NULL);
    sock->setParent(this); // for automatic deletion
    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)));
}

PVSClientConnection::~PVSClientConnection()
{
    this->closeConnection();
    if (_incomplete != NULL) delete _incomplete;
    if (_socket != NULL)
    {
        disconnect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
        disconnect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed()));
        disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError)));
    	_socket->abort();
    }
}

void PVSClientConnection::closeConnection()
{
	if (_toldDisconnect) return; // we already got served
    if (_socket == NULL || _socket->state() == QAbstractSocket::UnconnectedState)
    {
        // should not happen but handled anyway
        _toldDisconnect = true;
        _server->disconnectClient(this);
        return;
    }
    if (_socket->state() == QAbstractSocket::ClosingState) return; // sock_close() slot should eventually be called, nothing to do
    if (_socket->state() == QAbstractSocket::ConnectedState)   // this is what should be the case normally
    {
        _socket->disconnectFromHost(); // graceful shutdown of socket, sock_close() will be called once complete
        return;
    }
    // otherwise the socket is in some unknown state, so do a harsh shutdown
    _socket->abort();
    _toldDisconnect = true;
    _server->disconnectClient(this);
}

void PVSClientConnection::sock_dataArrival()
{
    if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState)
    {
        ConsoleLog writeError("dataArrival called in bad state");
        return;
    }

    _lastData = time(NULL);
    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->closeConnection();
                return;
            }
            if (retval == 1)   // message is complete
            {
                _server->handleClientMsg(_id, *_incomplete);
                delete _incomplete; // ...and delete...
                _incomplete = NULL; // ...so the next msg can be parsed
            }
        } while (retval == 1);
    }
}

void PVSClientConnection::sock_closed()
{
    // should this be unreliable in some way i suggest using the signal "stateChanged()" instead
    // and check if the state changed to unconnected.
    if (_toldDisconnect) return;
    _toldDisconnect = true;
    _server->disconnectClient(this);
}

void PVSClientConnection::sock_error(QAbstractSocket::SocketError errcode)
{
    this->closeConnection();
}

/*
void PVSClientConnection::push_back_receive(PVSMsg newMsg)
{
    _recQueue.push_back(newMsg);
}
*/

bool PVSClientConnection::push_back_send(PVSMsg newMsg)
{
    if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) return false;
    newMsg.setSndID(_id);
    int len;
    char data[2000];
    char *tmp = data;
    if (!newMsg.getBinaryData(tmp, len))
    {
        qDebug("Message empty. Ignored.");
        return false;
    }
    QByteArray ba;
    ba.append(tmp, len);
    int ret = (int)_socket->write(ba);
    //printf("Sent %d of %d bytes.\n", ret, len);
    if (ret == -1)
    {
        this->closeConnection();
        return false;
    }
    return true;
}

QSslSocket* PVSClientConnection::getSocket()
{
    return _socket;
}

void PVSClientConnection::setID(unsigned int id)
{
    _id = id;
    this->push_back_send(PVSMsg(PVSLOGIN, "ID", int2String(_id)));
}

void PVSClientConnection::ping()
{
    this->push_back_send(PVSMsg(PVSCOMMAND, "PING", "HELLO?", _id));
}

QString PVSClientConnection::getAddress()
{
    if (_socket == NULL) return QString();
    return _socket->peerAddress().toString();
}

QString PVSClientConnection::getNameUser()
{
	return getUserName();
}