package com.limegroup.gnutella.altlocs;
import java.io.IOException;
import java.util.Set;
import org.limewire.io.Connectable;
import org.limewire.io.ConnectableImpl;
import org.limewire.io.IpPort;
import org.limewire.io.NetworkInstanceUtils;
import org.limewire.service.ErrorService;
import com.limegroup.gnutella.RemoteFileDesc;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.UrnSet;
import com.limegroup.gnutella.downloader.RemoteFileDescFactory;
import com.limegroup.gnutella.http.HTTPConstants;
import com.limegroup.gnutella.util.DataUtils;
/**
* An alternate location that is directly reachable, i.e. not firewalled.
*/
public class DirectAltLoc extends AbstractAlternateLocation {
/**
* A constant prepending a list of direct locations that is used
* to define which locations following it support TLS.
*/
public static final String TLS_IDX = "tls=";
/** The node that backs this location. */
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;
private final NetworkInstanceUtils networkInstanceUtils;
protected DirectAltLoc(IpPort address, URN sha1, NetworkInstanceUtils networkInstanceUtils) throws IOException {
super(sha1);
this.networkInstanceUtils = networkInstanceUtils;
if (!networkInstanceUtils.isValidExternalIpPort(address))
throw new IOException("not a valid external address:port in direct altloc "+address);
_node=address;
}
@Override
protected String generateHTTPString() {
String ret = _node.getInetAddress().getHostAddress();
if (_node.getPort()!=6346)
ret = ret+":"+_node.getPort();
return ret;
}
@Override
public RemoteFileDesc createRemoteFileDesc(long size, RemoteFileDescFactory remoteFileDescFactory) {
Set<URN> urnSet = new UrnSet(getSHA1Urn());
int quality = 3;
RemoteFileDesc ret = remoteFileDescFactory.createRemoteFileDesc(_node instanceof Connectable ? (Connectable)_node : new ConnectableImpl(_node, false),
0, HTTPConstants.URI_RES_N2R + SHA1_URN, size, DataUtils.EMPTY_GUID,
1000, quality, false, null, urnSet, false, ALT_VENDOR, -1);
return ret;
}
@Override
public synchronized AlternateLocation createClone() {
DirectAltLoc ret = null;
try {
ret = new DirectAltLoc(_node, this.SHA1_URN, networkInstanceUtils);
} catch(IOException ioe) {
ErrorService.error(ioe);
return null;
}
ret._demoted = this._demoted;
ret._count = this._count;
return ret;
}
@Override
public boolean isMe(){
return networkInstanceUtils.isMe(_node);
}
/**
* Returns the host/port of this alternate location as an endpoint.
*/
public IpPort getHost() {
return _node;
}
@Override
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());
}
@Override
synchronized void demote() { _demoted = true;}
@Override
synchronized void promote() { _demoted = false; }
@Override
public synchronized boolean isDemoted() { return _demoted; }
@Override
public int compareTo(AlternateLocation 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;
}
@Override
public int hashCode() {
if (hashCode ==0) {
int result = super.hashCode();
result = (37* result)+_node.getAddress().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
*/
@Override
public String toString() {
return _node+","+_count+","+_demoted;
}
}