/*
# 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();
}