org.bitcoinj.core.PeerAddress Maven / Gradle / Ivy
/*
* Copyright 2011 Google Inc.
* Copyright 2015 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.params.MainNetParams;
import com.google.common.base.Objects;
import com.google.common.net.InetAddresses;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import static org.bitcoinj.core.Utils.uint32ToByteStreamLE;
import static org.bitcoinj.core.Utils.uint64ToByteStreamLE;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A PeerAddress holds an IP address and port number representing the network location of
* a peer in the Bitcoin P2P network. It exists primarily for serialization purposes.
*
* Instances of this class are not safe for use by multiple threads.
*/
public class PeerAddress extends ChildMessage {
static final int MESSAGE_SIZE = 30;
private InetAddress addr;
private String hostname; // Used for .onion addresses
private int port;
private BigInteger services;
private long time;
/**
* Construct a peer address from a serialized payload.
*/
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
super(params, payload, offset, protocolVersion);
}
/**
* Construct a peer address from a serialized payload.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param protocolVersion Bitcoin protocol version.
* @param serializer the serializer to use for this message.
* @throws ProtocolException
*/
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion, Message parent, MessageSerializer serializer) throws ProtocolException {
super(params, payload, offset, protocolVersion, parent, serializer, UNKNOWN_LENGTH);
}
/**
* Construct a peer address from a memorized or hardcoded address.
*/
public PeerAddress(NetworkParameters params, InetAddress addr, int port, int protocolVersion, BigInteger services) {
super(params);
this.addr = checkNotNull(addr);
this.port = port;
this.protocolVersion = protocolVersion;
this.services = services;
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
}
/**
* Constructs a peer address from the given IP address and port. Version number is default for the given parameters.
*/
public PeerAddress(NetworkParameters params, InetAddress addr, int port) {
this(params, addr, port, params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.CURRENT),
BigInteger.ZERO);
}
/**
* Constructs a peer address from the given IP address. Port and version number are default for the given
* parameters.
*/
public PeerAddress(NetworkParameters params, InetAddress addr) {
this(params, addr, params.getPort());
}
/**
* Constructs a peer address from an {@link InetSocketAddress}. An InetSocketAddress can take in as parameters an
* InetAddress or a String hostname. If you want to connect to a .onion, set the hostname to the .onion address.
*/
public PeerAddress(NetworkParameters params, InetSocketAddress addr) {
this(params, addr.getAddress(), addr.getPort());
}
/**
* Constructs a peer address from a stringified hostname+port. Use this if you want to connect to a Tor .onion address.
*/
public PeerAddress(NetworkParameters params, String hostname, int port) {
super(params);
this.hostname = hostname;
this.port = port;
this.protocolVersion = params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.CURRENT);
this.services = BigInteger.ZERO;
}
public static PeerAddress localhost(NetworkParameters params) {
return new PeerAddress(params, InetAddresses.forString("127.0.0.1"), params.getPort());
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (protocolVersion >= 31402) {
//TODO this appears to be dynamic because the client only ever sends out it's own address
//so assumes itself to be up. For a fuller implementation this needs to be dynamic only if
//the address refers to this client.
int secs = (int) (Utils.currentTimeSeconds());
uint32ToByteStreamLE(secs, stream);
}
uint64ToByteStreamLE(services, stream); // nServices.
// Java does not provide any utility to map an IPv4 address into IPv6 space, so we have to do it by hand.
byte[] ipBytes = addr.getAddress();
if (ipBytes.length == 4) {
byte[] v6addr = new byte[16];
System.arraycopy(ipBytes, 0, v6addr, 12, 4);
v6addr[10] = (byte) 0xFF;
v6addr[11] = (byte) 0xFF;
ipBytes = v6addr;
}
stream.write(ipBytes);
// And write out the port. Unlike the rest of the protocol, address and port is in big endian byte order.
stream.write((byte) (0xFF & port >> 8));
stream.write((byte) (0xFF & port));
}
@Override
protected void parse() throws ProtocolException {
// Format of a serialized address:
// uint32 timestamp
// uint64 services (flags determining what the node can do)
// 16 bytes ip address
// 2 bytes port num
if (protocolVersion > 31402)
time = readUint32();
else
time = -1;
services = readUint64();
byte[] addrBytes = readBytes(16);
try {
addr = InetAddress.getByAddress(addrBytes);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Cannot happen.
}
port = ((0xFF & payload[cursor++]) << 8) | (0xFF & payload[cursor++]);
// The 4 byte difference is the uint32 timestamp that was introduced in version 31402
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
}
public String getHostname() {
return hostname;
}
public InetAddress getAddr() {
return addr;
}
public InetSocketAddress getSocketAddress() {
return new InetSocketAddress(getAddr(), getPort());
}
public int getPort() {
return port;
}
public BigInteger getServices() {
return services;
}
public long getTime() {
return time;
}
@Override
public String toString() {
if (hostname != null) {
return "[" + hostname + "]:" + port;
}
return "[" + addr.getHostAddress() + "]:" + port;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PeerAddress other = (PeerAddress) o;
return other.addr.equals(addr) && other.port == port && other.time == time && other.services.equals(services);
}
@Override
public int hashCode() {
return Objects.hashCode(addr, port, time, services);
}
public InetSocketAddress toSocketAddress() {
// Reconstruct the InetSocketAddress properly
if (hostname != null) {
return InetSocketAddress.createUnresolved(hostname, port);
} else {
return new InetSocketAddress(addr, port);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy