package com.limegroup.gnutella;
import java.util.Set;
import org.limewire.io.Address;
import org.limewire.io.GUID;
import org.limewire.io.IpPort;
import com.limegroup.gnutella.http.HTTPHeaderValue;
/**
* a class that represents an endpoint behind one or more PushProxies.
* almost everything is immutable including the contents of the set.
*
* the network format this is serialized to is:
* byte 0 (from right-to-left):
* - bits 0-2 how many push proxies we have (so max is 7)
* - bits 3-4 the version of the f2f transfer protocol this altloc supports
* - bits 5-6 other possible features.
* - bit 7 set if the TLS-capable push proxy indexes byte is included
* bytes 1-16 : the guid
* bytes 17-22: ip:port of the address (if FWT version > 0)
* followed by a byte of TLS-capable PushProxy indexes (if bit 7 of features is set)
* followed by 6 bytes per PushProxy
*
* the http format this is serialized to is an ascii string consisting of
* ';'-delimited tokens. The first token is the client GUID represented in hex
* and is the only required token. The other tokens can be addresses of push proxies
* or various feature headers. At most one of the tokens should be the external ip and port
* of the firewalled node in a port:ip format. Currently the only feature header we
* parse is the fwawt header that contains the version number of the firewall to
* firewall transfer protocol supported by the altloc. In addition, the 'pptls=' field
* can indicate which, if any, push proxies support TLS. If the field is present, it
* must be immediately before the listing of the push proxies. The hexadecimal string
* after the '=' is a bit-representation of which push proxies are valid for TLS.
*
* A PE does not need to know the actual external address of the firewalled host,
* however without that knowledge we cannot do firewall-to-firewall transfer with
* the given host. Also, the RemoteFileDesc objects requires a valid IP for construction,
* so in the case we do not know the external address we return a BOGUS_IP.
*
* Examples:
*
* //altloc with 2 proxies and supports firewall transfer 1 :
*
* <ThisIsTheGUIDASDF>;fwt/1.0;20.30.40.50:60;1.2.3.4:5567
*
* //altloc with 1 proxy and doesn't support firewall transfer, with external address:
*
* <ThisIsTHeGUIDasfdaa527>;1.2.3.4:5564;6346:2.3.4.5
*
* //altloc with 1 proxy and supports two features we don't know/care about :
*
* <ThisIsTHeGUIDasfdaa527>;someFeature/3.2;10.20.30.40:5564;otherFeature/0.4
*
* //altloc with 1 proxy (the first) that's TLS capable, 1 that isn't:
*
* <ThisIsTheGUIDASDF>;fwt/1.0;pptls=8;20.30.40.50:60;1.2.3.4:5567
*
* //altloc without any proxies and doesn't support any features
* // not very useful, but still valid
*
* <ThisIsTheGUIDasdf23457>
*/
public interface PushEndpoint extends HTTPHeaderValue, IpPort, Address {
public static final int HEADER_SIZE = 17; //guid+# of proxies, maybe other things too
public static final int PROXY_SIZE = 6; //ip:port
public static final byte PLAIN = 0x0; //no features for this PE
public static final byte PPTLS_BINARY = (byte) 0x80;
public static final byte SIZE_MASK=0x7; //0000 0111
public static final byte FWT_VERSION_MASK=0x18; //0001 1000
//the features mask does not clear the bits we do not understand
//because we may pass on the altloc to someone who does.
public static final byte FEATURES_MASK= (byte)0xE0; //1110 0000
/** The pptls portion constant. */
public static final String PPTLS_HTTP = "pptls";
/** The maximum number of proxies to use. */
public static final int MAX_PROXIES = 4;
/**
* @return a byte-packed representation of this
*/
byte[] toBytes(boolean includeTLS);
/**
* creates a byte packet representation of this
* @param where the byte [] to serialize to
* @param offset the offset within that byte [] to serialize
*/
void toBytes(byte[] where, int offset, boolean includeTLS);
/**
* Returns the GUID of the client that can be reached through the pushproxies.
*/
byte[] getClientGUID();
/**
* @return a view of the current set of proxies, never returns null
*/
Set<? extends IpPort> getProxies();
/**
* @return which version of F2F transfers this PE supports.
* This always returns the most current version we know the PE supports
* unless it has never been put in the map.
*/
int getFWTVersion();
/**
* Should return the {@link GUID#hashCode()} of {@link #getClientGUID()}.
*/
int hashCode();
/**
* Equality should be based on the equality of the value of {@link #getClientGUID()}.
*/
boolean equals(Object other);
/**
* @return the various features this PE reports. This always
* returns the most current features, or the ones it was created with
* if they have never been updated.
*/
byte getFeatures();
/**
* @return true if this is the push endpoint for the local node
*/
boolean isLocal();
/**
* Updates either the PushEndpoint or the GUID_PROXY_MAP to ensure
* that GUID_PROXY_MAP has a reference to all live PE GUIDs and
* all live PE's reference the same GUID object as in GUID_PROXY_MAP.
*
* If this method is not called, the PE will know only about the set
* of proxies the remote host had when it was created. Otherwise it
* will point to the most recent known set.
*/
// TODO remove this in the long run and use the cache explicitly
void updateProxies(boolean good);
/**
* Can return null if no valid push endpoint can be cloned.
*/
PushEndpoint createClone();
/**
* Returns an {@link IpPort} representing the valid external address of
* this push endpoint if it is known, otherwise <code>null</code>.
*/
IpPort getValidExternalAddress();
/**
* @return the external address if known otherwise {@link RemoteFileDesc#BOGUS_IP}
*/
String getAddress();
}