mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-19 12:10:45 +00:00
392 lines
12 KiB
C++
392 lines
12 KiB
C++
|
#include "protocol.h"
|
|||
|
|
|||
|
QString ClientProtocol::unconnectedNoDstHost = QString("socket unconnected, no dstHost");
|
|||
|
|
|||
|
ClientProtocol::ClientProtocol( QTcpSocket *parent,
|
|||
|
const QString & _dstHost,
|
|||
|
const quint16 _dstPort )
|
|||
|
: QObject(parent), socket( parent ),
|
|||
|
dstHost( _dstHost ), dstPort( _dstPort ),
|
|||
|
protocolRetry( 0 ), maxProtocolRetries( 3 ), protocolStarted( false ),
|
|||
|
disconnectFromSocketOnDoneFlag( false )
|
|||
|
{
|
|||
|
Q_ASSERT( socket );
|
|||
|
|
|||
|
// check, if no dstHost, socket must be in the ConnectedState
|
|||
|
if( dstHost.isEmpty() &&
|
|||
|
socket->state() != QAbstractSocket::ConnectedState ) {
|
|||
|
qCritical() << this << "constructor, dstHost.isEmpty(), but socket state"
|
|||
|
<< socket->state();
|
|||
|
qFatal( "you must check socket state, before creating protocol" );
|
|||
|
}
|
|||
|
connectTimeoutTimer = new QTimer( this );
|
|||
|
connectTimeoutTimer->setSingleShot( true );
|
|||
|
connect( connectTimeoutTimer, SIGNAL( timeout() ),
|
|||
|
SLOT( slotSocketConnectTimeout() ) );
|
|||
|
reconnectSleepTimer = new QTimer( this );
|
|||
|
reconnectSleepTimer->setSingleShot( true );
|
|||
|
connect( reconnectSleepTimer, SIGNAL( timeout() ),
|
|||
|
SLOT( deferredStart() ) );
|
|||
|
|
|||
|
// connect socket signals to my slots
|
|||
|
connect( socket, SIGNAL( error(QAbstractSocket::SocketError) ),
|
|||
|
SLOT( slotSocketError(QAbstractSocket::SocketError) ) );
|
|||
|
connect( socket, SIGNAL( stateChanged(QAbstractSocket::SocketState) ),
|
|||
|
SLOT( slotSocketStateChanged(QAbstractSocket::SocketState) ) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::slotSocketStateChanged ( QAbstractSocket::SocketState socketState )
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "slotSocketStateChanged(" << socketState << ")";
|
|||
|
#endif
|
|||
|
// Не слишком ли много мы ходили в protocolStart?
|
|||
|
if( protocolRetry >= maxProtocolRetries ) {
|
|||
|
emitError( "maxProtocolRetries reached" );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
switch( socketState ) {
|
|||
|
case QAbstractSocket::ConnectedState:
|
|||
|
// уже соединены, запускаем протокол
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "slotSocketStateChanged((): connected!"
|
|||
|
<< "protocolRetry" << protocolRetry;
|
|||
|
#endif
|
|||
|
protocolStart();
|
|||
|
break;
|
|||
|
case QAbstractSocket::UnconnectedState:
|
|||
|
if( protocolStarted )
|
|||
|
protocolStop();
|
|||
|
|
|||
|
// can reconnect?
|
|||
|
if( dstHost.size() ) {
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this
|
|||
|
<< "slotSocketStateChanged(): starting reconnect timer...";
|
|||
|
#endif
|
|||
|
reconnectSleepTimer->start( reconnectSleep );
|
|||
|
}
|
|||
|
else
|
|||
|
emitError( unconnectedNoDstHost );
|
|||
|
break;
|
|||
|
default:
|
|||
|
; // do nothing
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::slotSocketError( QAbstractSocket::SocketError socketError )
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "slotSocketError(" << socketError << ")";
|
|||
|
#endif
|
|||
|
switch( socketError ) {
|
|||
|
case QAbstractSocket::ConnectionRefusedError:
|
|||
|
case QAbstractSocket::SocketTimeoutError:
|
|||
|
case QAbstractSocket::RemoteHostClosedError:
|
|||
|
// ну чо поделать, как только socketState
|
|||
|
// поменяется в UnconnectedState, начнется новый deferredStart
|
|||
|
break;
|
|||
|
case QAbstractSocket::HostNotFoundError:
|
|||
|
qWarning() << this << "slotSocketError(): host not found"
|
|||
|
<< dstHost << ":" << dstPort;
|
|||
|
emitError( QString("host not found: ") +
|
|||
|
dstHost + ":" + QString::number(dstPort) );
|
|||
|
break;
|
|||
|
case QAbstractSocket::SocketAccessError:
|
|||
|
case QAbstractSocket::SocketResourceError:
|
|||
|
case QAbstractSocket::DatagramTooLargeError:
|
|||
|
case QAbstractSocket::AddressInUseError:
|
|||
|
case QAbstractSocket::NetworkError:
|
|||
|
case QAbstractSocket::SocketAddressNotAvailableError:
|
|||
|
case QAbstractSocket::UnsupportedSocketOperationError:
|
|||
|
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
|||
|
case QAbstractSocket::UnknownSocketError:
|
|||
|
qCritical() << this << "slotSocketError(): bad socket error, aborting"
|
|||
|
<< socketError;
|
|||
|
emitError( "bad socket error" );
|
|||
|
break;
|
|||
|
default:
|
|||
|
qCritical() << this << "slotSocketError(): unknown socket error"
|
|||
|
<< socketError;
|
|||
|
emitError( "Unknown socket error" );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::slotSocketConnectTimeout()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "slotSocketConnectTimeout()";
|
|||
|
#endif
|
|||
|
emitError( "socket connect timeout" );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::deferredStart()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "deferredStart()";
|
|||
|
#endif
|
|||
|
// Не слишком ли много мы ходили в protocolStart?
|
|||
|
if( protocolRetry >= maxProtocolRetries ) {
|
|||
|
emitError( "maxProtocolRetries reached" );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Не запущен timeoutTimer?
|
|||
|
if( ! connectTimeoutTimer->isActive() )
|
|||
|
connectTimeoutTimer->start( connectTimeout );
|
|||
|
|
|||
|
// запущен reconnectSleepTimer?
|
|||
|
if( reconnectSleepTimer->isActive() )
|
|||
|
reconnectSleepTimer->stop();
|
|||
|
|
|||
|
switch( socket->state() ) {
|
|||
|
case QAbstractSocket::UnconnectedState:
|
|||
|
// еще никуда не коннектится, начнем :)
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "deferredStart(): socket->connectToHost("
|
|||
|
<< dstHost << "," << dstPort << ")";
|
|||
|
#endif
|
|||
|
if( dstHost.size() )
|
|||
|
connectSocket();
|
|||
|
else
|
|||
|
emitError( "dstHost is empty and socket unconnected" );
|
|||
|
break;
|
|||
|
case QAbstractSocket::ConnectedState:
|
|||
|
// уже соединены, запускаем протокол
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "deferredStart(): connected! protocolRetry"
|
|||
|
<< protocolRetry;
|
|||
|
#endif
|
|||
|
protocolStart();
|
|||
|
break;
|
|||
|
default:
|
|||
|
; // do nothing
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::connectSocket()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocol::connectSocket()";
|
|||
|
#endif
|
|||
|
|
|||
|
Q_ASSERT( dstHost.size() );
|
|||
|
socket->connectToHost( dstHost, dstPort );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
void ClientProtocol::slotBytesWritten ( qint64 bytes )
|
|||
|
{
|
|||
|
qDebug() << this << "ClientProtocol::slotBytesWritten(" << bytes << ")";
|
|||
|
#else
|
|||
|
void ClientProtocol::slotBytesWritten ( qint64 )
|
|||
|
{
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::slotReadyRead()
|
|||
|
{
|
|||
|
// default implementation just read all data
|
|||
|
QByteArray data = socket->readAll();
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocol::slotReadyRead(): " << data;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::emitError( const QString & errTxt )
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "emitError(" << errTxt << ")";
|
|||
|
#endif
|
|||
|
|
|||
|
if( protocolStarted )
|
|||
|
protocolStop();
|
|||
|
else
|
|||
|
stopTimers();
|
|||
|
|
|||
|
// disconnect all signals to me
|
|||
|
socket->disconnect( this );
|
|||
|
socket->abort();
|
|||
|
|
|||
|
emit error( errTxt );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::emitDone()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "emitDone()";
|
|||
|
#endif
|
|||
|
|
|||
|
if( protocolStarted )
|
|||
|
protocolStop();
|
|||
|
else
|
|||
|
stopTimers();
|
|||
|
|
|||
|
if( disconnectFromSocketOnDoneFlag )
|
|||
|
socket->disconnect( this );
|
|||
|
|
|||
|
emit done();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::sureWrite( const QByteArray & response )
|
|||
|
{
|
|||
|
qint64 len = response.size();
|
|||
|
const char * ptr = response.data();
|
|||
|
while( len ) {
|
|||
|
qint64 res = socket->write( ptr, len );
|
|||
|
if ( res < 0 )
|
|||
|
break;
|
|||
|
len -= res;
|
|||
|
ptr += res;
|
|||
|
}
|
|||
|
socket->flush();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::stopTimers()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocol::stopTimers()";
|
|||
|
#endif
|
|||
|
// stop my timers
|
|||
|
if( connectTimeoutTimer->isActive() )
|
|||
|
connectTimeoutTimer->stop();
|
|||
|
|
|||
|
if( reconnectSleepTimer->isActive() )
|
|||
|
reconnectSleepTimer->stop();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::protocolStop()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocol::protocolStop()";
|
|||
|
#endif
|
|||
|
protocolStarted = false;
|
|||
|
// disconnect socket data signals from protocol handlers
|
|||
|
disconnect( socket, SIGNAL( readyRead() ),
|
|||
|
this, SLOT( slotReadyRead() ) );
|
|||
|
disconnect( socket, SIGNAL( bytesWritten(qint64) ),
|
|||
|
this, SLOT( slotBytesWritten(qint64) ) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocol::protocolStart()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocol::protocolStart()";
|
|||
|
#endif
|
|||
|
stopTimers();
|
|||
|
|
|||
|
protocolRetry++;
|
|||
|
protocolStarted = true;
|
|||
|
// connect socket data signals to protocol handlers
|
|||
|
connect( socket, SIGNAL( readyRead() ),
|
|||
|
this, SLOT( slotReadyRead() ) );
|
|||
|
connect( socket, SIGNAL( bytesWritten(qint64) ),
|
|||
|
this, SLOT( slotBytesWritten(qint64) ) );
|
|||
|
|
|||
|
// noProxyMode?
|
|||
|
if( !qstrcmp(metaObject()->className(), "ClientProtocol") )
|
|||
|
emitDone();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ClientProtocolWithTimeout::ClientProtocolWithTimeout( QTcpSocket * parent,
|
|||
|
const int _protocolTimeout,
|
|||
|
const QString & dstHost,
|
|||
|
const quint16 dstPort )
|
|||
|
: ClientProtocol( parent, dstHost, dstPort ),
|
|||
|
protocolTimeout( _protocolTimeout )
|
|||
|
{
|
|||
|
protocolTimeoutTimer = new QTimer( this );
|
|||
|
protocolTimeoutTimer->setSingleShot( true );
|
|||
|
connect( protocolTimeoutTimer, SIGNAL( timeout() ),
|
|||
|
SLOT( slotProtocolTimeout() ) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocolWithTimeout::protocolStop()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocolWithTimeout::protocolStop():"
|
|||
|
<< "stop protocol timeout timer";
|
|||
|
#endif
|
|||
|
ClientProtocol::protocolStop();
|
|||
|
|
|||
|
if( protocolTimeoutTimer->isActive() )
|
|||
|
protocolTimeoutTimer->stop();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocolWithTimeout::protocolStart()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocolWithTimeout::protocolStart():"
|
|||
|
<< "start protocol timeout timer"
|
|||
|
<< protocolTimeout / 1000 << "secs";
|
|||
|
#endif
|
|||
|
ClientProtocol::protocolStart();
|
|||
|
|
|||
|
protocolTimeoutTimer->start( protocolTimeout );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocolWithTimeout::slotProtocolTimeout()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocolWithTimeout::slotProtocolTimeout()";
|
|||
|
#endif
|
|||
|
if( !objectName().length() ) {
|
|||
|
qCritical() << this << "ClientProtocolWithTimeout::slotProtocolTimeout():"
|
|||
|
<< "protocol name empty!"
|
|||
|
<< "Please setObjectName() for your protocols!";
|
|||
|
qFatal( "programming error" );
|
|||
|
}
|
|||
|
emitError( objectName() + " protocol timeout" );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
void ClientProtocolWithTimeout::slotBytesWritten( qint64 bytes )
|
|||
|
{
|
|||
|
qDebug() << this << "ClientProtocolWithTimeout::slotBytesWritten("
|
|||
|
<< bytes << "): restart protocol timeout timer"
|
|||
|
<< protocolTimeout / 1000 << "secs";
|
|||
|
#else
|
|||
|
void ClientProtocolWithTimeout::slotBytesWritten( qint64 )
|
|||
|
{
|
|||
|
#endif
|
|||
|
Q_ASSERT( protocolStarted );
|
|||
|
Q_ASSERT( protocolTimeoutTimer->isActive() );
|
|||
|
|
|||
|
// restart timeout timer.
|
|||
|
protocolTimeoutTimer->start( protocolTimeout );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ClientProtocolWithTimeout::slotReadyRead()
|
|||
|
{
|
|||
|
#ifdef DEBUG_PROTOCOL
|
|||
|
qDebug() << this << "ClientProtocolWithTimeout::slotReadyRead():"
|
|||
|
<< "restart protocol timeout timer"
|
|||
|
<< protocolTimeout / 1000 << "secs";
|
|||
|
#endif
|
|||
|
Q_ASSERT( protocolStarted );
|
|||
|
Q_ASSERT( protocolTimeoutTimer->isActive() );
|
|||
|
|
|||
|
// restart timeout timer.
|
|||
|
protocolTimeoutTimer->start( protocolTimeout );
|
|||
|
}
|