package com.limegroup.gnutella.connection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.limewire.net.SocketsManager;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.limegroup.gnutella.ConnectionManager;
import com.limegroup.gnutella.ConnectionServices;
import com.limegroup.gnutella.DownloadServices;
import com.limegroup.gnutella.UploadServices;
@Singleton
public class ConnectionCheckerManagerImpl implements ConnectionCheckerManager {
private static final Log LOG = LogFactory.getLog(ConnectionCheckerManagerImpl.class);
/**
* Array of standard internet hosts to connect to when determining whether
* or not the user has a live Internet connection. These are randomized
* so a minimum number is hit on each check. Note that we only hit one
* random server per test and that we only test the connection if we have
* ample evidence that the users machine is no longer connected, resulting
* in minimal traffic to these sites.
*/
private static final String[] STANDARD_HOSTS = {
"www.wanadoo.fr",
"www.tiscali.com",
"www.ntt.com",
"www.tonline.com",
"www.download.com",
"www.ibm.com",
"www.sun.com",
"www.apple.com",
"www.ebay.com",
"www.sun.com",
"www.monster.com",
"www.uunet.com",
"www.real.com",
"www.microsoft.com",
"www.sco.com",
"www.google.com",
"www.cnn.com",
"www.amazon.com",
"www.espn.com",
"www.yahoo.com",
"www.oracle.com",
"www.dell.com",
"www.ge.com",
"www.sprint.com",
"www.att.com",
"www.mci.com",
"www.cisco.com",
"www.intel.com",
"www.motorola.com",
"www.hp.com",
"www.gateway.com",
"www.sony.com",
"www.ford.com",
"www.gm.com",
"www.aol.com",
"www.verizon.com",
"www.passport.com",
"www.go.com",
"www.overture.com",
"www.earthlink.net",
"www.bellsouth.net",
"www.excite.com",
"www.paypal.com",
"www.altavista.com",
"www.weather.com",
"www.mapquest.com",
"www.geocities.com",
"www.juno.com",
"www.msnbc.com",
"www.lycos.com",
"www.comcast.com",
};
private final AtomicInteger numWorkarounds = new AtomicInteger();
private volatile ConnectionChecker currentChecker;
private ConnectionServices connectionServices;
private Provider<ConnectionManager> connectionManager;
private UploadServices uploadServices;
private SocketsManager socketsManager;
private final DownloadServices downloadServices;
private final Provider<UDPConnectionChecker> udpConnectionChecker;
private final ExecutorService executor;
private volatile boolean connected;
private volatile Future<Boolean> currentCheckerFuture;
@Inject
public ConnectionCheckerManagerImpl(ConnectionServices connectionServices,
Provider<ConnectionManager> connectionManager,
UploadServices uploadServices,
DownloadServices downloadServices,
SocketsManager socketsManager,
Provider<UDPConnectionChecker> udpConnectionChecker,
@Named("unlimitedExecutor") ExecutorService executor) {
this.connectionServices = connectionServices;
this.connectionManager = connectionManager;
this.uploadServices = uploadServices;
this.downloadServices = downloadServices;
this.socketsManager = socketsManager;
this.udpConnectionChecker = udpConnectionChecker;
this.executor = executor;
}
public Future<Boolean> checkForLiveConnection() {
LOG.debug("Checking for live connection");
boolean startThread = false;
synchronized (this) {
if (currentChecker == null) {
startThread = true;
currentChecker = new ConnectionChecker(numWorkarounds, getDefaultHosts(),
connectionServices, uploadServices, downloadServices,
socketsManager, udpConnectionChecker.get());
}
}
// Only create a new thread if one isn't alive.
if(startThread) {
LOG.debug("Starting a new connection-checker thread");
currentCheckerFuture = executor.submit(new ConnectionCheckerRunner());
}
return currentCheckerFuture;
}
public String[] getDefaultHosts() {
return STANDARD_HOSTS;
}
public int getNumWorkarounds() {
return numWorkarounds.get();
}
public boolean isConnected() {
return connected;
}
private class ConnectionCheckerRunner implements ConnectionCheckerListener, Callable<Boolean> {
public void connected() {
LOG.debug("Connected");
ConnectionCheckerManagerImpl.this.connected = true;
}
public void noInternetConnection() {
LOG.debug("No internet connection");
ConnectionCheckerManagerImpl.this.connected = false;
connectionManager.get().noInternetConnection();
}
public Boolean call() {
final ConnectionChecker checker;
synchronized (ConnectionCheckerManagerImpl.this) {
checker = currentChecker;
}
try {
checker.run(this);
} finally {
synchronized (ConnectionCheckerManagerImpl.this) {
currentChecker = null;
}
}
return ConnectionCheckerManagerImpl.this.connected;
}
}
}