Fixes some reconnect issues and early events where still no dns is configured (now waiting half a second). Fixes jabber provider not cleaned up after connection failed (during login process). Fixes an needed reconnect when more than one interface available and network is going down (stand by).

cusax-fix
Damian Minkov 15 years ago
parent 1269430cb4
commit e20ad10747

@ -33,12 +33,6 @@ public class NetworkConfigurationWatcher
private static Logger logger =
Logger.getLogger(NetworkConfigurationWatcher.class);
/**
* Listers for network configuration changes.
*/
private final List<NetworkConfigurationChangeListener> listeners =
new ArrayList<NetworkConfigurationChangeListener>();
/**
* The current active interfaces.
*/
@ -61,6 +55,12 @@ public class NetworkConfigurationWatcher
private SystemActivityNotificationsService
systemActivityNotificationsService = null;
/**
* The thread dispatcher of network change events.
*/
private NetworkEventDispatcher eventDispatcher =
new NetworkEventDispatcher();
/**
* Inits configuration watcher.
*/
@ -83,15 +83,9 @@ public class NetworkConfigurationWatcher
void addNetworkConfigurationChangeListener(
NetworkConfigurationChangeListener listener)
{
synchronized(listeners)
{
if(!listeners.contains(listener))
{
listeners.add(listener);
eventDispatcher.addNetworkConfigurationChangeListener(listener);
initialFireEvents(listener);
}
}
initialFireEvents(listener);
NetaddrActivator.getBundleContext().addServiceListener(this);
@ -139,7 +133,7 @@ private void initialFireEvents(
continue;
hasAddress = true;
fireChangeEvent(
NetworkEventDispatcher.fireChangeEvent(
new ChangeEvent(
networkInterface.getName(),
ChangeEvent.ADDRESS_UP,
@ -150,7 +144,7 @@ private void initialFireEvents(
}
if(hasAddress)
fireChangeEvent(
NetworkEventDispatcher.fireChangeEvent(
new ChangeEvent(networkInterface.getName(),
ChangeEvent.IFACE_UP, null, false, true),
listener);
@ -205,10 +199,7 @@ private void handleNewSystemActivityNotificationsService(
void removeNetworkConfigurationChangeListener(
NetworkConfigurationChangeListener listener)
{
synchronized(listeners)
{
listeners.remove(listener);
}
eventDispatcher.removeNetworkConfigurationChangeListener(listener);
}
/**
@ -251,41 +242,6 @@ public void serviceChanged(ServiceEvent serviceEvent)
}
}
/**
* Fire ChangeEvent.
* @param evt the event to fire.
*/
private void fireChangeEvent(ChangeEvent evt)
{
synchronized(listeners)
{
for (int i = 0; i < listeners.size(); i++)
{
NetworkConfigurationChangeListener nCChangeListener
= listeners.get(i);
fireChangeEvent(evt, nCChangeListener);
}
}
}
/**
* Fire ChangeEvent.
* @param evt the event to fire.
*/
private void fireChangeEvent(ChangeEvent evt,
NetworkConfigurationChangeListener listener)
{
try
{
listener.configurationChanged(evt);
} catch (Throwable e)
{
logger.warn("Error delivering event:" + evt + ", to:"
+ listener);
}
}
/**
* Stop.
*/
@ -299,27 +255,9 @@ void stop()
notifyAll();
}
}
}
/**
* Whether the supplied interface has a valid non-local address.
* @param iface interface.
* @return has a valid address.
*/
private static boolean hasValidAddress(NetworkInterface iface)
{
Enumeration<InetAddress> as =
iface.getInetAddresses();
while (as.hasMoreElements())
{
InetAddress inetAddress = as.nextElement();
if(inetAddress.isLinkLocalAddress())
continue;
return true;
}
return false;
if(eventDispatcher != null)
eventDispatcher.stop();
}
/**
@ -419,7 +357,7 @@ private void downAllInterfaces()
while (iter.hasNext())
{
String niface = iter.next();
fireChangeEvent(new ChangeEvent(niface,
eventDispatcher.fireChangeEvent(new ChangeEvent(niface,
ChangeEvent.IFACE_DOWN, true));
}
activeInterfaces.clear();
@ -492,7 +430,7 @@ private void checkNetworkInterfaces(
if(!currentActiveInterfacesSet.contains(iface))
{
if(fireEvents)
fireChangeEvent(new ChangeEvent(iface,
eventDispatcher.fireChangeEvent(new ChangeEvent(iface,
ChangeEvent.IFACE_DOWN));
activeInterfaces.remove(iface);
@ -520,7 +458,7 @@ private void checkNetworkInterfaces(
if(addresses != null && !addresses.contains(addr))
{
if(fireEvents)
fireChangeEvent(
eventDispatcher.fireChangeEvent(
new ChangeEvent(entry.getKey(),
ChangeEvent.ADDRESS_DOWN, addr));
@ -537,7 +475,7 @@ private void checkNetworkInterfaces(
synchronized(this)
{
try{
wait(1000);
wait(waitBeforeFiringUpEvents);
}catch(InterruptedException ex){}
}
}
@ -558,8 +496,10 @@ private void checkNetworkInterfaces(
if(addresses != null && !addresses.contains(addr))
{
if(fireEvents)
fireChangeEvent(new ChangeEvent(entry.getKey(),
ChangeEvent.ADDRESS_UP, addr));
eventDispatcher.fireChangeEvent(
new ChangeEvent(entry.getKey(),
ChangeEvent.ADDRESS_UP,
addr));
addresses.add(addr);
}
@ -579,18 +519,32 @@ private void checkNetworkInterfaces(
activeEntriesIter = currentActiveInterfaces.entrySet().iterator();
while(activeEntriesIter.hasNext())
{
Map.Entry<String, List<InetAddress>>
final Map.Entry<String, List<InetAddress>>
entry = activeEntriesIter.next();
for(InetAddress addr : entry.getValue())
{
if(fireEvents)
fireChangeEvent(new ChangeEvent(entry.getKey(),
ChangeEvent.ADDRESS_UP, addr));
eventDispatcher.fireChangeEvent(
new ChangeEvent(entry.getKey(),
ChangeEvent.ADDRESS_UP,
addr));
}
if(fireEvents)
fireChangeEvent(new ChangeEvent(entry.getKey(),
ChangeEvent.IFACE_UP));
{
// if we haven't waited before, lets wait here
// and give time to underlying os to configure fully the
// network interface (receive and store dns config)
int wait = waitBeforeFiringUpEvents;
if(wait == 0)
{
wait = 500;
}
eventDispatcher.fireChangeEvent(
new ChangeEvent(entry.getKey(), ChangeEvent.IFACE_UP),
wait);
}
activeInterfaces.put(entry.getKey(), entry.getValue());
}

@ -0,0 +1,230 @@
/*
* 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.netaddr;
import net.java.sip.communicator.service.netaddr.event.*;
import net.java.sip.communicator.util.*;
import java.util.*;
/**
* The class implements a dispatch event thread. The thread will
* fire event every time it is added through the <tt>fireChangeEvent()</tt>
* method and would then deliver it to a registered listener if any.
* (No fire would be performed until we have a
* <tt>NetworkConfigurationChangeListener</tt>). If the event has time set
* we used it as a delay before dispatching the event.
* <p>
*
* @author Damian Minkov
*/
public class NetworkEventDispatcher
implements Runnable
{
/**
* Our class logger.
*/
private static Logger logger =
Logger.getLogger(NetworkEventDispatcher.class);
/**
* Listeners for network configuration changes.
*/
private final List<NetworkConfigurationChangeListener> listeners =
new ArrayList<NetworkConfigurationChangeListener>();
/**
* The events to dispatch.
*/
private Map<ChangeEvent, Integer> eventsToDispatch
= new LinkedHashMap<ChangeEvent, Integer>();
/**
* start/stop indicator.
*/
private boolean stopped = true;
/**
* The thread that runs this dispatcher.
*/
private Thread dispatcherThread = null;
/**
* Adds new <tt>NetworkConfigurationChangeListener</tt> which will
* be informed for network configuration changes.
* @param listener the listener.
*/
void addNetworkConfigurationChangeListener(
NetworkConfigurationChangeListener listener)
{
synchronized(listeners)
{
if(!listeners.contains(listener))
{
listeners.add(listener);
if(dispatcherThread == null)
{
dispatcherThread = new Thread(this);
dispatcherThread.start();
}
}
}
}
/**
* Remove <tt>NetworkConfigurationChangeListener</tt>.
* @param listener the listener.
*/
void removeNetworkConfigurationChangeListener(
NetworkConfigurationChangeListener listener)
{
synchronized(listeners)
{
listeners.remove(listener);
}
}
/**
* Fire ChangeEvent.
* @param evt the event to fire.
*/
protected void fireChangeEvent(ChangeEvent evt)
{
this.fireChangeEvent(evt, 0);
}
/**
* Fire ChangeEvent.
* @param evt the event to fire.
*/
protected void fireChangeEvent(ChangeEvent evt, int wait)
{
synchronized(eventsToDispatch)
{
eventsToDispatch.put(evt, wait);
eventsToDispatch.notifyAll();
if(dispatcherThread == null && listeners.size() > 0)
{
dispatcherThread = new Thread(this);
dispatcherThread.start();
}
}
}
/**
* Fire ChangeEvent.
* @param evt the event to fire.
*/
static void fireChangeEvent(ChangeEvent evt,
NetworkConfigurationChangeListener listener)
{
try
{
if(logger.isTraceEnabled())
logger.trace("firing event to " + listener + " evt=" + evt);
listener.configurationChanged(evt);
} catch (Throwable e)
{
logger.warn("Error delivering event:" + evt + ", to:" + listener);
}
}
/**
* Runs the waiting thread.
*/
public void run()
{
stopped = false;
while(!stopped)
{
Map.Entry<ChangeEvent, Integer> eventToProcess = null;
List<NetworkConfigurationChangeListener> listenersCopy = null;
synchronized(eventsToDispatch)
{
if(eventsToDispatch.size() == 0)
{
try {
eventsToDispatch.wait();
}
catch (InterruptedException iex){}
}
//no point in dispatching if there's no one
//listening
if (listeners.size() == 0)
continue;
//store the ref of the listener in case someone resets
//it before we've had a chance to notify it.
listenersCopy = new ArrayList
<NetworkConfigurationChangeListener>(listeners);
Iterator<Map.Entry<ChangeEvent, Integer>> iter =
eventsToDispatch.entrySet().iterator();
if(iter.hasNext())
{
eventToProcess = iter.next();
iter.remove();
}
}
if(eventToProcess != null && listenersCopy != null)
{
if(eventToProcess.getValue() > 0)
synchronized(this)
{
try{
wait(eventToProcess.getValue());
}catch(Throwable t){}
}
for (int i = 0; i < listenersCopy.size(); i++)
{
fireChangeEvent(eventToProcess.getKey(),
listenersCopy.get(i));
}
}
eventToProcess = null;
listenersCopy = null;
}
}
/**
* Interrupts this dispatcher so that it would no longer disptach events.
*/
public void stop()
{
synchronized(eventsToDispatch)
{
stopped = true;
eventsToDispatch.notifyAll();
dispatcherThread = null;
}
}
/**
* Returns <tt>true</tt> if this dispatcher is currently running and
* delivering events when available and <tt>false</tt>
* otherwise.
*
* @return <tt>true</tt> if this dispatcher is currently running and
* delivering events when available and <tt>false</tt>
* otherwise.
*/
public boolean isRunning()
{
return !stopped;
}
}

@ -806,6 +806,12 @@ else if(state == ConnectState.STOP_TRYING)
// also needs this lock.
if(eventDuringLogin != null)
{
if(eventDuringLogin.getNewState().equals(
RegistrationState.CONNECTION_FAILED) ||
eventDuringLogin.getNewState().equals(
RegistrationState.UNREGISTERED))
disconnectAndCleanConnection();
fireRegistrationStateChanged(
eventDuringLogin.getOldState(),
eventDuringLogin.getNewState(),

@ -113,7 +113,7 @@ public class ReconnectPluginActivator
/**
* Start of the delay interval when starting a reconnect.
*/
private static final int RECONNECT_DELAY_MIN = 1; // sec
private static final int RECONNECT_DELAY_MIN = 2; // sec
/**
* The end of the interval for the initial reconnect.
@ -784,6 +784,24 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt)
if(timer == null)
return;
if(connectedInterfaces.size() == 0)
{
// well there is no network we just need
// this provider in needs reconnection when
// there is one
// means we started unregistering while
// network was going down and meanwhile there
// were no connected interface, this happens
// when we have more than one connected
// interface and we got 2 events for down iface
needsReconnection.add(pp);
if(currentlyReconnecting.containsKey(pp))
currentlyReconnecting.remove(pp).cancel();
return;
}
currentlyReconnecting.put(pp, task);
if (logger.isTraceEnabled())

@ -163,7 +163,9 @@ public String toString()
case ADDRESS_UP : buff.append("Address up"); break;
}
buff.append(", standby=" + standby);
buff.append(", standby=" + standby)
.append(", source=" + source)
.append(", address=" + address);
return buff.toString();
}

Loading…
Cancel
Save