package com.limegroup.gnutella.altlocs;
import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import com.limegroup.gnutella.http.HTTPConstants;
import com.limegroup.gnutella.util.IpPort;
import com.limegroup.gnutella.Endpoint;
import com.limegroup.gnutella.ErrorService;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.util.DataUtils;
import com.limegroup.gnutella.util.IpPortForSelf;
import com.limegroup.gnutella.util.IpPortImpl;
import com.limegroup.gnutella.util.NetworkUtils;
/**
* An alternate location that is directly reachable, i.e. not firewalled.
*/
public class DirectAltLoc extends AlternateLocation {
private final IpPort _node;
/**
* Remembers if this AltLoc ever failed, if it did _demoted is set. If this
* succeeds, it may be promoted again resetting the value of _demoted. The
* _count attribute does does take into account the case of a good alternate
* location with a high count, which has recently failed.
* <p>
* Note that demotion in not intrinsic to the use of this class, some
* modules like the download may not want to demote an AlternatLocation,
* other like the uploader may rely on it.
*/
protected volatile boolean _demoted = false;
/**
* Creates a new <tt>AlternateLocation</tt> with the specified <tt>URL</tt>
* and <tt>Date</tt> timestamp.
*
* @param url the <tt>URL</tt> for the <tt>AlternateLocation</tt>
* @param date the <tt>Date</tt> timestamp for the
* <tt>AlternateLocation</tt>
*/
protected DirectAltLoc(final URL url, final URN sha1)
throws IOException {
this(new IpPortImpl(url.getHost(),url.getPort()),sha1);
}
/**
* creates an altloc for myself.
*/
protected DirectAltLoc(final URN sha1) throws IOException{
this(new Endpoint(
RouterService.getAddress(),
RouterService.getPort())
,sha1);
}
protected DirectAltLoc(IpPort address, URN sha1) throws IOException{
super(sha1);
if (!NetworkUtils.isValidExternalIpPort(address))
throw new IOException("not a valid external address:port in direct altloc "+address);
_node=address;
if (_node == IpPortForSelf.instance())
hashCode = IpPortForSelf.instance().hashCode();
}
protected String generateHTTPString() {
String ret = _node.getInetAddress().getHostAddress();
if (_node.getPort()!=6346)
ret = ret+":"+_node.getPort();
return ret;
}
public RemoteFileDesc createRemoteFileDesc(int size) {
Set urnSet = new HashSet();
urnSet.add(getSHA1Urn());
int quality = 3;
RemoteFileDesc ret = new RemoteFileDesc(_node.getAddress(), _node.getPort(),
0, HTTPConstants.URI_RES_N2R+SHA1_URN, size,
DataUtils.EMPTY_GUID, 1000,
true, quality, false, null, urnSet, false,
false, //assume altLoc is not firewalled
ALT_VENDOR,//Never displayed, and we don't know
System.currentTimeMillis(), null, -1);
return ret;
}
public synchronized AlternateLocation createClone() {
DirectAltLoc ret = null;
try {
ret = new DirectAltLoc(_node, this.SHA1_URN);
} catch(IOException ioe) {
ErrorService.error(ioe);
return null;
}
ret._demoted = this._demoted;
ret._count = this._count;
return ret;
}
public boolean isMe(){
return NetworkUtils.isMe(_node);
}
/**
* Returns the host/port of this alternate location as an endpoint.
*/
public IpPort getHost() {
return _node;
}
public boolean equals(Object o){
if (o==null || !(o instanceof DirectAltLoc))
return false;
if (!super.equals(o))
return false;
DirectAltLoc other = (DirectAltLoc)o;
if (_node == other._node)
return true;
return (_node.getInetAddress().equals(other._node.getInetAddress()) &&
_node.getPort() == other._node.getPort());
}
synchronized void demote() { _demoted = true;}
synchronized void promote() { _demoted = false; }
public synchronized boolean isDemoted() { return _demoted; }
public int compareTo(Object o) {
if (this==o) //equal
return 0;
int ret = super.compareTo(o);
// if comparing to PushLocs count is all we need.
// if that is the same, compare by hashCode()
if (!(o instanceof DirectAltLoc)) {
if (ret!=0)
return ret;
else
return -1;
}
DirectAltLoc other = (DirectAltLoc)o;
// if I'm demoted, I'm bigger. Otherwise I'm smaller
if (_demoted != other._demoted) {
if (_demoted)
return 1;
return -1;
}
// ret still holds the count difference
if (ret != 0)
return ret;
// if we are both altlocs for myself
if (_node == other._node)
return 0;
ret = _node.getAddress().compareTo(other._node.getAddress());
if (ret != 0)
return ret;
ret = (_node.getPort() - other._node.getPort());
// if we got here and ret is still 0, we are the same as the other
// DirectLoc.
return ret;
}
public int hashCode() {
if (hashCode ==0) {
int result = super.hashCode();
result = (37* result)+_node.getInetAddress().hashCode();
result = (37* result)+_node.getPort();
hashCode=result;
}
return hashCode;
}
/**
* Overrides toString to return a string representation of this
* <tt>AlternateLocation</tt>, namely the url and the date.
*
* @return the string representation of this alternate location
*/
public String toString() {
return _node+","+_count+","+_demoted;
}
}