Added keepalive check in jabber

cusax-fix
Damian Minkov 20 years ago
parent 388c2507e8
commit d1ce1d3d2f

@ -11,8 +11,10 @@
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.Message;
import net.java.sip.communicator.service.protocol.event.*;
@ -30,6 +32,28 @@ public class OperationSetBasicInstantMessagingJabberImpl
private static final Logger logger =
Logger.getLogger(OperationSetBasicInstantMessagingJabberImpl.class);
/**
* KeepAlive interval for sending packets
*/
private static long KEEPALIVE_INTERVAL = 180000l; // 3 minutes
/**
* The interval after which a packet is considered to be lost
*/
private static long KEEPALIVE_WAIT = 20000l;
/**
* The task sending packets
*/
private KeepAliveSendTask keepAliveSendTask = null;
/**
* The timer executing tasks on specified intervals
*/
private Timer keepAliveTimer = new Timer();
/**
* The queue holding the received packets
*/
private LinkedList receivedKeepAlivePackets = new LinkedList();
/**
* A list of listeneres registered for message events.
*/
@ -57,6 +81,11 @@ public class OperationSetBasicInstantMessagingJabberImpl
{
this.jabberProvider = provider;
provider.addRegistrationStateChangeListener(new RegistrationStateListener());
// register the KeepAlive Extension in the smack library
ProviderManager.addExtensionProvider(KeepAliveEventProvider.ELEMENT_NAME,
KeepAliveEventProvider.NAMESPACE,
new KeepAliveEventProvider());
}
/**
@ -207,6 +236,13 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt)
new SmackMessageListener(),
new PacketTypeFilter(
org.jivesoftware.smack.packet.Message.class));
// run keepalive thread
if(keepAliveSendTask == null)
keepAliveSendTask = new KeepAliveSendTask();
keepAliveTimer.scheduleAtFixedRate(
keepAliveSendTask, KEEPALIVE_INTERVAL, KEEPALIVE_INTERVAL);
}
}
}
@ -264,6 +300,17 @@ public void processPacket(Packet packet)
+ msg.getBody());
}
KeepAliveEvent keepAliveEvent =
(KeepAliveEvent)packet.getExtension(
KeepAliveEventProvider.ELEMENT_NAME,
KeepAliveEventProvider.NAMESPACE);
if(keepAliveEvent != null)
{
keepAliveEvent.setFromUserID(fromUserID);
receivedKeepAlivePackets.addLast(keepAliveEvent);
return;
}
Message newMessage = createMessage(msg.getBody());
Contact sourceContact =
@ -313,4 +360,105 @@ public void processPacket(Packet packet)
fireMessageEvent(msgReceivedEvt);
}
}
/**
* Task sending packets on intervals.
* The task is runned on specified intervals by the keepAliveTimer
*/
private class KeepAliveSendTask
extends TimerTask
{
public void run()
{
try
{
// if we are not registerd do nothing
if(!jabberProvider.isRegistered())
return;
Chat chat =
jabberProvider.getConnection().
createChat(jabberProvider.getAccountID().getUserID());
org.jivesoftware.smack.packet.Message msg = chat.createMessage();
msg.setBody("SYSTEM MESSAGE!");
KeepAliveEvent keepAliveEvent = new KeepAliveEvent();
keepAliveEvent.setSrcOpSetHash(
OperationSetBasicInstantMessagingJabberImpl.this.hashCode());
keepAliveEvent.setSrcProviderHash(jabberProvider.hashCode());
// add keepalive data
msg.addExtension(keepAliveEvent);
// schedule the check task
keepAliveTimer.schedule(
new KeepAliveCheckTask(), KEEPALIVE_WAIT);
logger.trace("send keepalive");
chat.sendMessage(msg);
}
catch (XMPPException ex)
{
logger.error("", ex);
}
}
}
/**
* Check if the first received packet in the queue
* is ok and if its not or the queue has no received packets
* the this means there is some network problem, so fire event
*/
private class KeepAliveCheckTask
extends TimerTask
{
public void run()
{
try
{
// check till we find a correct message
// or if NoSuchElementException is thrown
// there is no message
while(!checkFirstPacket());
}
catch (NoSuchElementException ex)
{
fireUnregisterd();
}
}
/**
* Checks whether first packet in queue is ok
* @return boolean
* @throws NoSuchElementException
*/
boolean checkFirstPacket()
throws NoSuchElementException
{
KeepAliveEvent receivedEvent =
(KeepAliveEvent)receivedKeepAlivePackets.removeLast();
if(jabberProvider.hashCode() != receivedEvent.getSrcProviderHash() ||
OperationSetBasicInstantMessagingJabberImpl.this.hashCode() !=
receivedEvent.getSrcOpSetHash() ||
!jabberProvider.getAccountID().getUserID().
equals(receivedEvent.getFromUserID()) )
return false;
else
return true;
}
/**
* Fire Unregistered event
*/
void fireUnregisterd()
{
jabberProvider.fireRegistrationStateChanged(
RegistrationState.UNREGISTERED,
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_INTERNAL_ERROR, null);
}
}
}

