use XMPP ping (XEP-0199) to detect connection lost at applicatin level. fixes #2767

This commit is contained in:
Yann Leboulanger 2008-02-07 23:53:02 +00:00
parent 059ed3dd27
commit 85cc4889ec
2 changed files with 36 additions and 16 deletions

View File

@ -705,11 +705,21 @@ class Connection(ConnectionHandlers):
return return
common.xmpp.features_nb.getPrivacyLists(self.connection) common.xmpp.features_nb.getPrivacyLists(self.connection)
def sendPing(self, pingTo): def sendPing(self, pingTo=None):
'''Send XMPP Ping (XEP-0199) request. If pingTo is not set, ping is sent
to server to detect connection failure at application level.'''
if not self.connection: if not self.connection:
return return
iq = common.xmpp.Iq('get', to = pingTo.get_full_jid()) id = self.connection.getAnID()
if pingTo:
to = pingTo.get_full_jid()
self.dispatch('PING_SENT', (pingTo))
else:
to = gajim.config.get_per('accounts', self.name, 'hostname')
self.awaiting_xmpp_ping_id = id
iq = common.xmpp.Iq('get', to=to)
iq.addChild(name = 'ping', namespace = common.xmpp.NS_PING) iq.addChild(name = 'ping', namespace = common.xmpp.NS_PING)
iq.setID(id)
def _on_response(resp): def _on_response(resp):
timePong = time_time() timePong = time_time()
if not common.xmpp.isResultNode(resp): if not common.xmpp.isResultNode(resp):
@ -717,9 +727,12 @@ class Connection(ConnectionHandlers):
return return
timeDiff = round(timePong - timePing,2) timeDiff = round(timePong - timePing,2)
self.dispatch('PING_REPLY', (pingTo, timeDiff)) self.dispatch('PING_REPLY', (pingTo, timeDiff))
self.dispatch('PING_SENT', (pingTo)) if pingTo:
timePing = time_time() timePing = time_time()
self.connection.SendAndCallForResponse(iq, _on_response) self.connection.SendAndCallForResponse(iq, _on_response)
else:
self.connection.send(iq)
gajim.idlequeue.set_alarm(self.check_keepalive, 5)
def get_active_default_lists(self): def get_active_default_lists(self):
if not self.connection: if not self.connection:
@ -877,7 +890,7 @@ class Connection(ConnectionHandlers):
self.connection = con self.connection = con
if not self.connection: if not self.connection:
return return
self.connection.set_send_timeout(self.keepalives, self.send_keepalive) self.connection.set_send_timeout(self.keepalives, self.sendPing)
self.connection.onreceive(None) self.connection.onreceive(None)
iq = common.xmpp.Iq('get', common.xmpp.NS_PRIVACY, xmlns = '') iq = common.xmpp.Iq('get', common.xmpp.NS_PRIVACY, xmlns = '')
id = self.connection.getAnID() id = self.connection.getAnID()
@ -1601,10 +1614,10 @@ class Connection(ConnectionHandlers):
c.setTagData('reason', reason) c.setTagData('reason', reason)
self.connection.send(message) self.connection.send(message)
def send_keepalive(self): def check_keepalive(self):
# nothing received for the last foo seconds (60 secs by default) if self.awaiting_xmpp_ping_id:
if self.connection: # We haven't got the pong in time, disco and reconnect
self.connection.send(' ') self.disconnect()
def _reconnect_alarm(self): def _reconnect_alarm(self):
if self.time_to_reconnect: if self.time_to_reconnect:

View File

@ -427,6 +427,9 @@ class ConnectionBytestream:
real_id = unicode(iq_obj.getAttr('id')) real_id = unicode(iq_obj.getAttr('id'))
if real_id[:3] != 'au_': if real_id[:3] != 'au_':
return return
if real_id == self.awaiting_xmpp_ping_id:
self.awaiting_xmpp_ping_id = None
return
frm = helpers.get_full_jid_from_iq(iq_obj) frm = helpers.get_full_jid_from_iq(iq_obj)
id = real_id[3:] id = real_id[3:]
if self.files_props.has_key(id): if self.files_props.has_key(id):
@ -666,8 +669,8 @@ class ConnectionDisco:
query = iq.setTag('query') query = iq.setTag('query')
query.setAttr('node','http://gajim.org/caps#' + gajim.version.split('-', query.setAttr('node','http://gajim.org/caps#' + gajim.version.split('-',
1)[0]) 1)[0])
for f in (common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI, \ for f in (common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI,
common.xmpp.NS_FILE, common.xmpp.NS_COMMANDS): common.xmpp.NS_FILE, common.xmpp.NS_COMMANDS):
feature = common.xmpp.Node('feature') feature = common.xmpp.Node('feature')
feature.setAttr('var', f) feature.setAttr('var', f)
query.addChild(node=feature) query.addChild(node=feature)
@ -1243,6 +1246,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.last_ids = [] self.last_ids = []
# IDs of jabber:iq:version requests # IDs of jabber:iq:version requests
self.version_ids = [] self.version_ids = []
# ID of urn:xmpp:ping requests
self.awaiting_xmpp_ping_id = None
# keep track of sessions this connection has with other JIDs # keep track of sessions this connection has with other JIDs
self.sessions = {} self.sessions = {}
@ -1312,6 +1317,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.dispatch('LAST_STATUS_TIME', (jid_stripped, resource, -1, '')) self.dispatch('LAST_STATUS_TIME', (jid_stripped, resource, -1, ''))
self.last_ids.remove(id) self.last_ids.remove(id)
return return
if id == self.awaiting_xmpp_ping_id:
self.awaiting_xmpp_ping_id = None
errmsg = iq_obj.getErrorMsg() errmsg = iq_obj.getErrorMsg()
errcode = iq_obj.getErrorCode() errcode = iq_obj.getErrorCode()
self.dispatch('ERROR_ANSWER', (id, jid_from, errmsg, errcode)) self.dispatch('ERROR_ANSWER', (id, jid_from, errmsg, errcode))
@ -1400,9 +1407,9 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
qp.setTagData('os', helpers.get_os_info()) qp.setTagData('os', helpers.get_os_info())
self.connection.send(iq_obj) self.connection.send(iq_obj)
raise common.xmpp.NodeProcessed raise common.xmpp.NodeProcessed
def _LastCB(self, con, iq_obj): def _LastCB(self, con, iq_obj):
gajim.log.debug('IdleCB') gajim.log.debug('LastCB')
iq_obj = iq_obj.buildReply('result') iq_obj = iq_obj.buildReply('result')
qp = iq_obj.getTag('query') qp = iq_obj.getTag('query')
if not HAS_IDLE: if not HAS_IDLE:
@ -1412,7 +1419,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.connection.send(iq_obj) self.connection.send(iq_obj)
raise common.xmpp.NodeProcessed raise common.xmpp.NodeProcessed
def _LastResultCB(self, con, iq_obj): def _LastResultCB(self, con, iq_obj):
gajim.log.debug('LastResultCB') gajim.log.debug('LastResultCB')
qp = iq_obj.getTag('query') qp = iq_obj.getTag('query')
@ -1432,7 +1439,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.last_ids.remove(id) self.last_ids.remove(id)
jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who) jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who)
self.dispatch('LAST_STATUS_TIME', (jid_stripped, resource, seconds, status)) self.dispatch('LAST_STATUS_TIME', (jid_stripped, resource, seconds, status))
def _VersionResultCB(self, con, iq_obj): def _VersionResultCB(self, con, iq_obj):
gajim.log.debug('VersionResultCB') gajim.log.debug('VersionResultCB')
client_info = '' client_info = ''