/*
* Dijjer - A Peer to Peer HTTP Cache
* Copyright (C) 2004,2005 Change.Tv, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package freenet.io.comm;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import freenet.io.WritableToDataOutputStream;
import freenet.support.transport.ip.HostnameSyntaxException;
import freenet.support.transport.ip.IPUtil;
/**
* @author ian
*
* To change the template for this generated type comment go to Window - Preferences - Java - Code Generation - Code and
* Comments
*/
public class Peer implements WritableToDataOutputStream {
public static class LocalAddressException extends Exception {
private static final long serialVersionUID = -1;
}
public static final String VERSION = "$Id: Peer.java,v 1.4 2005/08/25 17:28:19 amphibian Exp $";
private final FreenetInetAddress addr;
private final int _port;
public Peer(DataInput dis) throws IOException {
addr = new FreenetInetAddress(dis);
_port = dis.readInt();
if(_port > 65535 || _port < 0) throw new IOException("bogus port");
}
public Peer(DataInput dis, boolean checkHostnameOrIPSyntax) throws HostnameSyntaxException, IOException {
addr = new FreenetInetAddress(dis, checkHostnameOrIPSyntax);
_port = dis.readInt();
if(_port > 65535 || _port < 0) throw new IOException("bogus port");
}
/**
* Create a Peer from an InetAddress and a port. The IP address is primary; that is
* to say, it will remain the same regardless of DNS changes. Don't do this if you
* are dealing with domain names whose IP may change.
*/
public Peer(InetAddress address, int port) {
addr = new FreenetInetAddress(address);
_port = port;
if(_port > 65535 || _port < 0) throw new IllegalArgumentException("bogus port");
}
/**
* Create a Peer from a string. This may be an IP address or a domain name. If it
* is the latter, the name is primary rather than the IP address;
* getHandshakeAddress() will do a new lookup on the name, and change the IP address
* if the domain name has changed.
* @param physical The string to be parsed, in the format [ ip or domain name ]:[ port number].
* @param allowUnknown If true, allow construction of the Peer even if the domain name
* lookup fails.
* @throws PeerParseException If the string is not valid e.g. if it doesn't contain a
* port.
* @throws UnknownHostException If allowUnknown is not set, and a domain name which does
* not exist was passed in.
*/
public Peer(String physical, boolean allowUnknown) throws PeerParseException, UnknownHostException {
int offset = physical.lastIndexOf(':'); // ipv6
if(offset < 0) throw new PeerParseException();
String host = physical.substring(0, offset);
addr = new FreenetInetAddress(host, allowUnknown);
String strport = physical.substring(offset+1);
try {
_port = Integer.parseInt(strport);
if(_port < 0 || _port > 65535) throw new PeerParseException("Invalid port "+_port);
} catch (NumberFormatException e) {
throw new PeerParseException(e);
}
}
/**
* Create a Peer from a string. This may be an IP address or a domain name. If it
* is the latter, the name is primary rather than the IP address;
* getHandshakeAddress() will do a new lookup on the name, and change the IP address
* if the domain name has changed.
* @param physical The string to be parsed, in the format [ ip or domain name ]:[ port number].
* @param allowUnknown If true, allow construction of the Peer even if the domain name
* lookup fails.
* @param checkHostnameOrIPSyntax If true, validate the syntax of the given DNS hostname or IPv4
* IP address
* @throws HostnameSyntaxException If the string is not formatted as a proper DNS hostname
* or IPv4 IP address
* @throws PeerParseException If the string is not valid e.g. if it doesn't contain a
* port.
* @throws UnknownHostException If allowUnknown is not set, and a domain name which does
* not exist was passed in.
*/
public Peer(String physical, boolean allowUnknown, boolean checkHostnameOrIPSyntax) throws HostnameSyntaxException, PeerParseException, UnknownHostException {
int offset = physical.lastIndexOf(':'); // ipv6
if(offset < 0)
throw new PeerParseException("No port number: \""+physical+"\"");
String host = physical.substring(0, offset);
addr = new FreenetInetAddress(host, allowUnknown, checkHostnameOrIPSyntax);
String strport = physical.substring(offset+1);
try {
_port = Integer.parseInt(strport);
if(_port < 0 || _port > 65535) throw new PeerParseException("Invalid port "+_port);
} catch (NumberFormatException e) {
throw new PeerParseException(e);
}
}
public Peer(FreenetInetAddress addr, int port) {
this.addr = addr;
if(addr == null) throw new NullPointerException();
this._port = port;
if(_port > 65535 || _port < 0) throw new IllegalArgumentException("bogus port");
}
public boolean isNull() {
return _port == 0;
}
// FIXME same issues as with FreenetInetAddress.laxEquals/equals/strictEquals
public boolean laxEquals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Peer)) {
return false;
}
final Peer peer = (Peer) o;
if (_port != peer._port) {
return false;
}
if(!addr.laxEquals(peer.addr))
return false;
return true;
}
// FIXME same issues as with FreenetInetAddress.laxEquals/equals/strictEquals
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Peer)) {
return false;
}
final Peer peer = (Peer) o;
if (_port != peer._port) {
return false;
}
if(!addr.equals(peer.addr))
return false;
return true;
}
public boolean strictEquals(Object o) {
if (this == o) {
return true;
}
if(o == null) return false;
if (!(o instanceof Peer)) {
return false;
}
final Peer peer = (Peer) o;
if (_port != peer._port) {
return false;
}
if(!addr.strictEquals(peer.addr))
return false;
return true;
}
/**
* Get the IP address. Look it up if necessary, but return the last value if it
* has ever been looked up before; will not trigger a new lookup if it has been
* looked up before.
*/
public InetAddress getAddress() {
return getAddress(true);
}
/**
* Get the IP address. Look it up if allowed to, but return the last value if it
* has ever been looked up before; will not trigger a new lookup if it has been
* looked up before.
*/
public InetAddress getAddress(boolean doDNSRequest) {
return addr.getAddress(doDNSRequest);
}
public InetAddress getAddress(boolean doDNSRequest, boolean allowLocal) throws LocalAddressException {
InetAddress a = addr.getAddress(doDNSRequest);
if(a == null) return null;
if(allowLocal || IPUtil.isValidAddress(a, false)) return a;
throw new LocalAddressException();
}
/**
* Get the IP address, looking up the hostname if the hostname is primary, even if
* it has been looked up before. Typically called on a reconnect attempt, when the
* dyndns address may have changed.
*/
public InetAddress getHandshakeAddress() {
return addr.getHandshakeAddress();
}
@Override
public int hashCode() {
return addr.hashCode() + _port;
}
public int getPort() {
return _port;
}
@Override
public String toString() {
return addr.toString() + ':' + _port;
}
@Override
public void writeToDataOutputStream(DataOutputStream dos) throws IOException {
addr.writeToDataOutputStream(dos);
dos.writeInt(_port);
}
public FreenetInetAddress getFreenetAddress() {
return addr;
}
public boolean isRealInternetAddress(boolean lookup, boolean defaultVal, boolean allowLocalAddresses) {
return addr.isRealInternetAddress(lookup, defaultVal, allowLocalAddresses);
}
/**
* Get the address:port string, but prefer numeric IPs - don't return the name.
*/
public String toStringPrefNumeric() {
return addr.toStringPrefNumeric()+':'+_port;
}
public Peer dropHostName() {
FreenetInetAddress newAddr = addr.dropHostname();
if(newAddr == null) return null;
if(addr != newAddr) {
return new Peer(newAddr, _port);
} else return this;
}
/** Is this peer using IPv6? */
public boolean isIPv6(boolean defaultValue) {
if(addr == null) return defaultValue;
return addr.isIPv6(defaultValue);
}
}