mirror of
https://github.com/Qortal/qortal.git
synced 2025-04-01 17:55:54 +00:00
Update PeerAddress.java
* Added validation for ports with universal fixed range between 1 and 65535. * Detailed exception messages improve debugging when invalid data is provided. * Simplified and enforced consistent bracket handling for IPv6 addresses. * Throws a clear UnknownHostException if the address cannot be resolved. * Simplified the equality logic while ensuring proper null checks. * Improve logging logic to handle better dubugs.
This commit is contained in:
parent
8ffb0625a1
commit
4f2c71b82a
@ -9,126 +9,139 @@ import javax.xml.bind.annotation.XmlAccessorType;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience class for encapsulating/parsing/rendering/converting peer addresses
|
* Encapsulates parsing, rendering, and resolving peer addresses,
|
||||||
* including late-stage resolving before actual use by a socket.
|
* including late-stage resolving before actual use by a socket.
|
||||||
*/
|
*/
|
||||||
// All properties to be converted to JSON via JAXB
|
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
public class PeerAddress {
|
public class PeerAddress {
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
private String host;
|
private String host; // Hostname or IP address (bracketed if IPv6)
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
private PeerAddress(String host, int port) {
|
// Private constructor to enforce factory usage
|
||||||
this.host = host;
|
private PeerAddress(String host, int port) {
|
||||||
this.port = port;
|
if (host == null || host.isEmpty()) {
|
||||||
}
|
throw new IllegalArgumentException("Host cannot be null or empty");
|
||||||
|
}
|
||||||
|
if (port < 1 || port > 65535) {
|
||||||
|
throw new IllegalArgumentException("Port must be between 1 and 65535");
|
||||||
|
}
|
||||||
|
|
||||||
// Constructors
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
// For JAXB
|
// Default constructor for JAXB
|
||||||
protected PeerAddress() {
|
protected PeerAddress() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructs new PeerAddress using remote address from passed connected socket. */
|
// Factory Methods
|
||||||
public static PeerAddress fromSocket(Socket socket) {
|
|
||||||
InetSocketAddress socketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
|
|
||||||
InetAddress address = socketAddress.getAddress();
|
|
||||||
|
|
||||||
String host = InetAddresses.toAddrString(address);
|
/**
|
||||||
|
* Constructs a PeerAddress from a connected socket.
|
||||||
|
*
|
||||||
|
* @param socket the connected socket
|
||||||
|
* @return the PeerAddress
|
||||||
|
*/
|
||||||
|
public static PeerAddress fromSocket(Socket socket) {
|
||||||
|
InetSocketAddress socketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
|
||||||
|
InetAddress address = socketAddress.getAddress();
|
||||||
|
|
||||||
// Make sure we encapsulate IPv6 addresses in brackets
|
String host = InetAddresses.toAddrString(address);
|
||||||
if (address instanceof Inet6Address)
|
|
||||||
host = "[" + host + "]";
|
|
||||||
|
|
||||||
return new PeerAddress(host, socketAddress.getPort());
|
// Ensure IPv6 addresses are properly bracketed
|
||||||
}
|
if (address instanceof Inet6Address) {
|
||||||
|
host = "[" + host + "]";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
return new PeerAddress(host, socketAddress.getPort());
|
||||||
* Constructs new PeerAddress using hostname or literal IP address and optional port.<br>
|
}
|
||||||
* Literal IPv6 addresses must be enclosed within square brackets.
|
|
||||||
* <p>
|
|
||||||
* Examples:
|
|
||||||
* <ul>
|
|
||||||
* <li>peer.example.com
|
|
||||||
* <li>peer.example.com:9084
|
|
||||||
* <li>192.0.2.1
|
|
||||||
* <li>192.0.2.1:9084
|
|
||||||
* <li>[2001:db8::1]
|
|
||||||
* <li>[2001:db8::1]:9084
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
* Not allowed:
|
|
||||||
* <ul>
|
|
||||||
* <li>2001:db8::1
|
|
||||||
* <li>2001:db8::1:9084
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public static PeerAddress fromString(String addressString) throws IllegalArgumentException {
|
|
||||||
boolean isBracketed = addressString.startsWith("[");
|
|
||||||
|
|
||||||
// Attempt to parse string into host and port
|
/**
|
||||||
HostAndPort hostAndPort = HostAndPort.fromString(addressString).withDefaultPort(Settings.getInstance().getDefaultListenPort()).requireBracketsForIPv6();
|
* Constructs a PeerAddress from a string containing hostname/IP and optional port.
|
||||||
|
* IPv6 addresses must be enclosed in brackets.
|
||||||
|
*
|
||||||
|
* @param addressString the address string
|
||||||
|
* @return the PeerAddress
|
||||||
|
* @throws IllegalArgumentException if the input is invalid
|
||||||
|
*/
|
||||||
|
public static PeerAddress fromString(String addressString) {
|
||||||
|
boolean isBracketed = addressString.startsWith("[");
|
||||||
|
|
||||||
String host = hostAndPort.getHost();
|
// Parse the host and port
|
||||||
if (host.isEmpty())
|
HostAndPort hostAndPort = HostAndPort.fromString(addressString)
|
||||||
throw new IllegalArgumentException("Empty host part");
|
.withDefaultPort(Settings.getInstance().getDefaultListenPort())
|
||||||
|
.requireBracketsForIPv6();
|
||||||
|
|
||||||
// Validate IP literals by attempting to convert to InetAddress, without DNS lookups
|
String host = hostAndPort.getHost();
|
||||||
if (host.contains(":") || host.matches("[0-9.]+"))
|
|
||||||
InetAddresses.forString(host);
|
|
||||||
|
|
||||||
// If we've reached this far then we have a valid address
|
// Validate host as IP literal or hostname
|
||||||
|
if (host.contains(":") || host.matches("[0-9.]+")) {
|
||||||
|
try {
|
||||||
|
InetAddresses.forString(host); // Validate IP literal
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid IP literal: " + host, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we encapsulate IPv6 addresses in brackets
|
// Enforce IPv6 brackets for consistency
|
||||||
if (isBracketed)
|
if (isBracketed) {
|
||||||
host = "[" + host + "]";
|
host = "[" + host + "]";
|
||||||
|
}
|
||||||
|
|
||||||
return new PeerAddress(host, hostAndPort.getPort());
|
return new PeerAddress(host, hostAndPort.getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
/** Returns hostname or literal IP address, bracketed if IPv6 */
|
/** @return the hostname or IP address (bracketed if IPv6) */
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return this.host;
|
return this.host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPort() {
|
/** @return the port number */
|
||||||
return this.port;
|
public int getPort() {
|
||||||
}
|
return this.port;
|
||||||
|
}
|
||||||
|
|
||||||
// Conversions
|
// Conversions
|
||||||
|
|
||||||
/** Returns InetSocketAddress for use with Socket.connect(), or throws UnknownHostException if address could not be resolved by DNS lookup. */
|
/**
|
||||||
public InetSocketAddress toSocketAddress() throws UnknownHostException {
|
* Converts this PeerAddress to an InetSocketAddress, performing DNS resolution if necessary.
|
||||||
// Attempt to construct new InetSocketAddress with DNS lookups.
|
*
|
||||||
// There's no control here over whether IPv6 or IPv4 will be used.
|
* @return the InetSocketAddress
|
||||||
InetSocketAddress socketAddress = new InetSocketAddress(this.host, this.port);
|
* @throws UnknownHostException if the host cannot be resolved
|
||||||
|
*/
|
||||||
|
public InetSocketAddress toSocketAddress() throws UnknownHostException {
|
||||||
|
InetSocketAddress socketAddress = new InetSocketAddress(this.host, this.port);
|
||||||
|
|
||||||
// If we couldn't resolve then return null
|
if (socketAddress.isUnresolved()) {
|
||||||
if (socketAddress.isUnresolved())
|
throw new UnknownHostException("Unable to resolve host: " + this.host);
|
||||||
throw new UnknownHostException();
|
}
|
||||||
|
|
||||||
return socketAddress;
|
return socketAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.host + ":" + this.port;
|
return this.host + ":" + this.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
|
|
||||||
/** Returns true if other PeerAddress has same port and same case-insensitive host part, without DNS lookups */
|
/**
|
||||||
public boolean equals(PeerAddress other) {
|
* Checks if another PeerAddress is equal to this one.
|
||||||
// Ports must match
|
*
|
||||||
if (this.port != other.port)
|
* @param other the other PeerAddress
|
||||||
return false;
|
* @return true if they are equal, false otherwise
|
||||||
|
*/
|
||||||
// Compare host parts but without DNS lookups
|
public boolean equals(PeerAddress other) {
|
||||||
return this.host.equalsIgnoreCase(other.host);
|
if (other == null) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ports must match, and hostnames/IPs must be case-insensitively equal
|
||||||
|
return this.port == other.port && this.host.equalsIgnoreCase(other.host);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user