[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kopete-devel
Subject:    [kopete-devel] SocketTimeoutWatcher
From:       "Roman Jarosz" <kedgedev () gmail ! com>
Date:       2009-05-17 21:59:25
Message-ID: op.ut3gpbaxasvm2a () kedge
[Download RAW message or body]

Hi,

there has been a lot of complains that protocols don't disconnect  
themselves
when somehow connection is lost (or disconnect after long time).

So after lot of googling I found linux only way how we can fix this.
There is TCP_INFO struct which contains info when last ACK was received
and when last data were sent and from this we can check if server still
gets packets from us.

This is all the code that needs to be add when we want to watch for
timeouts on some tcp based socket

new SocketTimeoutWatcher(some_tcp_based_socket, timeout);

I would like to put in into libkopete and add SocketTimeoutWatcher
to most protocols. I'll also add Q_WS_X11 to SocketTimeoutWatcher
so it doesn't break Win or Mac

Any objections?

Roman
["timeoutwatcher.diff" (timeoutwatcher.diff)]

Index: liboscar/sockettimeoutwatcher.h
===================================================================
--- liboscar/sockettimeoutwatcher.h	(revision 0)
+++ liboscar/sockettimeoutwatcher.h	(revision 0)
@@ -0,0 +1,60 @@
+/*
+	sockettimeoutwatcher.h - Kopete Socket Timeout Watcher
+
+	Copyright (c) 2009 Roman Jarosz <kedgedev@centrum.cz>
+	Kopete (c) 2009 by the Kopete developers <kopete-devel@kde.org>
+
+	*************************************************************************
+	*                                                                       *
+	* This library is free software; you can redistribute it and/or         *
+	* modify it under the terms of the GNU Lesser General Public            *
+	* License as published by the Free Software Foundation; either          *
+	* version 2 of the License, or (at your option) any later version.      *
+	*                                                                       *
+	*************************************************************************
+*/
+#ifndef SOCKETTIMEOUTWATCHER_H
+#define SOCKETTIMEOUTWATCHER_H
+
+#include <QObject>
+#include <QAbstractSocket>
+
+class QTimer;
+
+/**
+	@author Roman Jarosz <kedgedev@centrum.cz>
+*/
+class SocketTimeoutWatcher : public QObject
+{
+Q_OBJECT
+public:
+	/**
+	 * SocketTimeoutWatcher watches if outgoing data has been sent out.
+	 * The implementation check if ACK was received after data has been sent
+	 * and emits error(QAbstractSocket::SocketError) if ACK hasn't been
+	 * received before @p msecTimeout milliseconds.
+	 * @note abort is called on socket when timeout is reached.
+	 */
+	SocketTimeoutWatcher( QAbstractSocket* socket, quint32 msecTimeout = 15000 );
+
+	~SocketTimeoutWatcher();
+
+signals:
+	/**
+	 * Emitted when timeout is reached.
+	 * @note socketError is always QAbstractSocket::RemoteHostClosedError
+	 */
+	void error( QAbstractSocket::SocketError socketError );
+
+private slots:
+	void bytesWritten();
+	void ackTimeoutCheck();
+
+private:
+	QAbstractSocket* mSocket;
+	QTimer* mAckCheckTimer;
+	bool mActive;
+	quint32 mTimeoutThreshold;
+};
+
+#endif
Index: liboscar/sockettimeoutwatcher.cpp
===================================================================
--- liboscar/sockettimeoutwatcher.cpp	(revision 0)
+++ liboscar/sockettimeoutwatcher.cpp	(revision 0)
@@ -0,0 +1,98 @@
+/*
+	sockettimeoutwatcher.cpp - Kopete Socket Timeout Watcher
+
+	Copyright (c) 2009 Roman Jarosz <kedgedev@centrum.cz>
+	Kopete (c) 2009 by the Kopete developers <kopete-devel@kde.org>
+
+	*************************************************************************
+	*                                                                       *
+	* This library is free software; you can redistribute it and/or         *
+	* modify it under the terms of the GNU Lesser General Public            *
+	* License as published by the Free Software Foundation; either          *
+	* version 2 of the License, or (at your option) any later version.      *
+	*                                                                       *
+	*************************************************************************
+*/
+#include "sockettimeoutwatcher.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/tcp.h>
+
+#include <kdebug.h>
+
+#include <QAbstractSocket>
+#include <QTimer>
+#include <QHostAddress>
+
+SocketTimeoutWatcher::SocketTimeoutWatcher( QAbstractSocket* socket, quint32 \
msecTimeout ) +: QObject(socket), mSocket(socket), mActive(true), \
mTimeoutThreshold(msecTimeout) +{
+	mAckCheckTimer = new QTimer();
+
+	connect( socket, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten()) );
+	connect( socket, SIGNAL(disconnected()), mAckCheckTimer, SLOT(stop()) );
+	connect( socket, SIGNAL(error(QAbstractSocket::SocketError)), mAckCheckTimer, \
SLOT(stop()) ); +
+	connect( mAckCheckTimer, SIGNAL(timeout()), this, SLOT(ackTimeoutCheck()) );
+	mAckCheckTimer->setInterval( mTimeoutThreshold );
+}
+
+SocketTimeoutWatcher::~SocketTimeoutWatcher()
+{
+	delete mAckCheckTimer;
+}
+
+void SocketTimeoutWatcher::bytesWritten()
+{
+	if ( !mActive )
+		return;
+
+	if ( mSocket->socketDescriptor() != -1 )
+	{
+		if ( !mAckCheckTimer->isActive() )
+			mAckCheckTimer->start();
+	}
+	else
+	{
+		if ( mAckCheckTimer->isActive() )
+			mAckCheckTimer->stop();
+	}
+	
+}
+
+void SocketTimeoutWatcher::ackTimeoutCheck()
+{
+	const int sDesc = mSocket->socketDescriptor();
+	if ( sDesc != -1 )
+	{
+		struct tcp_info info;
+		int info_length = sizeof(info);
+		if ( getsockopt( sDesc, SOL_TCP, TCP_INFO, (void*)&info, (socklen_t*)&info_length \
) == 0 ) +		{
+			if ( info.tcpi_last_ack_recv >= info.tcpi_last_data_sent && \
(info.tcpi_last_ack_recv - info.tcpi_last_data_sent) > mTimeoutThreshold ) +			{
+				kWarning() << "Connection timeout for " << mSocket->peerAddress();
+				mAckCheckTimer->stop();
+				emit error( QAbstractSocket::RemoteHostClosedError );
+				mSocket->abort();
+			}
+			else if ( info.tcpi_last_ack_recv < info.tcpi_last_data_sent )
+			{
+				mAckCheckTimer->stop();
+			}
+		}
+		else if ( mActive )
+		{
+			mAckCheckTimer->stop();
+			mActive = false;
+			kWarning() << "Timeout watcher not active for " << mSocket->peerAddress();
+		}
+	}
+	else
+	{
+		mAckCheckTimer->stop();
+	}
+}
+
+#include "sockettimeoutwatcher.moc"



_______________________________________________
kopete-devel mailing list
kopete-devel@kde.org
https://mail.kde.org/mailman/listinfo/kopete-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic