Detects ip changes (not link changes) under macosx. Fixes a problem with reconnecting several tcp/tls sip providers.

cusax-fix
Damian Minkov 15 years ago
parent c4883ab9fc
commit 326a24d843

@ -215,7 +215,7 @@ void scCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
&context);
const CFStringRef keys[1] = {
CFSTR("State:/Network/Interface/.*/Link")
CFSTR("State:/Network/Interface/.*/IPv.")
};
CFArrayRef watchedKeys = CFArrayCreate(kCFAllocatorDefault,
(const void **)keys,
@ -226,7 +226,8 @@ void scCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
watchedKeys))
{
CFRelease(watchedKeys);
fprintf(stderr, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
fprintf(stderr, "SCDynamicStoreSetNotificationKeys() failed: %s",
SCErrorString(SCError()));
CFRelease(dynStore);
dynStore = NULL;
@ -235,8 +236,10 @@ void scCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
CFRelease(watchedKeys);
rlSrc = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, dynStore, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rlSrc, kCFRunLoopDefaultMode);
rlSrc = SCDynamicStoreCreateRunLoopSource(
kCFAllocatorDefault, dynStore, 0);
CFRunLoopAddSource(
CFRunLoopGetCurrent(), rlSrc, kCFRunLoopDefaultMode);
CFRelease(rlSrc);
}
}