@ -373,7 +373,7 @@ protected XMPPConnection getConnection()
* @param reason a String further explaining the reason code or null if
* no such explanation is necessary.
*/
private void fireRegistrationStateChanged( RegistrationState oldState,
void fireRegistrationStateChanged( RegistrationState oldState,
RegistrationState newState,
int reasonCode,
String reason)

@ -0,0 +1,132 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions;
import org.jivesoftware.smack.packet.*;
/**
* KeepAlive Event. Events are send on specified interval
* and must be received from the sendin provider.
* Carries the information for the source ProtocolProvider and
* source OperationSet - so we can be sure that we are sending and receiving the
* same package.
*
* @author Damian Minkov
*/
public class KeepAliveEvent
implements PacketExtension
{
public static final String SOURCE_PROVIDER_HASH = "src-provider-hash";
public static final String SOURCE_OPSET_HASH = "src-opset-hash";
private int srcProviderHash = -1;
private int srcOpSetHash = -1;
private String fromUserID = null;
/**
* Returns the XML element name of the extension sub-packet root element.
* Always returns "x"
*
* @return the XML element name of the packet extension.
*/
public String getElementName()
{
return KeepAliveEventProvider.ELEMENT_NAME;
}
/**
* Returns the XML namespace of the extension sub-packet root element.
* The namespace is always "sip-communicator:x:keepalive"
*
* @return the XML namespace of the packet extension.
*/
public String getNamespace()
{
return KeepAliveEventProvider.NAMESPACE;
}
/**
* Returns the XML reppresentation of the PacketExtension.
*
* @return the packet extension as XML.
* @todo Implement this org.jivesoftware.smack.packet.PacketExtension
* method
*/
public String toXML()
{
StringBuffer buf = new StringBuffer();
buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
"\">");
buf.append("<").
append(SOURCE_PROVIDER_HASH).append(">").
append(getSrcProviderHash()).append("</").
append(SOURCE_PROVIDER_HASH).append(">");
buf.append("<").
append(SOURCE_OPSET_HASH).append(">").
append(getSrcOpSetHash()).append("</").
append(SOURCE_OPSET_HASH).append(">");
buf.append("</").append(getElementName()).append(">");
return buf.toString();
}
/**
* Returns the hash of the source opeartion set sending this message
* @return int hash of the operation set
*/
public int getSrcOpSetHash()
{
return srcOpSetHash;
}
/**
* Returns the hash of the source provider sending this message
* @return int hash of the provider
*/
public int getSrcProviderHash()
{
return srcProviderHash;
}
/**
* The user id sending this packet
* @return String user id
*/
public String getFromUserID()
{
return fromUserID;
}
/**
* Sets the hash of the source provider that will send the message
* @param srcProviderHash int hash of the provider
*/
public void setSrcProviderHash(int srcProviderHash)
{
this.srcProviderHash = srcProviderHash;
}
/**
* Sets the hash of the source opeartion set that will send the message
* @param srcProviderHash int hash of the operation set
*/
public void setSrcOpSetHash(int srcOpSetHash)
{
this.srcOpSetHash = srcOpSetHash;
}
/**
* The user id sending this packet
* @param fromUserID String user id
*/
public void setFromUserID(String fromUserID)
{
this.fromUserID = fromUserID;
}
}

@ -0,0 +1,81 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.xmlpull.v1.*;
/**
* The KeepAliveEventProvider parses KeepAlive Event packets.
*
* @author Damian Minkov
*/
public class KeepAliveEventProvider
implements PacketExtensionProvider
{
public static final String ELEMENT_NAME = "x";
public static final String NAMESPACE = "sip-communicator:x:keepalive";
/**
* Creates a new KeepAliveEventProvider.
* ProviderManager requires that every PacketExtensionProvider has a public,
* no-argument constructor
*/
public KeepAliveEventProvider()
{}
/**
* Parses a KeepAliveEvent packet (extension sub-packet).
*
* @param parser an XML parser.
* @return a new IQ instance.
* @throws Exception if an error occurs parsing the XML.
* @todo Implement this
* org.jivesoftware.smack.provider.PacketExtensionProvider method
*/
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception
{
KeepAliveEvent result = new KeepAliveEvent();
boolean done = false;
while (!done)
{
try
{
int eventType = parser.next();
if(eventType == XmlPullParser.START_TAG)
{
if(parser.getName().equals(KeepAliveEvent.
SOURCE_PROVIDER_HASH))
{
result.setSrcProviderHash(Integer.parseInt(parser.
nextText()));
}
if(parser.getName().equals(KeepAliveEvent.SOURCE_OPSET_HASH))
{
result.setSrcOpSetHash(Integer.parseInt(parser.nextText()));
}
}
else if(eventType == XmlPullParser.END_TAG)
{
if(parser.getName().equals("x"))
{
done = true;
}
}
}
catch(NumberFormatException ex)
{
ex.printStackTrace();
}
}
return result;
}
}
Loading…
Cancel
Save