1
//=============================================================================
3
// File : kvi_lagmeter.cpp
4
// Creation date : Fri Oct 18 13:31:36 CEST 1999 by Juanjo �lvarez
6
// This file is part of the KVirc irc client distribution
7
// Copyright (C) 1999 Juanjo �lvarez
8
// Copyright (C) 2000-2008 Szymon Stefanek (pragma at kvirc dot net)
10
// This program is FREE software. You can redistribute it and/or
11
// modify it under the terms of the GNU General Public License
12
// as published by the Free Software Foundation; either version 2
13
// of the License, or (at your opinion) any later version.
15
// This program is distributed in the HOPE that it will be USEFUL,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
// See the GNU General Public License for more details.
20
// You should have received a copy of the GNU General Public License
21
// along with this program. If not, write to the Free Software Foundation,
22
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
//=============================================================================
28
#include "kvi_lagmeter.h"
29
#include "kvi_options.h"
30
#include "kvi_kvs_eventtriggers.h"
31
#include "kvi_parameterlist.h"
32
#include "kvi_ircconnection.h"
33
#include "kvi_irccontext.h"
34
#include "kvi_frame.h"
35
#include "kvi_console.h"
37
#include "kvi_ircconnectionuserinfo.h"
38
#include "kvi_ircconnectionserverinfo.h"
40
#include "kvi_locale.h"
42
KviLagMeter::KviLagMeter(KviIrcConnection * c)
46
m_pCheckList = new KviPointerList<KviLagCheck>;
47
m_pCheckList->setAutoDelete(true);
49
m_uLastEmittedLag = 0;
50
m_uLastReliability = 0;
55
m_pDeletionSignal = 0;
57
// FIXME: We could use the KviIrcConnection::heartbeat() here!
58
if(KVI_OPTION_UINT(KviOption_uintLagMeterHeartbeat) < 2000)
59
KVI_OPTION_UINT(KviOption_uintLagMeterHeartbeat) = 2000; // kinda absurd
61
if(KVI_OPTION_UINT(KviOption_uintLagMeterHeartbeat) > 10000)
62
KVI_OPTION_UINT(KviOption_uintLagMeterHeartbeat) = 10000; // kinda absurd
64
startTimer(KVI_OPTION_UINT(KviOption_uintLagMeterHeartbeat)); // 5 seconds by default
67
KviLagMeter::~KviLagMeter()
69
if(m_pDeletionSignal)*m_pDeletionSignal = true;
73
unsigned int KviLagMeter::secondsSinceLastCompleted()
76
kvi_gettimeofday(&tv,0);
77
return tv.tv_sec - m_tLastCompleted;
80
void KviLagMeter::timerEvent(QTimerEvent *)
82
if(m_pConnection->state() != KviIrcConnection::Connected)return; // do nothing atm
84
// If the lag has changed emit our signals
85
if((m_uLag / 10) != (m_uLastEmittedLag / 10))
87
m_uLastEmittedLag = m_uLag;
88
g_pFrame->childConnectionLagChange(m_pConnection);
90
KviStr szLag(KviStr::Format,"%u",m_uLag);
92
bool bDeletionSignal = false;
93
m_pDeletionSignal = &bDeletionSignal;
95
if((!m_bOnAlarm) && (m_uLag > KVI_OPTION_UINT(KviOption_uintLagAlarmTime)))
97
KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnLagAlarmTimeUp,
98
m_pConnection->console(),m_pConnection->serverInfo()->name(),QString(szLag.ptr()));
99
if(bDeletionSignal)return; // killed , probably by a quit -f -u
101
} else if(m_bOnAlarm)
103
KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnLagAlarmTimeDown,
104
m_pConnection->console(),m_pConnection->serverInfo()->name(),QString(szLag.ptr()));
105
if(bDeletionSignal)return; // killed , probably by a quit -f -u
109
KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnLagCheck,
110
m_pConnection->console(),m_pConnection->serverInfo()->name(),QString(szLag.ptr()));
111
if(bDeletionSignal)return; // killed , probably by a quit -f -u
113
m_pDeletionSignal = 0;
118
kvi_gettimeofday(&tv,0);
119
unsigned int uDiff = tv.tv_sec - m_tLastCompleted;
120
unsigned int uHeartbeat = KVI_OPTION_UINT(KviOption_uintLagMeterHeartbeat) / 1000;
121
if(uHeartbeat < 2)uHeartbeat = 2;
122
// we keep the last lag value for an amount of time
123
// depending on its reliability.
124
// Since reliability ranges from 10 to 100 we keep the lags
125
// for (hrtbt * 4) + (reliability / 2) seconds (which means from 25 to 70 seconds by default)
126
if(uDiff <= ((uHeartbeat * 4) + (m_uLastReliability / 2)))return; // nothing to do, the actual value is accurate
128
// the last completed check has been completed a lot of time ago
129
// do we have some checks on the queue ?
130
if(m_pCheckList->count() > 0)
132
// if the first registered check is not too outdated
133
// we wait a little more for it to return
134
KviLagCheck * c = m_pCheckList->first();
137
if((tv.tv_sec - c->lSecs) <= 10)return;
139
// the first check was registered more than 10 secs before
140
if(m_tLastOwnCheck > 0)
142
// hm.. we have already sent our own (reliable) check after the last completed
143
// make the lag grow (we're pretty sure it's growing)
144
uDiff = (tv.tv_sec - m_tFirstOwnCheck) * 1000;
145
if(m_uLag < uDiff)m_uLag = uDiff; // the lag grows for sure
146
uDiff = tv.tv_sec - m_tLastOwnCheck;
147
if(uDiff < (uHeartbeat * 4))return; // wait a bit...send own checks only every 20 secs (by default) at this point
150
// or we have no checks in the queue at all
151
// or it's really time to do something...
152
if(m_tFirstOwnCheck == 0)
155
m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Sending out PING based lag probe"));
157
// this is the first our own lag check since the last succesfull one: use the ping
158
lagCheckRegister("@ping@",70); // the ping may be fooled easily
159
m_pConnection->sendFmtData("PING %s %s",
160
m_pConnection->encodeText( m_pConnection->userInfo()->nickName() ).data(),
161
m_pConnection->encodeText( m_pConnection->serverInfo()->name() ).data() );
162
m_tFirstOwnCheck = tv.tv_sec;
165
m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Sending out CTCP based lag probe"));
167
// we have already sent a ping but we got no reply
168
// try with another method... even if this will reset our idle time
169
KviStr tmp(KviStr::Format,"%d%d-yeah-:)",tv.tv_sec,tv.tv_usec);
170
lagCheckRegister(tmp.ptr(),100); // almost impossible to fool
171
m_pConnection->sendFmtData("NOTICE %s :%cLAGCHECK %s%c",
172
m_pConnection->encodeText( m_pConnection->userInfo()->nickName() ).data(),
177
m_tLastOwnCheck = tv.tv_sec;
180
void KviLagMeter::lagCheckRegister(const char * key,unsigned int uReliability)
182
if(uReliability < 10)return; // what the heck of a lag check is this ?
183
// store the lagcheck structure and just return
186
m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Registered lag check with reliability %u (%s)"),uReliability,key);
188
KviLagCheck * c = new KviLagCheck;
191
kvi_gettimeofday(&tv,0);
192
c->lSecs = tv.tv_sec;
193
c->lUSecs = tv.tv_usec;
194
c->uReliability = uReliability <= 100 ? uReliability : 100;
195
m_pCheckList->append(c);
196
while(m_pCheckList->count() > 30)
199
// either our ping mechanism is not working
200
// or the server is stoned...
201
m_pCheckList->removeFirst();
205
bool KviLagMeter::lagCheckComplete(const char * key)
207
// find this lag check
209
for(c = m_pCheckList->first();c;c = m_pCheckList->next())
211
if(kvi_strEqualCS(c->szKey.ptr(),key))break;
213
if(!c)return false; // not found
214
// kill any earlier lag checks (IRC is a sequential proto)
215
while(m_pCheckList->first() != c)m_pCheckList->removeFirst();
218
m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Lag check completed (%s)"),key);
221
kvi_gettimeofday(&tv,0);
223
unsigned int uLag = ((tv.tv_sec - c->lSecs) * 1000);
224
if(tv.tv_usec < c->lUSecs)uLag -= ((c->lUSecs - tv.tv_usec) / 1000);
225
else uLag += ((tv.tv_usec - c->lUSecs) / 1000);
227
// now check the reliability
229
if(m_uLastReliability > c->uReliability)
231
// the actual data is more reliable than the new one :/
232
// change the real lag only by a certain amount
233
// c->uRel : 100 = uLag : m_uLag
234
m_uLag = ((uLag * c->uReliability) + (m_uLag * m_uLastReliability)) / (c->uReliability + m_uLastReliability);
236
// the actual data is less reliable than the new one
240
m_tLastCompleted = tv.tv_sec; // now
242
m_tFirstOwnCheck = 0;
243
m_uLastReliability = c->uReliability;
245
m_pCheckList->removeFirst();
250
void KviLagMeter::lagCheckAbort(const char * key)
252
KviPointerList<KviLagCheck> l;
253
l.setAutoDelete(false);
257
m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Lag check aborted (%s)"),key);
259
for(c = m_pCheckList->first();c;c = m_pCheckList->next())
260
if(kvi_strEqualCS(c->szKey.ptr(),key))l.append(c);
261
for(c = l.first();c;c = l.next())m_pCheckList->removeRef(c);
264
#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
265
#include "kvi_lagmeter.moc"
266
#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES