package com.limegroup.gnutella.connection;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.DefaultHttpClient;
import com.util.LOG;
import com.limegroup.gnutella.ErrorService;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.http.HTTPHeaderName;
import com.limegroup.gnutella.util.CommonUtils;
import com.limegroup.gnutella.util.ManagedThread;
/**
* Specialized class that attempts to connect to a rotating list of well-known
* Internet addresses to check whether or not this host has a live connection
* to the Internet.
*/
public final class ConnectionChecker implements Runnable {
/**
* Flag for whether or not we know for sure that we're connected from
* successfully connecting to an external host.
*/
private volatile boolean _connected;
/**
* Variable for the number of unsuccessful connection attempts.
*/
private int _unsuccessfulAttempts;
/**
* 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. NON-FINAL FOR TESTING.
*/
private static String[] STANDARD_HOSTS = {
"http://www.wanadoo.fr",
"http://www.tiscali.com",
"http://www.ntt.com",
"http://www.tonline.com",
"http://www.download.com",
"http://www.ibm.com",
"http://www.sun.com",
"http://www.apple.com",
"http://www.ebay.com",
"http://www.sun.com",
"http://www.monster.com",
"http://www.uunet.com",
"http://www.real.com",
"http://www.level3.com",
"http://www.microsoft.com",
"http://www.sco.com",
"http://www.google.com",
"http://www.cnn.com",
"http://www.amazon.com",
"http://www.espn.com",
"http://www.yahoo.com",
"http://www.oracle.com",
"http://www.dell.com",
"http://www.ge.com",
"http://www.sprint.com",
"http://www.att.com",
"http://www.mci.com",
"http://www.cisco.com",
"http://www.intel.com",
"http://www.motorola.com",
"http://www.hp.com",
"http://www.gateway.com",
"http://www.sony.com",
"http://www.ford.com",
"http://www.gm.com",
"http://www.aol.com",
"http://www.verizon.com",
"http://www.passport.com",
"http://www.go.com",
"http://www.overture.com",
"http://www.earthlink.net",
"http://www.bellsouth.net",
"http://www.excite.com",
"http://www.paypal.com",
"http://www.altavista.com",
"http://www.weather.com",
"http://www.mapquest.com",
"http://www.geocities.com",
"http://www.juno.com",
"http://www.msnbc.com",
"http://www.lycos.com",
"http://www.comcast.com",
"http://www.overture.com",
};
/**
* Private constructor ensures that only this class can create instances of
* itself.
*/
private ConnectionChecker() {}
/**
* Creates a new <tt>ConnectionChecker</tt> instance that checks for a live
* internet connection. If the checker determines that there is no active
* connection, it will notify the <tt>ConnectionManager</tt> to take
* appropriate action.
*
* @return a new <tt>ConnectionChecker</tt> instance
*/
public static ConnectionChecker checkForLiveConnection() {
LOG.trace("ConnectionChecker checking for live connection");
ConnectionChecker checker = new ConnectionChecker();
Thread connectionThread =
new ManagedThread(checker, "check for live connection");
connectionThread.setDaemon(true);
connectionThread.start();
return checker;
}
/**
* Checks for a live internet connection.
*/
public void run() {
try {
List hostList = Arrays.asList(STANDARD_HOSTS);
// Add some randomization.
Collections.shuffle(hostList);
Iterator iter = hostList.iterator();
while(iter.hasNext()) {
String curHost = (String)iter.next();
connectToHost(curHost);
// Break out of the loop if we've already discovered that we're
// connected -- we only need to successfully connect to one host
// to know for sure that we're up.
if(_connected) {
return;
}
// Stop if we've failed to connect to more than 2 of the hosts
// that should be up all of the time. We do this to make extra
// sure the user's connection is down. If it is down, trying
// multiple times adds no load to the test servers.
if(_unsuccessfulAttempts > 2) {
RouterService.getConnectionManager().noInternetConnection();
return;
}
}
} catch(Throwable t) {
// Report any unhandled errors.
ErrorService.error(t);
}
}
/**
* Determines whether or not we have connected to an external host,
* verifying that we have an internet connection.
*
* @return <tt>true</tt> if we have created a successful connection,
* otherwise <tt>false</tt>
*/
public boolean hasConnected() {
return _connected;
}
/**
* Connects to an individual host.
*
* @param host the host to connect to
*/
private void connectToHost(String host) {
if(LOG.isTraceEnabled()) {
LOG.trace("connecting to: "+host);
}
HttpHead head = new HttpHead(host);
head.addHeader("Cache-Control", "no-cache");
head.addHeader("User-Agent", CommonUtils.getHttpServer());
head.addHeader(HTTPHeaderName.CONNECTION.httpStringValue(),
"close");
//head.setFollowRedirects(false);
DefaultHttpClient client = new DefaultHttpClient();
try {
client.execute(head);
_connected = true;
} catch (IOException e) {
LOG.warn("Exception while handling server", e);
_unsuccessfulAttempts++;
}
}
}