@ -173,6 +173,9 @@ private void initialFireEvents(
private void handleNewSystemActivityNotificationsService(
SystemActivityNotificationsService newService)
{
if(newService == null)
return;
this.systemActivityNotificationsService = newService;
if(this.systemActivityNotificationsService
@ -397,16 +400,6 @@ public void activityChanged(SystemActivityEvent event)
}
else if(event.getEventID() == SystemActivityEvent.EVENT_NETWORK_CHANGE)
{
// when there is a net change
// give time for devices to come up/down fully
// before checking with them
synchronized(this)
{
try{
wait(3000);
}catch(InterruptedException ex){}
}
try
{
checkNetworkInterfaces(true, 0);

@ -136,7 +136,8 @@ public void processPacket(Packet packet)
try
{
if(packetLogging.isLoggingEnabled(
PacketLoggingService.ProtocolName.JABBER))
PacketLoggingService.ProtocolName.JABBER)
&& packet != null && connection.getSocket() != null)
{
packetLogging.logPacket(
PacketLoggingService.ProtocolName.JABBER,

@ -185,6 +185,9 @@ public static byte[] loadIcon(String imagePath)
{
InputStream is = resources.getImageInputStreamForPath(imagePath);
if(is == null)
return null;
try
{
icon = new byte[is.available()];

@ -18,7 +18,9 @@
import javax.sip.header.*;
import javax.sip.message.*;
import net.java.sip.communicator.service.netaddr.event.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
@ -35,7 +37,8 @@
* @author Sebastien Mazy
*/
public class SipStackSharing
implements SipListener
implements SipListener,
NetworkConfigurationChangeListener
{
/**
* We set a custom parameter in the contact address for registrar accounts,
@ -116,6 +119,9 @@ public class SipStackSharing
new AddressResolverImpl();
((SIPTransactionStack) this.stack)
.setAddressResolver(addressResolver);
SipActivator.getNetworkAddressManagerService()
.addNetworkConfigurationChangeListener(this);
}
catch(Exception ex)
{
@ -1187,4 +1193,149 @@ private boolean applyNonConformanceHacks(RequestEvent event)
return false;
}
/**
* List of currently waiting timers that will monitor the protocol provider
*
*/
Map<String, TimerTask> resetListeningPointsTimers
= new HashMap<String, TimerTask>();
/**
* Listens for network changes and if we have a down interface
* and we have a tcp/tls provider which is staying for 20 seconds in
* unregistering state, it cannot unregister cause its using the old
* address which is currently down, and we must recreate its listening
* points so it can further reconnect.
*
* @param event the change event.
*/
public void configurationChanged(ChangeEvent event)
{
if(event.isInitial())
return;
if(event.getType() == ChangeEvent.ADDRESS_DOWN)
{
for(final ProtocolProviderServiceSipImpl pp : listeners)
{
if(pp.getRegistrarConnection().getTransport() != null
&& (pp.getRegistrarConnection().getTransport()
.equals(ListeningPoint.TCP)
|| pp.getRegistrarConnection().getTransport()
.equals(ListeningPoint.TLS)))
{
ResetListeningPoint reseter;
synchronized(resetListeningPointsTimers)
{
// we do this only once for transport
if(resetListeningPointsTimers.containsKey(
pp.getRegistrarConnection().getTransport()))
continue;
reseter = new ResetListeningPoint(pp);
resetListeningPointsTimers.put(
pp.getRegistrarConnection().getTransport(),
reseter);
}
pp.addRegistrationStateChangeListener(reseter);
}
}
}
}
/**
* If a tcp(tls) provider stays unregistering for a long time after
* connection changed most probably it won't get registered after
* unregistering fails, cause underlying listening point are conncted
* to wrong interfaces. So we will replace them.
*/
private class ResetListeningPoint
extends TimerTask
implements RegistrationStateChangeListener
{
/**
* The time we wait before checking is the provider still unregistering.
*/
private static final int TIME_FOR_PP_TO_UNREGISTER = 20000;
/**
* The protocol provider we are checking.
*/
private final ProtocolProviderServiceSipImpl protocolProvider;
/**
* Constructs this task.
* @param pp
*/
ResetListeningPoint(ProtocolProviderServiceSipImpl pp)
{
this.protocolProvider = pp;
}
/**
* Notified when registration state changed for a provider.
* @param evt
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
if(evt.getNewState() == RegistrationState.UNREGISTERING)
{
new Timer().schedule(this, TIME_FOR_PP_TO_UNREGISTER);
}
else
{
protocolProvider.removeRegistrationStateChangeListener(this);
resetListeningPointsTimers.remove(
protocolProvider.getRegistrarConnection().getTransport());
}
}
/**
* The real task work, replace listening point.
*/
public void run()
{
// if the provider is still unregistering it most probably won't
// successes until we re-init the LP
if(protocolProvider.getRegistrationState()
== RegistrationState.UNREGISTERING)
{
String transport = protocolProvider.getRegistrarConnection()
.getTransport();
ListeningPoint old = getLP(transport);
try
{
stack.deleteListeningPoint(old);
}
catch(Throwable t)
{
logger.warn("Error replacing ListeningPoint for "
+ transport, t);
}
try
{
ListeningPoint tcpLP =
stack.createListeningPoint(
NetworkUtils.IN_ADDR_ANY
, transport.equals(ListeningPoint.TCP)?
getPreferredClearPort(): getPreferredSecurePort()
, transport);
clearJainSipProvider.addListeningPoint(tcpLP);
}
catch(Throwable t)
{
logger.warn("Error replacing ListeningPoint for " +
protocolProvider.getRegistrarConnection().getTransport(),
t);
}
}
resetListeningPointsTimers.remove(
protocolProvider.getRegistrarConnection().getTransport());
}
}
}

@ -46,6 +46,7 @@ Import-Package: org.apache.log4j,
net.java.sip.communicator.service.neomedia.format,
net.java.sip.communicator.service.hid,
net.java.sip.communicator.service.netaddr,
net.java.sip.communicator.service.netaddr.event,
net.java.sip.communicator.service.packetlogging,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,

@ -502,7 +502,7 @@ public InputStream getImageInputStreamForPath(String path)
}
}
if (path != null)
if (path != null && imagePack != null)
return imagePack.getClass().getClassLoader()
.getResourceAsStream(path);

@ -71,7 +71,7 @@ public void start(BundleContext bc) throws Exception
new DefaultSettingsPackImpl();
Hashtable<String, String> setProps = new Hashtable<String, String>();
langProps.put(ResourcePack.RESOURCE_NAME,
setProps.put(ResourcePack.RESOURCE_NAME,
SettingsPack.RESOURCE_NAME_DEFAULT_VALUE);
bundleContext.registerService( SettingsPack.class.getName(),
@ -82,7 +82,7 @@ public void start(BundleContext bc) throws Exception
new DefaultSoundPackImpl();
Hashtable<String, String> sndProps = new Hashtable<String, String>();
langProps.put(ResourcePack.RESOURCE_NAME,
sndProps.put(ResourcePack.RESOURCE_NAME,
SoundPack.RESOURCE_NAME_DEFAULT_VALUE);
bundleContext.registerService( SoundPack.class.getName(),

@ -434,7 +434,7 @@ public synchronized void configurationChanged(ChangeEvent event)
reconnect(pp);
}
needsReconnection.clear();
}
@ -491,7 +491,8 @@ else if(event.getType() == ChangeEvent.IFACE_DOWN)
currentlyReconnecting.remove(pp).cancel();
}
unregister(pp);
// don't reconnect just unregister if needed.
unregister(pp, false, null, null);
}
connectedInterfaces.clear();
@ -514,8 +515,16 @@ else if(event.getType() == ChangeEvent.IFACE_DOWN)
* Unregisters the ProtocolProvider. Make sure to do it in separate thread
* so we don't block other processing.
* @param pp the protocol provider to unregister.
*/
private void unregister(final ProtocolProviderService pp)
* @param reconnect if the protocol provider does not need unregistering
* shall we trigger reconnect. Its true when call called from
* reconnect.
* @param listener the listener used in reconnect method.
* @param task the task to use for reconnection.
*/
private void unregister(final ProtocolProviderService pp,
final boolean reconnect,
final RegistrationStateChangeListener listener,
final ReconnectTask task)
{
unregisteredProviders.add(pp);
@ -535,7 +544,26 @@ public void run()
RegistrationState.UNREGISTERED)
|| pp.getRegistrationState().equals(
RegistrationState.CONNECTION_FAILED))
{
if(reconnect)
{
if(listener != null)
pp.removeRegistrationStateChangeListener(
listener);
if(timer == null || task == null)
return;
currentlyReconnecting.put(pp, task);
if (logger.isTraceEnabled())
logger.trace("Reconnect " + pp +
" after " + task.delay + " ms.");
timer.schedule(task, task.delay);
}
return;
}
pp.unregister();
}
@ -713,7 +741,7 @@ else if(evt.getNewState().equals(RegistrationState.UNREGISTERED))
* Method to schedule a reconnect for a protocol provider.
* @param pp the provider.
*/
private void reconnect(ProtocolProviderService pp)
private void reconnect(final ProtocolProviderService pp)
{
long delay;
@ -733,16 +761,50 @@ private void reconnect(ProtocolProviderService pp)
+ Math.random() * RECONNECT_DELAY_MAX)*1000;
}
// as we will reconnect, lets unregister
unregister(pp);
ReconnectTask task = new ReconnectTask(pp);
final ReconnectTask task = new ReconnectTask(pp);
task.delay = delay;
currentlyReconnecting.put(pp, task);
if (logger.isTraceEnabled())
logger.trace("Reconnect " + pp + " after " + delay + " ms.");
timer.schedule(task, delay);
// start registering after the pp has unregistered
RegistrationStateChangeListener listener =
new RegistrationStateChangeListener()
{
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
if(evt.getSource() instanceof ProtocolProviderService)
{
if(evt.getNewState().equals(
RegistrationState.UNREGISTERED)
|| evt.getNewState().equals(
RegistrationState.CONNECTION_FAILED))
{
synchronized(this)
{
pp.removeRegistrationStateChangeListener(this);
if(timer == null)
return;
currentlyReconnecting.put(pp, task);
if (logger.isTraceEnabled())
logger.trace("Reconnect " + pp +
" after " + task.delay + " ms.");
timer.schedule(task, task.delay);
}
}
else if(evt.getNewState().equals(
RegistrationState.REGISTERED))
{
pp.removeRegistrationStateChangeListener(this);
}
}
}
};
pp.addRegistrationStateChangeListener(listener);
// as we will reconnect, lets unregister
unregister(pp, true, listener, task);
}
/**

Loading…
Cancel
Save